From 648b2876f65a5f11d12f3e69781c710630bdd46d Mon Sep 17 00:00:00 2001 From: nnethercott Date: Sun, 27 Apr 2025 00:51:26 +0200 Subject: [PATCH 001/292] Create temp threadpool with all CPUs in dump --- .../src/scheduler/process_index_operation.rs | 9 ++++++--- crates/meilisearch/src/lib.rs | 19 +++++++++++++++++++ crates/meilisearch/src/option.rs | 4 ++-- crates/milli/src/index.rs | 9 ++++++--- .../milli/src/update/index_documents/mod.rs | 4 +++- crates/milli/src/update/indexer_config.rs | 6 ++++-- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/crates/index-scheduler/src/scheduler/process_index_operation.rs b/crates/index-scheduler/src/scheduler/process_index_operation.rs index 9b12d61cf..68a1de25a 100644 --- a/crates/index-scheduler/src/scheduler/process_index_operation.rs +++ b/crates/index-scheduler/src/scheduler/process_index_operation.rs @@ -115,7 +115,8 @@ impl IndexScheduler { let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool = match &indexer_config.thread_pool { + let pool_guard = indexer_config.thread_pool.read().unwrap(); + let pool = match &*pool_guard { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new() @@ -268,7 +269,8 @@ impl IndexScheduler { if task.error.is_none() { let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool = match &indexer_config.thread_pool { + let pool_guard = indexer_config.thread_pool.read().unwrap(); + let pool = match &*pool_guard { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new() @@ -431,7 +433,8 @@ impl IndexScheduler { if !tasks.iter().all(|res| res.error.is_some()) { let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool = match &indexer_config.thread_pool { + let pool_guard = indexer_config.thread_pool.read().unwrap(); + let pool = match &*pool_guard { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new() diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 761726d83..4f31606f6 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -38,6 +38,7 @@ use meilisearch_auth::{open_auth_store_env, AuthController}; use meilisearch_types::milli::constants::VERSION_MAJOR; use meilisearch_types::milli::documents::{DocumentsBatchBuilder, DocumentsBatchReader}; use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod}; +use meilisearch_types::milli::ThreadPoolNoAbortBuilder; use meilisearch_types::settings::apply_settings_to_builder; use meilisearch_types::tasks::KindWithContent; use meilisearch_types::versioning::{ @@ -505,6 +506,18 @@ fn import_dump( let indexer_config = index_scheduler.indexer_config(); + // Use all cpus to index a dump + let pool_before = { + let all_cpus = num_cpus::get(); + + let temp_pool = ThreadPoolNoAbortBuilder::new() + .thread_name(|index| format!("indexing-thread:{index}")) + .num_threads(all_cpus) + .build()?; + + indexer_config.thread_pool.write().unwrap().replace(temp_pool) + }; + // /!\ The tasks must be imported AFTER importing the indexes or else the scheduler might // try to process tasks while we're trying to import the indexes. @@ -576,6 +589,12 @@ fn import_dump( index_scheduler.refresh_index_stats(&uid)?; } + // Restore original thread pool after dump + { + let mut guard = indexer_config.thread_pool.write().unwrap(); + *guard = pool_before; + } + // 5. Import the queue let mut index_scheduler_dump = index_scheduler.register_dumped_task()?; // 5.1. Import the batches diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index c71bf16c0..41dd05651 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -6,7 +6,7 @@ use std::num::{NonZeroUsize, ParseIntError}; use std::ops::Deref; use std::path::PathBuf; use std::str::FromStr; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use std::{env, fmt, fs}; use byte_unit::{Byte, ParseError, UnitType}; @@ -765,7 +765,7 @@ impl TryFrom<&IndexerOpts> for IndexerConfig { Ok(Self { log_every_n: Some(DEFAULT_LOG_EVERY_N), max_memory: other.max_indexing_memory.map(|b| b.as_u64() as usize), - thread_pool: Some(thread_pool), + thread_pool: RwLock::new(Some(thread_pool)), max_positions_per_attributes: None, skip_index_budget: other.skip_index_budget, ..Default::default() diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index 1f006b316..779185ca2 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -1936,7 +1936,8 @@ pub(crate) mod tests { ) -> Result<(), crate::error::Error> { let local_pool; let indexer_config = &self.indexer_config; - let pool = match &indexer_config.thread_pool { + let pool_guard = indexer_config.thread_pool.read().unwrap(); + let pool = match &*pool_guard { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); @@ -2030,7 +2031,8 @@ pub(crate) mod tests { ) -> Result<(), crate::error::Error> { let local_pool; let indexer_config = &self.indexer_config; - let pool = match &indexer_config.thread_pool { + let pool_guard = indexer_config.thread_pool.read().unwrap(); + let pool = match &*pool_guard { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); @@ -2109,7 +2111,8 @@ pub(crate) mod tests { let local_pool; let indexer_config = &index.indexer_config; - let pool = match &indexer_config.thread_pool { + let pool_guard = indexer_config.thread_pool.read().unwrap(); + let pool = match &*pool_guard { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); diff --git a/crates/milli/src/update/index_documents/mod.rs b/crates/milli/src/update/index_documents/mod.rs index 4acb78b9a..1f962ae9f 100644 --- a/crates/milli/src/update/index_documents/mod.rs +++ b/crates/milli/src/update/index_documents/mod.rs @@ -228,8 +228,10 @@ where let possible_embedding_mistakes = crate::vector::error::PossibleEmbeddingMistakes::new(&field_distribution); + let pool_guard = self.indexer_config.thread_pool.read().unwrap(); + let backup_pool; - let pool = match self.indexer_config.thread_pool { + let pool = match &*pool_guard { Some(ref pool) => pool, None => { // We initialize a backup pool with the default diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index 6fb33ad78..b3559190f 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -1,3 +1,5 @@ +use std::sync::RwLock; + use grenad::CompressionType; use super::GrenadParameters; @@ -11,7 +13,7 @@ pub struct IndexerConfig { pub max_memory: Option, pub chunk_compression_type: CompressionType, pub chunk_compression_level: Option, - pub thread_pool: Option, + pub thread_pool: RwLock>, pub max_positions_per_attributes: Option, pub skip_index_budget: bool, } @@ -36,7 +38,7 @@ impl Default for IndexerConfig { max_memory: None, chunk_compression_type: CompressionType::None, chunk_compression_level: None, - thread_pool: None, + thread_pool: RwLock::new(None), max_positions_per_attributes: None, skip_index_budget: false, } From 3b773b3416d945c5f1676d6addfc2672cdbc1193 Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 28 Apr 2025 11:45:21 +0200 Subject: [PATCH 002/292] Revert thread_pool type back to Option in config --- .../src/scheduler/process_index_operation.rs | 9 +++------ crates/meilisearch/src/lib.rs | 20 +++++++------------ crates/meilisearch/src/option.rs | 4 ++-- crates/milli/src/index.rs | 9 +++------ .../milli/src/update/index_documents/mod.rs | 4 +--- crates/milli/src/update/indexer_config.rs | 20 +++++++++++++++---- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/crates/index-scheduler/src/scheduler/process_index_operation.rs b/crates/index-scheduler/src/scheduler/process_index_operation.rs index 68a1de25a..9b12d61cf 100644 --- a/crates/index-scheduler/src/scheduler/process_index_operation.rs +++ b/crates/index-scheduler/src/scheduler/process_index_operation.rs @@ -115,8 +115,7 @@ impl IndexScheduler { let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool_guard = indexer_config.thread_pool.read().unwrap(); - let pool = match &*pool_guard { + let pool = match &indexer_config.thread_pool { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new() @@ -269,8 +268,7 @@ impl IndexScheduler { if task.error.is_none() { let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool_guard = indexer_config.thread_pool.read().unwrap(); - let pool = match &*pool_guard { + let pool = match &indexer_config.thread_pool { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new() @@ -433,8 +431,7 @@ impl IndexScheduler { if !tasks.iter().all(|res| res.error.is_some()) { let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool_guard = indexer_config.thread_pool.read().unwrap(); - let pool = match &*pool_guard { + let pool = match &indexer_config.thread_pool { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new() diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 4f31606f6..df45dc63b 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -37,7 +37,7 @@ use index_scheduler::{IndexScheduler, IndexSchedulerOptions}; use meilisearch_auth::{open_auth_store_env, AuthController}; use meilisearch_types::milli::constants::VERSION_MAJOR; use meilisearch_types::milli::documents::{DocumentsBatchBuilder, DocumentsBatchReader}; -use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod}; +use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod, IndexerConfig}; use meilisearch_types::milli::ThreadPoolNoAbortBuilder; use meilisearch_types::settings::apply_settings_to_builder; use meilisearch_types::tasks::KindWithContent; @@ -504,10 +504,10 @@ fn import_dump( let network = dump_reader.network()?.cloned().unwrap_or_default(); index_scheduler.put_network(network)?; - let indexer_config = index_scheduler.indexer_config(); + let mut indexer_config = IndexerConfig::clone_no_threadpool(index_scheduler.indexer_config()); - // Use all cpus to index a dump - let pool_before = { + // 3.1 Use all cpus to index the import dump + indexer_config.thread_pool = { let all_cpus = num_cpus::get(); let temp_pool = ThreadPoolNoAbortBuilder::new() @@ -515,7 +515,7 @@ fn import_dump( .num_threads(all_cpus) .build()?; - indexer_config.thread_pool.write().unwrap().replace(temp_pool) + Some(temp_pool) }; // /!\ The tasks must be imported AFTER importing the indexes or else the scheduler might @@ -533,7 +533,7 @@ fn import_dump( let mut wtxn = index.write_txn()?; - let mut builder = milli::update::Settings::new(&mut wtxn, &index, indexer_config); + let mut builder = milli::update::Settings::new(&mut wtxn, &index, &indexer_config); // 4.1 Import the primary key if there is one. if let Some(ref primary_key) = metadata.primary_key { builder.set_primary_key(primary_key.to_string()); @@ -568,7 +568,7 @@ fn import_dump( let builder = milli::update::IndexDocuments::new( &mut wtxn, &index, - indexer_config, + &indexer_config, IndexDocumentsConfig { update_method: IndexDocumentsMethod::ReplaceDocuments, ..Default::default() @@ -589,12 +589,6 @@ fn import_dump( index_scheduler.refresh_index_stats(&uid)?; } - // Restore original thread pool after dump - { - let mut guard = indexer_config.thread_pool.write().unwrap(); - *guard = pool_before; - } - // 5. Import the queue let mut index_scheduler_dump = index_scheduler.register_dumped_task()?; // 5.1. Import the batches diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index 41dd05651..c71bf16c0 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -6,7 +6,7 @@ use std::num::{NonZeroUsize, ParseIntError}; use std::ops::Deref; use std::path::PathBuf; use std::str::FromStr; -use std::sync::{Arc, RwLock}; +use std::sync::Arc; use std::{env, fmt, fs}; use byte_unit::{Byte, ParseError, UnitType}; @@ -765,7 +765,7 @@ impl TryFrom<&IndexerOpts> for IndexerConfig { Ok(Self { log_every_n: Some(DEFAULT_LOG_EVERY_N), max_memory: other.max_indexing_memory.map(|b| b.as_u64() as usize), - thread_pool: RwLock::new(Some(thread_pool)), + thread_pool: Some(thread_pool), max_positions_per_attributes: None, skip_index_budget: other.skip_index_budget, ..Default::default() diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index 779185ca2..1f006b316 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -1936,8 +1936,7 @@ pub(crate) mod tests { ) -> Result<(), crate::error::Error> { let local_pool; let indexer_config = &self.indexer_config; - let pool_guard = indexer_config.thread_pool.read().unwrap(); - let pool = match &*pool_guard { + let pool = match &indexer_config.thread_pool { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); @@ -2031,8 +2030,7 @@ pub(crate) mod tests { ) -> Result<(), crate::error::Error> { let local_pool; let indexer_config = &self.indexer_config; - let pool_guard = indexer_config.thread_pool.read().unwrap(); - let pool = match &*pool_guard { + let pool = match &indexer_config.thread_pool { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); @@ -2111,8 +2109,7 @@ pub(crate) mod tests { let local_pool; let indexer_config = &index.indexer_config; - let pool_guard = indexer_config.thread_pool.read().unwrap(); - let pool = match &*pool_guard { + let pool = match &indexer_config.thread_pool { Some(pool) => pool, None => { local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); diff --git a/crates/milli/src/update/index_documents/mod.rs b/crates/milli/src/update/index_documents/mod.rs index 1f962ae9f..4acb78b9a 100644 --- a/crates/milli/src/update/index_documents/mod.rs +++ b/crates/milli/src/update/index_documents/mod.rs @@ -228,10 +228,8 @@ where let possible_embedding_mistakes = crate::vector::error::PossibleEmbeddingMistakes::new(&field_distribution); - let pool_guard = self.indexer_config.thread_pool.read().unwrap(); - let backup_pool; - let pool = match &*pool_guard { + let pool = match self.indexer_config.thread_pool { Some(ref pool) => pool, None => { // We initialize a backup pool with the default diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index b3559190f..a534a21e9 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -1,5 +1,3 @@ -use std::sync::RwLock; - use grenad::CompressionType; use super::GrenadParameters; @@ -13,7 +11,7 @@ pub struct IndexerConfig { pub max_memory: Option, pub chunk_compression_type: CompressionType, pub chunk_compression_level: Option, - pub thread_pool: RwLock>, + pub thread_pool: Option, pub max_positions_per_attributes: Option, pub skip_index_budget: bool, } @@ -27,6 +25,20 @@ impl IndexerConfig { max_nb_chunks: self.max_nb_chunks, } } + + pub fn clone_no_threadpool(other: &IndexerConfig) -> Self { + Self { + log_every_n: other.log_every_n.clone(), + max_nb_chunks: other.max_nb_chunks.clone(), + documents_chunk_size: other.documents_chunk_size.clone(), + max_memory: other.max_memory.clone(), + chunk_compression_type: other.chunk_compression_type.clone(), + chunk_compression_level: other.chunk_compression_level.clone(), + max_positions_per_attributes: other.max_positions_per_attributes.clone(), + skip_index_budget: other.skip_index_budget.clone(), + thread_pool: None, + } + } } impl Default for IndexerConfig { @@ -38,7 +50,7 @@ impl Default for IndexerConfig { max_memory: None, chunk_compression_type: CompressionType::None, chunk_compression_level: None, - thread_pool: RwLock::new(None), + thread_pool: None, max_positions_per_attributes: None, skip_index_budget: false, } From 89aff2081c81a2ed4e767228d4e19f073e5a698a Mon Sep 17 00:00:00 2001 From: nnethercott Date: Wed, 30 Apr 2025 14:17:32 +0200 Subject: [PATCH 003/292] Fix clippy warnings --- crates/milli/src/update/indexer_config.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index a534a21e9..433273fac 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -28,14 +28,14 @@ impl IndexerConfig { pub fn clone_no_threadpool(other: &IndexerConfig) -> Self { Self { - log_every_n: other.log_every_n.clone(), - max_nb_chunks: other.max_nb_chunks.clone(), - documents_chunk_size: other.documents_chunk_size.clone(), - max_memory: other.max_memory.clone(), - chunk_compression_type: other.chunk_compression_type.clone(), - chunk_compression_level: other.chunk_compression_level.clone(), - max_positions_per_attributes: other.max_positions_per_attributes.clone(), - skip_index_budget: other.skip_index_budget.clone(), + log_every_n: other.log_every_n, + max_nb_chunks: other.max_nb_chunks, + documents_chunk_size: other.documents_chunk_size, + max_memory: other.max_memory, + chunk_compression_type: other.chunk_compression_type, + chunk_compression_level: other.chunk_compression_level, + max_positions_per_attributes: other.max_positions_per_attributes, + skip_index_budget: other.skip_index_budget, thread_pool: None, } } From 2ac826edca956a71c7d4976a06474386a6baf395 Mon Sep 17 00:00:00 2001 From: Nate Nethercott <53127799+nnethercott@users.noreply.github.com> Date: Thu, 1 May 2025 14:48:59 +0200 Subject: [PATCH 004/292] Apply suggested changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément Renault Update crates/meilisearch/src/lib.rs Co-authored-by: Clément Renault --- crates/meilisearch/src/lib.rs | 4 ++-- crates/milli/src/update/indexer_config.rs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index df45dc63b..3b3c94230 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -37,7 +37,7 @@ use index_scheduler::{IndexScheduler, IndexSchedulerOptions}; use meilisearch_auth::{open_auth_store_env, AuthController}; use meilisearch_types::milli::constants::VERSION_MAJOR; use meilisearch_types::milli::documents::{DocumentsBatchBuilder, DocumentsBatchReader}; -use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod, IndexerConfig}; +use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod}; use meilisearch_types::milli::ThreadPoolNoAbortBuilder; use meilisearch_types::settings::apply_settings_to_builder; use meilisearch_types::tasks::KindWithContent; @@ -504,7 +504,7 @@ fn import_dump( let network = dump_reader.network()?.cloned().unwrap_or_default(); index_scheduler.put_network(network)?; - let mut indexer_config = IndexerConfig::clone_no_threadpool(index_scheduler.indexer_config()); + let mut indexer_config = index_scheduler.indexer_config().clone_no_threadpool(); // 3.1 Use all cpus to index the import dump indexer_config.thread_pool = { diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index 433273fac..f9503c48e 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -26,16 +26,16 @@ impl IndexerConfig { } } - pub fn clone_no_threadpool(other: &IndexerConfig) -> Self { + pub fn clone_no_threadpool(&self) -> Self { Self { - log_every_n: other.log_every_n, - max_nb_chunks: other.max_nb_chunks, - documents_chunk_size: other.documents_chunk_size, - max_memory: other.max_memory, - chunk_compression_type: other.chunk_compression_type, - chunk_compression_level: other.chunk_compression_level, - max_positions_per_attributes: other.max_positions_per_attributes, - skip_index_budget: other.skip_index_budget, + log_every_n: self.log_every_n, + max_nb_chunks: self.max_nb_chunks, + documents_chunk_size: self.documents_chunk_size, + max_memory: self.max_memory, + chunk_compression_type: self.chunk_compression_type, + chunk_compression_level: self.chunk_compression_level, + max_positions_per_attributes: self.max_positions_per_attributes, + skip_index_budget: self.skip_index_budget, thread_pool: None, } } From 47a7ed93d334fd423619514c5e91d041995b8ea6 Mon Sep 17 00:00:00 2001 From: nnethercott Date: Tue, 6 May 2025 09:10:09 +0200 Subject: [PATCH 005/292] feat: Make MaxThreads None by default --- crates/meilisearch/src/lib.rs | 32 ++++++++++-------- crates/meilisearch/src/option.rs | 40 +++++++++++++---------- crates/milli/src/update/indexer_config.rs | 3 ++ 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 3b3c94230..7310260f6 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -504,18 +504,22 @@ fn import_dump( let network = dump_reader.network()?.cloned().unwrap_or_default(); index_scheduler.put_network(network)?; - let mut indexer_config = index_scheduler.indexer_config().clone_no_threadpool(); - - // 3.1 Use all cpus to index the import dump - indexer_config.thread_pool = { - let all_cpus = num_cpus::get(); - - let temp_pool = ThreadPoolNoAbortBuilder::new() - .thread_name(|index| format!("indexing-thread:{index}")) - .num_threads(all_cpus) - .build()?; - - Some(temp_pool) + // 3.1 Use all cpus to process dump if max_indexing_threads not configured + let backup_config; + let indexer_config = if index_scheduler.indexer_config().max_threads.is_none() { + let mut _config = index_scheduler.indexer_config().clone_no_threadpool(); + _config.thread_pool = { + Some( + ThreadPoolNoAbortBuilder::new() + .thread_name(|index| format!("indexing-thread:{index}")) + .num_threads(num_cpus::get()) + .build()?, + ) + }; + backup_config = _config; + &backup_config + } else { + index_scheduler.indexer_config() }; // /!\ The tasks must be imported AFTER importing the indexes or else the scheduler might @@ -533,7 +537,7 @@ fn import_dump( let mut wtxn = index.write_txn()?; - let mut builder = milli::update::Settings::new(&mut wtxn, &index, &indexer_config); + let mut builder = milli::update::Settings::new(&mut wtxn, &index, indexer_config); // 4.1 Import the primary key if there is one. if let Some(ref primary_key) = metadata.primary_key { builder.set_primary_key(primary_key.to_string()); @@ -568,7 +572,7 @@ fn import_dump( let builder = milli::update::IndexDocuments::new( &mut wtxn, &index, - &indexer_config, + indexer_config, IndexDocumentsConfig { update_method: IndexDocumentsMethod::ReplaceDocuments, ..Default::default() diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index c71bf16c0..259fd501f 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -746,10 +746,12 @@ impl IndexerOpts { max_indexing_memory.to_string(), ); } - export_to_env_if_not_present( - MEILI_MAX_INDEXING_THREADS, - max_indexing_threads.0.to_string(), - ); + if let Some(max_indexing_threads) = max_indexing_threads.0 { + export_to_env_if_not_present( + MEILI_MAX_INDEXING_THREADS, + max_indexing_threads.to_string(), + ); + } } } @@ -757,14 +759,18 @@ impl TryFrom<&IndexerOpts> for IndexerConfig { type Error = anyhow::Error; fn try_from(other: &IndexerOpts) -> Result { + // use 1/2 cpu threads if no value specified + let max_indexing_threads = other.max_indexing_threads.unwrap_or(num_cpus::get() / 2); + let thread_pool = ThreadPoolNoAbortBuilder::new() .thread_name(|index| format!("indexing-thread:{index}")) - .num_threads(*other.max_indexing_threads) + .num_threads(max_indexing_threads) .build()?; Ok(Self { log_every_n: Some(DEFAULT_LOG_EVERY_N), max_memory: other.max_indexing_memory.map(|b| b.as_u64() as usize), + max_threads: *other.max_indexing_threads, thread_pool: Some(thread_pool), max_positions_per_attributes: None, skip_index_budget: other.skip_index_budget, @@ -828,31 +834,31 @@ fn total_memory_bytes() -> Option { } } -#[derive(Debug, Clone, Copy, Deserialize, Serialize)] -pub struct MaxThreads(usize); +#[derive(Default, Debug, Clone, Copy, Deserialize, Serialize)] +pub struct MaxThreads(Option); impl FromStr for MaxThreads { type Err = ParseIntError; - fn from_str(s: &str) -> Result { - usize::from_str(s).map(Self) - } -} - -impl Default for MaxThreads { - fn default() -> Self { - MaxThreads(num_cpus::get() / 2) + fn from_str(s: &str) -> Result { + if s.is_empty() { + return Ok(MaxThreads::default()); + } + usize::from_str(s).map(Some).map(MaxThreads) } } impl fmt::Display for MaxThreads { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) + match self.0 { + Some(threads) => write!(f, "{}", threads), + None => Ok(()), + } } } impl Deref for MaxThreads { - type Target = usize; + type Target = Option; fn deref(&self) -> &Self::Target { &self.0 diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index f9503c48e..e19649a0d 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -9,6 +9,7 @@ pub struct IndexerConfig { pub max_nb_chunks: Option, pub documents_chunk_size: Option, pub max_memory: Option, + pub max_threads: Option, pub chunk_compression_type: CompressionType, pub chunk_compression_level: Option, pub thread_pool: Option, @@ -32,6 +33,7 @@ impl IndexerConfig { max_nb_chunks: self.max_nb_chunks, documents_chunk_size: self.documents_chunk_size, max_memory: self.max_memory, + max_threads: self.max_threads, chunk_compression_type: self.chunk_compression_type, chunk_compression_level: self.chunk_compression_level, max_positions_per_attributes: self.max_positions_per_attributes, @@ -48,6 +50,7 @@ impl Default for IndexerConfig { max_nb_chunks: None, documents_chunk_size: None, max_memory: None, + max_threads: None, chunk_compression_type: CompressionType::None, chunk_compression_level: None, thread_pool: None, From 53f32a7dd78f945d7c126b3696ace419da1ba7af Mon Sep 17 00:00:00 2001 From: nnethercott Date: Wed, 7 May 2025 17:00:08 +0200 Subject: [PATCH 006/292] refactor: change thread_pool from Option to ThreadPoolNoAbort --- .../src/scheduler/process_index_operation.rs | 38 ++----------------- crates/meilisearch/src/lib.rs | 26 ++++++------- crates/meilisearch/src/option.rs | 2 +- crates/milli/src/index.rs | 28 ++------------ .../milli/src/update/index_documents/mod.rs | 20 +--------- crates/milli/src/update/indexer_config.rs | 34 ++++++++--------- 6 files changed, 38 insertions(+), 110 deletions(-) diff --git a/crates/index-scheduler/src/scheduler/process_index_operation.rs b/crates/index-scheduler/src/scheduler/process_index_operation.rs index 9b12d61cf..093c6209d 100644 --- a/crates/index-scheduler/src/scheduler/process_index_operation.rs +++ b/crates/index-scheduler/src/scheduler/process_index_operation.rs @@ -5,7 +5,7 @@ use meilisearch_types::milli::documents::PrimaryKey; use meilisearch_types::milli::progress::Progress; use meilisearch_types::milli::update::new::indexer::{self, UpdateByFunction}; use meilisearch_types::milli::update::DocumentAdditionResult; -use meilisearch_types::milli::{self, ChannelCongestion, Filter, ThreadPoolNoAbortBuilder}; +use meilisearch_types::milli::{self, ChannelCongestion, Filter}; use meilisearch_types::settings::apply_settings_to_builder; use meilisearch_types::tasks::{Details, KindWithContent, Status, Task}; use meilisearch_types::Index; @@ -113,18 +113,8 @@ impl IndexScheduler { } } - let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new() - .thread_name(|i| format!("indexing-thread-{i}")) - .build() - .unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; progress.update_progress(DocumentOperationProgress::ComputingDocumentChanges); let (document_changes, operation_stats, primary_key) = indexer @@ -266,18 +256,8 @@ impl IndexScheduler { let mut congestion = None; if task.error.is_none() { - let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new() - .thread_name(|i| format!("indexing-thread-{i}")) - .build() - .unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; let candidates_count = candidates.len(); progress.update_progress(DocumentEditionProgress::ComputingDocumentChanges); @@ -429,18 +409,8 @@ impl IndexScheduler { let mut congestion = None; if !tasks.iter().all(|res| res.error.is_some()) { - let local_pool; let indexer_config = self.index_mapper.indexer_config(); - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new() - .thread_name(|i| format!("indexing-thread-{i}")) - .build() - .unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; progress.update_progress(DocumentDeletionProgress::DeleteDocuments); let mut indexer = indexer::DocumentDeletion::new(); diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 7310260f6..9364bc83d 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -37,7 +37,7 @@ use index_scheduler::{IndexScheduler, IndexSchedulerOptions}; use meilisearch_auth::{open_auth_store_env, AuthController}; use meilisearch_types::milli::constants::VERSION_MAJOR; use meilisearch_types::milli::documents::{DocumentsBatchBuilder, DocumentsBatchReader}; -use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod}; +use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod, IndexerConfig}; use meilisearch_types::milli::ThreadPoolNoAbortBuilder; use meilisearch_types::settings::apply_settings_to_builder; use meilisearch_types::tasks::KindWithContent; @@ -504,22 +504,22 @@ fn import_dump( let network = dump_reader.network()?.cloned().unwrap_or_default(); index_scheduler.put_network(network)?; - // 3.1 Use all cpus to process dump if max_indexing_threads not configured + // 3.1 Use all cpus to process dump if a) `max_indexing_threads` not configured and + // b) we're not executing from within a test let backup_config; - let indexer_config = if index_scheduler.indexer_config().max_threads.is_none() { - let mut _config = index_scheduler.indexer_config().clone_no_threadpool(); - _config.thread_pool = { - Some( - ThreadPoolNoAbortBuilder::new() - .thread_name(|index| format!("indexing-thread:{index}")) - .num_threads(num_cpus::get()) - .build()?, - ) - }; + let base_config = index_scheduler.indexer_config(); + + let indexer_config = if base_config.max_threads.is_none() && !cfg!(test) { + let thread_pool = ThreadPoolNoAbortBuilder::new() + .thread_name(|index| format!("indexing-thread:{index}")) + .num_threads(num_cpus::get()) + .build()?; + + let _config = IndexerConfig { thread_pool, ..*base_config }; backup_config = _config; &backup_config } else { - index_scheduler.indexer_config() + base_config }; // /!\ The tasks must be imported AFTER importing the indexes or else the scheduler might diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index 259fd501f..8dcbdcfca 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -768,10 +768,10 @@ impl TryFrom<&IndexerOpts> for IndexerConfig { .build()?; Ok(Self { + thread_pool, log_every_n: Some(DEFAULT_LOG_EVERY_N), max_memory: other.max_indexing_memory.map(|b| b.as_u64() as usize), max_threads: *other.max_indexing_threads, - thread_pool: Some(thread_pool), max_positions_per_attributes: None, skip_index_budget: other.skip_index_budget, ..Default::default() diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index 1f006b316..948d0fb0d 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -1893,7 +1893,6 @@ pub(crate) mod tests { use crate::vector::EmbeddingConfigs; use crate::{ db_snap, obkv_to_json, Filter, FilterableAttributesRule, Index, Search, SearchResult, - ThreadPoolNoAbortBuilder, }; pub(crate) struct TempIndex { @@ -1934,15 +1933,8 @@ pub(crate) mod tests { wtxn: &mut RwTxn<'t>, documents: Mmap, ) -> Result<(), crate::error::Error> { - let local_pool; let indexer_config = &self.indexer_config; - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; let rtxn = self.inner.read_txn()?; let db_fields_ids_map = self.inner.fields_ids_map(&rtxn)?; @@ -2028,15 +2020,8 @@ pub(crate) mod tests { wtxn: &mut RwTxn<'t>, external_document_ids: Vec, ) -> Result<(), crate::error::Error> { - let local_pool; let indexer_config = &self.indexer_config; - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; let rtxn = self.inner.read_txn()?; let db_fields_ids_map = self.inner.fields_ids_map(&rtxn)?; @@ -2107,15 +2092,8 @@ pub(crate) mod tests { let mut wtxn = index.inner.write_txn().unwrap(); let should_abort = AtomicBool::new(false); - let local_pool; let indexer_config = &index.indexer_config; - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; let rtxn = index.inner.read_txn().unwrap(); let db_fields_ids_map = index.inner.fields_ids_map(&rtxn).unwrap(); diff --git a/crates/milli/src/update/index_documents/mod.rs b/crates/milli/src/update/index_documents/mod.rs index 4acb78b9a..379b991e0 100644 --- a/crates/milli/src/update/index_documents/mod.rs +++ b/crates/milli/src/update/index_documents/mod.rs @@ -33,7 +33,6 @@ use crate::documents::{obkv_to_object, DocumentsBatchReader}; use crate::error::{Error, InternalError}; use crate::index::{PrefixSearch, PrefixSettings}; use crate::progress::Progress; -use crate::thread_pool_no_abort::ThreadPoolNoAbortBuilder; pub use crate::update::index_documents::helpers::CursorClonableMmap; use crate::update::{ IndexerConfig, UpdateIndexingStep, WordPrefixDocids, WordPrefixIntegerDocids, WordsPrefixesFst, @@ -228,24 +227,7 @@ where let possible_embedding_mistakes = crate::vector::error::PossibleEmbeddingMistakes::new(&field_distribution); - let backup_pool; - let pool = match self.indexer_config.thread_pool { - Some(ref pool) => pool, - None => { - // We initialize a backup pool with the default - // settings if none have already been set. - #[allow(unused_mut)] - let mut pool_builder = ThreadPoolNoAbortBuilder::new(); - - #[cfg(test)] - { - pool_builder = pool_builder.num_threads(1); - } - - backup_pool = pool_builder.build()?; - &backup_pool - } - }; + let pool = &self.indexer_config.thread_pool; // create LMDB writer channel let (lmdb_writer_sx, lmdb_writer_rx): ( diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index e19649a0d..c6ae2b859 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -1,7 +1,7 @@ use grenad::CompressionType; use super::GrenadParameters; -use crate::thread_pool_no_abort::ThreadPoolNoAbort; +use crate::{thread_pool_no_abort::ThreadPoolNoAbort, ThreadPoolNoAbortBuilder}; #[derive(Debug)] pub struct IndexerConfig { @@ -12,7 +12,7 @@ pub struct IndexerConfig { pub max_threads: Option, pub chunk_compression_type: CompressionType, pub chunk_compression_level: Option, - pub thread_pool: Option, + pub thread_pool: ThreadPoolNoAbort, pub max_positions_per_attributes: Option, pub skip_index_budget: bool, } @@ -26,25 +26,23 @@ impl IndexerConfig { max_nb_chunks: self.max_nb_chunks, } } - - pub fn clone_no_threadpool(&self) -> Self { - Self { - log_every_n: self.log_every_n, - max_nb_chunks: self.max_nb_chunks, - documents_chunk_size: self.documents_chunk_size, - max_memory: self.max_memory, - max_threads: self.max_threads, - chunk_compression_type: self.chunk_compression_type, - chunk_compression_level: self.chunk_compression_level, - max_positions_per_attributes: self.max_positions_per_attributes, - skip_index_budget: self.skip_index_budget, - thread_pool: None, - } - } } impl Default for IndexerConfig { fn default() -> Self { + #[allow(unused_mut)] + let mut pool_builder = ThreadPoolNoAbortBuilder::new(); + + #[cfg(test)] + { + pool_builder = pool_builder.num_threads(1); + } + + let thread_pool = pool_builder + .thread_name(|index| format!("indexing-thread:{index}")) + .build() + .expect("failed to build default rayon thread pool"); + Self { log_every_n: None, max_nb_chunks: None, @@ -53,9 +51,9 @@ impl Default for IndexerConfig { max_threads: None, chunk_compression_type: CompressionType::None, chunk_compression_level: None, - thread_pool: None, max_positions_per_attributes: None, skip_index_budget: false, + thread_pool, } } } From 15cdc6924b6b733d924d14d87ad9ce165cdd85dc Mon Sep 17 00:00:00 2001 From: nnethercott Date: Tue, 13 May 2025 09:12:34 +0200 Subject: [PATCH 007/292] refactor: remove runtime cfg!(test) check Won't work in integration tests and consequently all threads would be used. To remedy this we make explicit `max_threads=Some(1)` in the IndexerConfig::default --- crates/meilisearch/src/lib.rs | 5 ++-- crates/milli/src/test_index.rs | 32 +++-------------------- crates/milli/src/update/indexer_config.rs | 8 ++++-- 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 57ef6d6f2..0a5c2f1f5 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -501,12 +501,11 @@ fn import_dump( let network = dump_reader.network()?.cloned().unwrap_or_default(); index_scheduler.put_network(network)?; - // 3.1 Use all cpus to process dump if a) `max_indexing_threads` not configured and - // b) we're not executing from within a test + // 3.1 Use all cpus to process dump if `max_indexing_threads` not configured let backup_config; let base_config = index_scheduler.indexer_config(); - let indexer_config = if base_config.max_threads.is_none() && !cfg!(test) { + let indexer_config = if base_config.max_threads.is_none() { let thread_pool = ThreadPoolNoAbortBuilder::new() .thread_name(|index| format!("indexing-thread:{index}")) .num_threads(num_cpus::get()) diff --git a/crates/milli/src/test_index.rs b/crates/milli/src/test_index.rs index 7759b3e18..dfd570b96 100644 --- a/crates/milli/src/test_index.rs +++ b/crates/milli/src/test_index.rs @@ -19,10 +19,7 @@ use crate::update::{ }; use crate::vector::settings::{EmbedderSource, EmbeddingSettings}; use crate::vector::EmbeddingConfigs; -use crate::{ - db_snap, obkv_to_json, Filter, FilterableAttributesRule, Index, Search, SearchResult, - ThreadPoolNoAbortBuilder, -}; +use crate::{db_snap, obkv_to_json, Filter, FilterableAttributesRule, Index, Search, SearchResult}; pub(crate) struct TempIndex { pub inner: Index, @@ -62,15 +59,8 @@ impl TempIndex { wtxn: &mut RwTxn<'t>, documents: Mmap, ) -> Result<(), crate::error::Error> { - let local_pool; let indexer_config = &self.indexer_config; - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; let rtxn = self.inner.read_txn()?; let db_fields_ids_map = self.inner.fields_ids_map(&rtxn)?; @@ -153,15 +143,8 @@ impl TempIndex { wtxn: &mut RwTxn<'t>, external_document_ids: Vec, ) -> Result<(), crate::error::Error> { - let local_pool; let indexer_config = &self.indexer_config; - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; let rtxn = self.inner.read_txn()?; let db_fields_ids_map = self.inner.fields_ids_map(&rtxn)?; @@ -231,15 +214,8 @@ fn aborting_indexation() { let mut wtxn = index.inner.write_txn().unwrap(); let should_abort = AtomicBool::new(false); - let local_pool; let indexer_config = &index.indexer_config; - let pool = match &indexer_config.thread_pool { - Some(pool) => pool, - None => { - local_pool = ThreadPoolNoAbortBuilder::new().build().unwrap(); - &local_pool - } - }; + let pool = &indexer_config.thread_pool; let rtxn = index.inner.read_txn().unwrap(); let db_fields_ids_map = index.inner.fields_ids_map(&rtxn).unwrap(); diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index c6ae2b859..33573aef6 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -33,9 +33,13 @@ impl Default for IndexerConfig { #[allow(unused_mut)] let mut pool_builder = ThreadPoolNoAbortBuilder::new(); + #[allow(unused_mut, unused_assignments)] + let mut max_threads = None; + #[cfg(test)] { pool_builder = pool_builder.num_threads(1); + max_threads = Some(1); } let thread_pool = pool_builder @@ -44,16 +48,16 @@ impl Default for IndexerConfig { .expect("failed to build default rayon thread pool"); Self { + max_threads, + thread_pool, log_every_n: None, max_nb_chunks: None, documents_chunk_size: None, max_memory: None, - max_threads: None, chunk_compression_type: CompressionType::None, chunk_compression_level: None, max_positions_per_attributes: None, skip_index_budget: false, - thread_pool, } } } From e96c1d4b0fa044da9606c5247e921e30cfe58abb Mon Sep 17 00:00:00 2001 From: nnethercott Date: Tue, 13 May 2025 12:16:34 +0200 Subject: [PATCH 008/292] style: change fmt from empty str to "unlimited" --- crates/meilisearch/src/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index 8dcbdcfca..e7d172b71 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -852,7 +852,7 @@ impl fmt::Display for MaxThreads { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { Some(threads) => write!(f, "{}", threads), - None => Ok(()), + None => write!(f, "unlimited"), } } } From 806e983aa54ef6d303dde8ab0e4b1efa46cbcb46 Mon Sep 17 00:00:00 2001 From: Nate Nethercott <53127799+nnethercott@users.noreply.github.com> Date: Tue, 13 May 2025 14:14:48 +0200 Subject: [PATCH 009/292] fix: lazy computation in thread default Co-authored-by: Martin Grigorov --- crates/meilisearch/src/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index e7d172b71..acb4bc05e 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -760,7 +760,7 @@ impl TryFrom<&IndexerOpts> for IndexerConfig { fn try_from(other: &IndexerOpts) -> Result { // use 1/2 cpu threads if no value specified - let max_indexing_threads = other.max_indexing_threads.unwrap_or(num_cpus::get() / 2); + let max_indexing_threads = other.max_indexing_threads.unwrap_or_else(|| num_cpus::get() / 2); let thread_pool = ThreadPoolNoAbortBuilder::new() .thread_name(|index| format!("indexing-thread:{index}")) From 83e71cd7b9efce913fe983461a00c7adc91c8080 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 14 May 2025 15:50:05 +0200 Subject: [PATCH 010/292] Add an experimental cli flag to disable snapshot compaction --- crates/index-scheduler/src/lib.rs | 2 ++ crates/index-scheduler/src/scheduler/mod.rs | 5 +++++ .../src/scheduler/process_snapshot_creation.rs | 11 ++++++++--- crates/index-scheduler/src/test_utils.rs | 1 + .../src/analytics/segment_analytics.rs | 3 +++ crates/meilisearch/src/lib.rs | 1 + crates/meilisearch/src/option.rs | 15 +++++++++++++++ 7 files changed, 35 insertions(+), 3 deletions(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 4f1109348..c2658739b 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -131,6 +131,8 @@ pub struct IndexSchedulerOptions { /// /// 0 disables the cache. pub embedding_cache_cap: usize, + /// Snapshot compaction status. + pub experimental_no_snapshot_compaction: bool, } /// Structure which holds meilisearch's indexes and schedules the tasks diff --git a/crates/index-scheduler/src/scheduler/mod.rs b/crates/index-scheduler/src/scheduler/mod.rs index f0e324a8d..f1775a892 100644 --- a/crates/index-scheduler/src/scheduler/mod.rs +++ b/crates/index-scheduler/src/scheduler/mod.rs @@ -83,6 +83,9 @@ pub struct Scheduler { /// /// 0 disables the cache. pub(crate) embedding_cache_cap: usize, + + /// Snapshot compaction status. + pub(crate) experimental_no_snapshot_compaction: bool, } impl Scheduler { @@ -98,6 +101,7 @@ impl Scheduler { auth_env: self.auth_env.clone(), version_file_path: self.version_file_path.clone(), embedding_cache_cap: self.embedding_cache_cap, + experimental_no_snapshot_compaction: self.experimental_no_snapshot_compaction, } } @@ -114,6 +118,7 @@ impl Scheduler { auth_env, version_file_path: options.version_file_path.clone(), embedding_cache_cap: options.embedding_cache_cap, + experimental_no_snapshot_compaction: options.experimental_no_snapshot_compaction, } } } diff --git a/crates/index-scheduler/src/scheduler/process_snapshot_creation.rs b/crates/index-scheduler/src/scheduler/process_snapshot_creation.rs index 599991a7d..d58157ae3 100644 --- a/crates/index-scheduler/src/scheduler/process_snapshot_creation.rs +++ b/crates/index-scheduler/src/scheduler/process_snapshot_creation.rs @@ -41,7 +41,12 @@ impl IndexScheduler { progress.update_progress(SnapshotCreationProgress::SnapshotTheIndexScheduler); let dst = temp_snapshot_dir.path().join("tasks"); fs::create_dir_all(&dst)?; - self.env.copy_to_path(dst.join("data.mdb"), CompactionOption::Disabled)?; + let compaction_option = if self.scheduler.experimental_no_snapshot_compaction { + CompactionOption::Disabled + } else { + CompactionOption::Enabled + }; + self.env.copy_to_path(dst.join("data.mdb"), compaction_option)?; // 2.2 Create a read transaction on the index-scheduler let rtxn = self.env.read_txn()?; @@ -80,7 +85,7 @@ impl IndexScheduler { let dst = temp_snapshot_dir.path().join("indexes").join(uuid.to_string()); fs::create_dir_all(&dst)?; index - .copy_to_path(dst.join("data.mdb"), CompactionOption::Disabled) + .copy_to_path(dst.join("data.mdb"), compaction_option) .map_err(|e| Error::from_milli(e, Some(name.to_string())))?; } @@ -90,7 +95,7 @@ impl IndexScheduler { progress.update_progress(SnapshotCreationProgress::SnapshotTheApiKeys); let dst = temp_snapshot_dir.path().join("auth"); fs::create_dir_all(&dst)?; - self.scheduler.auth_env.copy_to_path(dst.join("data.mdb"), CompactionOption::Disabled)?; + self.scheduler.auth_env.copy_to_path(dst.join("data.mdb"), compaction_option)?; // 5. Copy and tarball the flat snapshot progress.update_progress(SnapshotCreationProgress::CreateTheTarball); diff --git a/crates/index-scheduler/src/test_utils.rs b/crates/index-scheduler/src/test_utils.rs index 0d44b3c81..f96149359 100644 --- a/crates/index-scheduler/src/test_utils.rs +++ b/crates/index-scheduler/src/test_utils.rs @@ -113,6 +113,7 @@ impl IndexScheduler { instance_features: Default::default(), auto_upgrade: true, // Don't cost much and will ensure the happy path works embedding_cache_cap: 10, + experimental_no_snapshot_compaction: false, }; let version = configuration(&mut options).unwrap_or({ (versioning::VERSION_MAJOR, versioning::VERSION_MINOR, versioning::VERSION_PATCH) diff --git a/crates/meilisearch/src/analytics/segment_analytics.rs b/crates/meilisearch/src/analytics/segment_analytics.rs index 3209bba4c..ee8a9ee20 100644 --- a/crates/meilisearch/src/analytics/segment_analytics.rs +++ b/crates/meilisearch/src/analytics/segment_analytics.rs @@ -200,6 +200,7 @@ struct Infos { experimental_get_task_documents_route: bool, experimental_composite_embedders: bool, experimental_embedding_cache_entries: usize, + experimental_no_snapshot_compaction: bool, gpu_enabled: bool, db_path: bool, import_dump: bool, @@ -248,6 +249,7 @@ impl Infos { experimental_max_number_of_batched_tasks, experimental_limit_batched_tasks_total_size, experimental_embedding_cache_entries, + experimental_no_snapshot_compaction, http_addr, master_key: _, env, @@ -315,6 +317,7 @@ impl Infos { experimental_get_task_documents_route: get_task_documents_route, experimental_composite_embedders: composite_embedders, experimental_embedding_cache_entries, + experimental_no_snapshot_compaction, gpu_enabled: meilisearch_types::milli::vector::is_cuda_enabled(), db_path: db_path != PathBuf::from("./data.ms"), import_dump: import_dump.is_some(), diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 40d318140..f4df7efa0 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -234,6 +234,7 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc, Arc< instance_features: opt.to_instance_features(), auto_upgrade: opt.experimental_dumpless_upgrade, embedding_cache_cap: opt.experimental_embedding_cache_entries, + experimental_no_snapshot_compaction: opt.experimental_no_snapshot_compaction, }; let binary_version = (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index c71bf16c0..6e06b161d 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -65,6 +65,7 @@ const MEILI_EXPERIMENTAL_LIMIT_BATCHED_TASKS_TOTAL_SIZE: &str = "MEILI_EXPERIMENTAL_LIMIT_BATCHED_TASKS_SIZE"; const MEILI_EXPERIMENTAL_EMBEDDING_CACHE_ENTRIES: &str = "MEILI_EXPERIMENTAL_EMBEDDING_CACHE_ENTRIES"; +const MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION: &str = "MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION"; const DEFAULT_CONFIG_FILE_PATH: &str = "./config.toml"; const DEFAULT_DB_PATH: &str = "./data.ms"; const DEFAULT_HTTP_ADDR: &str = "localhost:7700"; @@ -455,6 +456,15 @@ pub struct Opt { #[serde(default = "default_embedding_cache_entries")] pub experimental_embedding_cache_entries: usize, + /// Experimental no snapshot compaction feature. + /// + /// When enabled, Meilisearch will not compact snapshots during creation. + /// + /// For more information, see . + #[clap(long, env = MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION)] + #[serde(default)] + pub experimental_no_snapshot_compaction: bool, + #[serde(flatten)] #[clap(flatten)] pub indexer_options: IndexerOpts, @@ -559,6 +569,7 @@ impl Opt { experimental_max_number_of_batched_tasks, experimental_limit_batched_tasks_total_size, experimental_embedding_cache_entries, + experimental_no_snapshot_compaction, } = self; export_to_env_if_not_present(MEILI_DB_PATH, db_path); export_to_env_if_not_present(MEILI_HTTP_ADDR, http_addr); @@ -655,6 +666,10 @@ impl Opt { MEILI_EXPERIMENTAL_EMBEDDING_CACHE_ENTRIES, experimental_embedding_cache_entries.to_string(), ); + export_to_env_if_not_present( + MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION, + experimental_no_snapshot_compaction.to_string(), + ); indexer_options.export_to_env(); } From 8608d10fa2d0403899c09bcd9d9fe53730fc8542 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 14 May 2025 17:09:10 +0200 Subject: [PATCH 011/292] Don't process any tasks if the max number of batched tasks is set to 0 --- crates/index-scheduler/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 4f1109348..7148c5c50 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -381,6 +381,11 @@ impl IndexScheduler { /// This function will execute in a different thread and must be called /// only once per index scheduler. fn run(&self) { + // If the number of batched tasks is 0, we don't need to run the scheduler at all. + // It will never be able to process any tasks. + if self.scheduler.max_number_of_batched_tasks == 0 { + return; + } let run = self.private_clone(); std::thread::Builder::new() .name(String::from("scheduler")) From 0f10ec96afccb95da1a5e1ad9f2ca430c0183a4b Mon Sep 17 00:00:00 2001 From: curquiza Date: Wed, 14 May 2025 17:35:47 +0200 Subject: [PATCH 012/292] Fix swarmia deployement --- .github/workflows/publish-docker-images.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/publish-docker-images.yml b/.github/workflows/publish-docker-images.yml index ae6532ef9..c947b779b 100644 --- a/.github/workflows/publish-docker-images.yml +++ b/.github/workflows/publish-docker-images.yml @@ -106,6 +106,8 @@ jobs: client-payload: '{ "meilisearch_version": "${{ github.ref_name }}", "stable": "${{ steps.check-tag-format.outputs.stable }}" }' # Send notification to Swarmia to notify of a deployment: https://app.swarmia.com + - name: 'Setup jq' + uses: dcarbone/install-jq-action - name: Send deployment to Swarmia if: github.event_name == 'push' && success() run: | From c9b4c1fb815ab6dfda6e80ee981e39dc3be7a8fa Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Mon, 12 May 2025 11:59:21 +0200 Subject: [PATCH 013/292] Only intern in case of single-typo when looking for single typoes --- crates/milli/src/search/new/query_term/compute_derivations.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/milli/src/search/new/query_term/compute_derivations.rs b/crates/milli/src/search/new/query_term/compute_derivations.rs index 10e480a04..5edf85e97 100644 --- a/crates/milli/src/search/new/query_term/compute_derivations.rs +++ b/crates/milli/src/search/new/query_term/compute_derivations.rs @@ -92,12 +92,12 @@ fn find_one_typo_derivations( let mut stream = fst.search_with_state(Intersection(starts, &dfa)).into_stream(); while let Some((derived_word, state)) = stream.next() { - let derived_word = std::str::from_utf8(derived_word)?; - let derived_word = ctx.word_interner.insert(derived_word.to_owned()); let d = dfa.distance(state.1); match d.to_u8() { 0 => (), 1 => { + let derived_word = std::str::from_utf8(derived_word)?; + let derived_word = ctx.word_interner.insert(derived_word.to_owned()); let cf = visit(derived_word)?; if cf.is_break() { break; From c5dd8e7d6f5d4cef47841e39e23d4034b1bb01b7 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Mon, 12 May 2025 12:40:55 +0200 Subject: [PATCH 014/292] Add test --- crates/meilisearch/tests/search/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index 6d98c0b2a..f1d9c8b3b 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -112,6 +112,26 @@ async fn simple_search() { .await; } +/// See +#[actix_rt::test] +async fn bug_5547() { + let server = Server::new().await; + let index = server.index("big_fst"); + let (response, _code) = index.create(None).await; + index.wait_task(response.uid()).await.succeeded(); + + let mut documents = Vec::new(); + for i in 0..65_535 { + documents.push(json!({"id": i, "title": format!("title{i}")})); + } + + let (response, _code) = index.add_documents(json!(documents), Some("id")).await; + index.wait_task(response.uid()).await.succeeded(); + let (response, code) = index.search_post(json!({"q": "title"})).await; + assert_eq!(code, 200); + snapshot!(response["hits"], @r###"[{"id":0,"title":"title0"},{"id":1,"title":"title1"},{"id":10,"title":"title10"},{"id":100,"title":"title100"},{"id":101,"title":"title101"},{"id":102,"title":"title102"},{"id":103,"title":"title103"},{"id":104,"title":"title104"},{"id":105,"title":"title105"},{"id":106,"title":"title106"},{"id":107,"title":"title107"},{"id":108,"title":"title108"},{"id":1000,"title":"title1000"},{"id":1001,"title":"title1001"},{"id":1002,"title":"title1002"},{"id":1003,"title":"title1003"},{"id":1004,"title":"title1004"},{"id":1005,"title":"title1005"},{"id":1006,"title":"title1006"},{"id":1007,"title":"title1007"}]"###); +} + #[actix_rt::test] async fn search_with_stop_word() { // related to https://github.com/meilisearch/meilisearch/issues/4984 From 865f24cfefbdfd2d0c6f6be2006266977f9d4cee Mon Sep 17 00:00:00 2001 From: nnethercott Date: Wed, 14 May 2025 23:45:24 +0200 Subject: [PATCH 015/292] refactor: helper methods for pool and max threads --- crates/meilisearch/src/lib.rs | 6 ++-- crates/meilisearch/src/option.rs | 10 ++---- crates/milli/src/thread_pool_no_abort.rs | 4 +++ crates/milli/src/update/indexer_config.rs | 37 +++++++++++++---------- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 0a5c2f1f5..441da0d7f 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -506,10 +506,8 @@ fn import_dump( let base_config = index_scheduler.indexer_config(); let indexer_config = if base_config.max_threads.is_none() { - let thread_pool = ThreadPoolNoAbortBuilder::new() - .thread_name(|index| format!("indexing-thread:{index}")) - .num_threads(num_cpus::get()) - .build()?; + let thread_pool = + ThreadPoolNoAbortBuilder::new_for_indexing().num_threads(num_cpus::get()).build()?; let _config = IndexerConfig { thread_pool, ..*base_config }; backup_config = _config; diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index acb4bc05e..d98b9aa8b 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -759,12 +759,8 @@ impl TryFrom<&IndexerOpts> for IndexerConfig { type Error = anyhow::Error; fn try_from(other: &IndexerOpts) -> Result { - // use 1/2 cpu threads if no value specified - let max_indexing_threads = other.max_indexing_threads.unwrap_or_else(|| num_cpus::get() / 2); - - let thread_pool = ThreadPoolNoAbortBuilder::new() - .thread_name(|index| format!("indexing-thread:{index}")) - .num_threads(max_indexing_threads) + let thread_pool = ThreadPoolNoAbortBuilder::new_for_indexing() + .num_threads(other.max_indexing_threads.unwrap_or_else(|| num_cpus::get() / 2)) .build()?; Ok(Self { @@ -841,7 +837,7 @@ impl FromStr for MaxThreads { type Err = ParseIntError; fn from_str(s: &str) -> Result { - if s.is_empty() { + if s.is_empty() || s == "unlimited" { return Ok(MaxThreads::default()); } usize::from_str(s).map(Some).map(MaxThreads) diff --git a/crates/milli/src/thread_pool_no_abort.rs b/crates/milli/src/thread_pool_no_abort.rs index b57050a63..0c2fbb30d 100644 --- a/crates/milli/src/thread_pool_no_abort.rs +++ b/crates/milli/src/thread_pool_no_abort.rs @@ -54,6 +54,10 @@ impl ThreadPoolNoAbortBuilder { ThreadPoolNoAbortBuilder::default() } + pub fn new_for_indexing() -> ThreadPoolNoAbortBuilder { + ThreadPoolNoAbortBuilder::default().thread_name(|index| format!("indexing-thread:{index}")) + } + pub fn thread_name(mut self, closure: F) -> Self where F: FnMut(usize) -> String + 'static, diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index 33573aef6..edca71e14 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -28,24 +28,29 @@ impl IndexerConfig { } } +/// By default use only 1 thread for indexing in tests +#[cfg(test)] +fn default_thread_pool_and_threads() -> (ThreadPoolNoAbort, Option) { + let pool = ThreadPoolNoAbortBuilder::new_for_indexing() + .num_threads(1) + .build() + .expect("failed to build default rayon thread pool"); + + (pool, Some(1)) +} + +#[cfg(not(test))] +fn default_thread_pool_and_threads() -> (ThreadPoolNoAbort, Option) { + let pool = ThreadPoolNoAbortBuilder::new_for_indexing() + .build() + .expect("failed to build default rayon thread pool"); + + (pool, None) +} + impl Default for IndexerConfig { fn default() -> Self { - #[allow(unused_mut)] - let mut pool_builder = ThreadPoolNoAbortBuilder::new(); - - #[allow(unused_mut, unused_assignments)] - let mut max_threads = None; - - #[cfg(test)] - { - pool_builder = pool_builder.num_threads(1); - max_threads = Some(1); - } - - let thread_pool = pool_builder - .thread_name(|index| format!("indexing-thread:{index}")) - .build() - .expect("failed to build default rayon thread pool"); + let (thread_pool, max_threads) = default_thread_pool_and_threads(); Self { max_threads, From 0940f0e4f46651a3bf459901d58f118a7c1b4563 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 14 May 2025 17:40:15 +0200 Subject: [PATCH 016/292] add a test --- crates/index-scheduler/src/scheduler/test.rs | 27 ++++++++++++++++++++ crates/index-scheduler/src/test_utils.rs | 7 +++++ 2 files changed, 34 insertions(+) diff --git a/crates/index-scheduler/src/scheduler/test.rs b/crates/index-scheduler/src/scheduler/test.rs index 84112de08..f13af9f87 100644 --- a/crates/index-scheduler/src/scheduler/test.rs +++ b/crates/index-scheduler/src/scheduler/test.rs @@ -929,3 +929,30 @@ fn create_and_list_index() { ] "###); } + +#[test] +fn test_scheduler_doesnt_run_with_zero_batched_tasks() { + let (index_scheduler, mut handle) = IndexScheduler::test_with_custom_config(vec![], |config| { + config.max_number_of_batched_tasks = 0; + None + }); + + handle.scheduler_is_down(); + + // Register a task + index_scheduler + .register( + KindWithContent::IndexCreation { index_uid: S("doggos"), primary_key: None }, + None, + false, + ) + .unwrap(); + snapshot!(snapshot_index_scheduler(&index_scheduler), name: "registered_task"); + + handle.scheduler_is_down(); + + // If we restart the scheduler, it should run properly. + let (index_scheduler, mut handle) = handle.restart(index_scheduler, true, vec![], |_| None); + handle.advance_n_successful_batches(1); + snapshot!(snapshot_index_scheduler(&index_scheduler), name: "after_restart"); +} diff --git a/crates/index-scheduler/src/test_utils.rs b/crates/index-scheduler/src/test_utils.rs index 0d44b3c81..bbdf0c500 100644 --- a/crates/index-scheduler/src/test_utils.rs +++ b/crates/index-scheduler/src/test_utils.rs @@ -118,6 +118,9 @@ impl IndexScheduler { (versioning::VERSION_MAJOR, versioning::VERSION_MINOR, versioning::VERSION_PATCH) }); + // If the number of batched tasks is 0, the scheduler will not run and we can't do the init check. + let skip_init = options.max_number_of_batched_tasks == 0; + std::fs::create_dir_all(&options.auth_path).unwrap(); let auth_env = open_auth_store_env(&options.auth_path).unwrap(); let index_scheduler = @@ -126,7 +129,11 @@ impl IndexScheduler { // To be 100% consistent between all test we're going to start the scheduler right now // and ensure it's in the expected starting state. let breakpoint = match receiver.recv_timeout(std::time::Duration::from_secs(10)) { + Ok(b) if skip_init => { + panic!("The scheduler was not supposed to start, but it did: {b:?}.") + } Ok(b) => b, + Err(_) if skip_init => (Init, false), Err(RecvTimeoutError::Timeout) => { panic!("The scheduler seems to be waiting for a new task while your test is waiting for a breakpoint.") } From 79db2e67fb25af4b52a239a3ea21f150832ce949 Mon Sep 17 00:00:00 2001 From: Nate Nethercott <53127799+nnethercott@users.noreply.github.com> Date: Thu, 15 May 2025 11:04:38 +0200 Subject: [PATCH 017/292] refactor: prefer helper over explicit pool construction Co-authored-by: Many the fish --- crates/meilisearch/src/lib.rs | 8 ++++---- crates/milli/src/update/indexer_config.rs | 4 ++-- crates/milli/src/update/mod.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/meilisearch/src/lib.rs b/crates/meilisearch/src/lib.rs index 441da0d7f..d83786394 100644 --- a/crates/meilisearch/src/lib.rs +++ b/crates/meilisearch/src/lib.rs @@ -37,8 +37,9 @@ use index_scheduler::{IndexScheduler, IndexSchedulerOptions}; use meilisearch_auth::{open_auth_store_env, AuthController}; use meilisearch_types::milli::constants::VERSION_MAJOR; use meilisearch_types::milli::documents::{DocumentsBatchBuilder, DocumentsBatchReader}; -use meilisearch_types::milli::update::{IndexDocumentsConfig, IndexDocumentsMethod, IndexerConfig}; -use meilisearch_types::milli::ThreadPoolNoAbortBuilder; +use meilisearch_types::milli::update::{ + default_thread_pool_and_threads, IndexDocumentsConfig, IndexDocumentsMethod, IndexerConfig, +}; use meilisearch_types::settings::apply_settings_to_builder; use meilisearch_types::tasks::KindWithContent; use meilisearch_types::versioning::{ @@ -506,8 +507,7 @@ fn import_dump( let base_config = index_scheduler.indexer_config(); let indexer_config = if base_config.max_threads.is_none() { - let thread_pool = - ThreadPoolNoAbortBuilder::new_for_indexing().num_threads(num_cpus::get()).build()?; + let (thread_pool, _) = default_thread_pool_and_threads(); let _config = IndexerConfig { thread_pool, ..*base_config }; backup_config = _config; diff --git a/crates/milli/src/update/indexer_config.rs b/crates/milli/src/update/indexer_config.rs index edca71e14..eb7fbd4d5 100644 --- a/crates/milli/src/update/indexer_config.rs +++ b/crates/milli/src/update/indexer_config.rs @@ -30,7 +30,7 @@ impl IndexerConfig { /// By default use only 1 thread for indexing in tests #[cfg(test)] -fn default_thread_pool_and_threads() -> (ThreadPoolNoAbort, Option) { +pub fn default_thread_pool_and_threads() -> (ThreadPoolNoAbort, Option) { let pool = ThreadPoolNoAbortBuilder::new_for_indexing() .num_threads(1) .build() @@ -40,7 +40,7 @@ fn default_thread_pool_and_threads() -> (ThreadPoolNoAbort, Option) { } #[cfg(not(test))] -fn default_thread_pool_and_threads() -> (ThreadPoolNoAbort, Option) { +pub fn default_thread_pool_and_threads() -> (ThreadPoolNoAbort, Option) { let pool = ThreadPoolNoAbortBuilder::new_for_indexing() .build() .expect("failed to build default rayon thread pool"); diff --git a/crates/milli/src/update/mod.rs b/crates/milli/src/update/mod.rs index 9a783ffd2..ebb313dcf 100644 --- a/crates/milli/src/update/mod.rs +++ b/crates/milli/src/update/mod.rs @@ -4,7 +4,7 @@ pub use self::concurrent_available_ids::ConcurrentAvailableIds; pub use self::facet::bulk::FacetsUpdateBulk; pub use self::facet::incremental::FacetsUpdateIncrementalInner; pub use self::index_documents::*; -pub use self::indexer_config::IndexerConfig; +pub use self::indexer_config::{default_thread_pool_and_threads, IndexerConfig}; pub use self::new::ChannelCongestion; pub use self::settings::{validate_embedding_settings, Setting, Settings}; pub use self::update_step::UpdateIndexingStep; From 1d6777ee685c31319f3624b5e458a4512a91e7a9 Mon Sep 17 00:00:00 2001 From: Tamo Date: Thu, 15 May 2025 11:32:08 +0200 Subject: [PATCH 018/292] Forbid 0 in maxTotalHits --- crates/dump/src/reader/compat/v5_to_v6.rs | 9 +++- crates/meilisearch-types/src/settings.rs | 8 ++-- .../src/routes/indexes/settings_analytics.rs | 4 +- crates/meilisearch/tests/settings/errors.rs | 41 +++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/crates/dump/src/reader/compat/v5_to_v6.rs b/crates/dump/src/reader/compat/v5_to_v6.rs index b4a4fcb24..14570c258 100644 --- a/crates/dump/src/reader/compat/v5_to_v6.rs +++ b/crates/dump/src/reader/compat/v5_to_v6.rs @@ -1,3 +1,4 @@ +use std::num::NonZeroUsize; use std::str::FromStr; use super::v4_to_v5::{CompatIndexV4ToV5, CompatV4ToV5}; @@ -388,7 +389,13 @@ impl From> for v6::Settings { }, pagination: match settings.pagination { v5::Setting::Set(pagination) => v6::Setting::Set(v6::PaginationSettings { - max_total_hits: pagination.max_total_hits.into(), + max_total_hits: match pagination.max_total_hits { + v5::Setting::Set(max_total_hits) => v6::Setting::Set( + max_total_hits.try_into().unwrap_or(NonZeroUsize::new(1).unwrap()), + ), + v5::Setting::Reset => v6::Setting::Reset, + v5::Setting::NotSet => v6::Setting::NotSet, + }, }), v5::Setting::Reset => v6::Setting::Reset, v5::Setting::NotSet => v6::Setting::NotSet, diff --git a/crates/meilisearch-types/src/settings.rs b/crates/meilisearch-types/src/settings.rs index ccf0d75ee..edb136567 100644 --- a/crates/meilisearch-types/src/settings.rs +++ b/crates/meilisearch-types/src/settings.rs @@ -132,7 +132,7 @@ pub struct PaginationSettings { #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option, example = json!(250))] - pub max_total_hits: Setting, + pub max_total_hits: Setting, } impl MergeWithError for DeserrJsonError { @@ -748,7 +748,7 @@ pub fn apply_settings_to_builder( match pagination { Setting::Set(ref value) => match value.max_total_hits { - Setting::Set(val) => builder.set_pagination_max_total_hits(val), + Setting::Set(val) => builder.set_pagination_max_total_hits(val.into()), Setting::Reset => builder.reset_pagination_max_total_hits(), Setting::NotSet => (), }, @@ -867,8 +867,8 @@ pub fn settings( max_total_hits: Setting::Set( index .pagination_max_total_hits(rtxn)? - .map(|x| x as usize) - .unwrap_or(DEFAULT_PAGINATION_MAX_TOTAL_HITS), + .and_then(|x| (x as usize).try_into().ok()) + .unwrap_or(NonZeroUsize::new(DEFAULT_PAGINATION_MAX_TOTAL_HITS).unwrap()), ), }; diff --git a/crates/meilisearch/src/routes/indexes/settings_analytics.rs b/crates/meilisearch/src/routes/indexes/settings_analytics.rs index cb5983f02..41df91966 100644 --- a/crates/meilisearch/src/routes/indexes/settings_analytics.rs +++ b/crates/meilisearch/src/routes/indexes/settings_analytics.rs @@ -454,7 +454,9 @@ pub struct PaginationAnalytics { impl PaginationAnalytics { pub fn new(setting: Option<&PaginationSettings>) -> Self { - Self { max_total_hits: setting.as_ref().and_then(|s| s.max_total_hits.set()) } + Self { + max_total_hits: setting.as_ref().and_then(|s| s.max_total_hits.set().map(|x| x.into())), + } } pub fn into_settings(self) -> SettingsAnalytics { diff --git a/crates/meilisearch/tests/settings/errors.rs b/crates/meilisearch/tests/settings/errors.rs index 4220cdbf8..6654a95a4 100644 --- a/crates/meilisearch/tests/settings/errors.rs +++ b/crates/meilisearch/tests/settings/errors.rs @@ -338,6 +338,47 @@ async fn settings_bad_pagination() { "###); } +#[actix_rt::test] +async fn settings_bad_max_total_hits() { + let server = Server::new_shared(); + let index = server.unique_index(); + + let (response, code) = + index.update_settings(json!({ "pagination": { "maxTotalHits": "doggo" } })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.pagination.maxTotalHits`: expected a positive integer, but found a string: `\"doggo\"`", + "code": "invalid_settings_pagination", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_pagination" + } + "###); + + let (response, code) = + index.update_settings_pagination(json!({ "maxTotalHits": "doggo" } )).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r#" + { + "message": "Invalid value type at `.maxTotalHits`: expected a positive integer, but found a string: `\"doggo\"`", + "code": "invalid_settings_pagination", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_pagination" + } + "#); + + let (response, code) = index.update_settings_pagination(json!({ "maxTotalHits": 0 } )).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r#" + { + "message": "Invalid value at `.maxTotalHits`: a non-zero integer value lower than `18446744073709551615` was expected, but found a zero", + "code": "invalid_settings_pagination", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_pagination" + } + "#); +} + #[actix_rt::test] async fn settings_bad_search_cutoff_ms() { let server = Server::new_shared(); From 604e156c2b8289aff2199ada83a5e9a40cc9a248 Mon Sep 17 00:00:00 2001 From: Tamo Date: Thu, 15 May 2025 11:35:31 +0200 Subject: [PATCH 019/292] add the snapshots --- .../after_restart.snap | 63 +++++++++++++++++++ .../registered_task.snap | 51 +++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap create mode 100644 crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/registered_task.snap diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap new file mode 100644 index 000000000..d955557c7 --- /dev/null +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap @@ -0,0 +1,63 @@ +--- +source: crates/index-scheduler/src/scheduler/test.rs +--- +### Autobatching Enabled = true +### Processing batch None: +[] +---------------------------------------------------------------------- +### All Tasks: +0 {uid: 0, batch_uid: 0, status: succeeded, details: { primary_key: None }, kind: IndexCreation { index_uid: "doggos", primary_key: None }} +---------------------------------------------------------------------- +### Status: +enqueued [] +succeeded [0,] +---------------------------------------------------------------------- +### Kind: +"indexCreation" [0,] +---------------------------------------------------------------------- +### Index Tasks: +doggos [0,] +---------------------------------------------------------------------- +### Index Mapper: +doggos: { number_of_documents: 0, field_distribution: {} } + +---------------------------------------------------------------------- +### Canceled By: + +---------------------------------------------------------------------- +### Enqueued At: +[timestamp] [0,] +---------------------------------------------------------------------- +### Started At: +[timestamp] [0,] +---------------------------------------------------------------------- +### Finished At: +[timestamp] [0,] +---------------------------------------------------------------------- +### All Batches: +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +---------------------------------------------------------------------- +### Batch to tasks mapping: +0 [0,] +---------------------------------------------------------------------- +### Batches Status: +succeeded [0,] +---------------------------------------------------------------------- +### Batches Kind: +"indexCreation" [0,] +---------------------------------------------------------------------- +### Batches Index Tasks: +doggos [0,] +---------------------------------------------------------------------- +### Batches Enqueued At: +[timestamp] [0,] +---------------------------------------------------------------------- +### Batches Started At: +[timestamp] [0,] +---------------------------------------------------------------------- +### Batches Finished At: +[timestamp] [0,] +---------------------------------------------------------------------- +### File Store: + +---------------------------------------------------------------------- diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/registered_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/registered_task.snap new file mode 100644 index 000000000..dd1d76f55 --- /dev/null +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/registered_task.snap @@ -0,0 +1,51 @@ +--- +source: crates/index-scheduler/src/scheduler/test.rs +--- +### Autobatching Enabled = true +### Processing batch None: +[] +---------------------------------------------------------------------- +### All Tasks: +0 {uid: 0, status: enqueued, details: { primary_key: None }, kind: IndexCreation { index_uid: "doggos", primary_key: None }} +---------------------------------------------------------------------- +### Status: +enqueued [0,] +---------------------------------------------------------------------- +### Kind: +"indexCreation" [0,] +---------------------------------------------------------------------- +### Index Tasks: +doggos [0,] +---------------------------------------------------------------------- +### Index Mapper: + +---------------------------------------------------------------------- +### Canceled By: + +---------------------------------------------------------------------- +### Enqueued At: +[timestamp] [0,] +---------------------------------------------------------------------- +### Started At: +---------------------------------------------------------------------- +### Finished At: +---------------------------------------------------------------------- +### All Batches: +---------------------------------------------------------------------- +### Batch to tasks mapping: +---------------------------------------------------------------------- +### Batches Status: +---------------------------------------------------------------------- +### Batches Kind: +---------------------------------------------------------------------- +### Batches Index Tasks: +---------------------------------------------------------------------- +### Batches Enqueued At: +---------------------------------------------------------------------- +### Batches Started At: +---------------------------------------------------------------------- +### Batches Finished At: +---------------------------------------------------------------------- +### File Store: + +---------------------------------------------------------------------- From 768cfb6c2d8e641b6e4141bcb4041bec2961ab14 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Mon, 19 May 2025 11:34:21 +0200 Subject: [PATCH 020/292] Comment out swarmia deployment for now --- .github/workflows/publish-docker-images.yml | 32 ++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/publish-docker-images.yml b/.github/workflows/publish-docker-images.yml index c947b779b..74384e670 100644 --- a/.github/workflows/publish-docker-images.yml +++ b/.github/workflows/publish-docker-images.yml @@ -106,20 +106,20 @@ jobs: client-payload: '{ "meilisearch_version": "${{ github.ref_name }}", "stable": "${{ steps.check-tag-format.outputs.stable }}" }' # Send notification to Swarmia to notify of a deployment: https://app.swarmia.com - - name: 'Setup jq' - uses: dcarbone/install-jq-action - - name: Send deployment to Swarmia - if: github.event_name == 'push' && success() - run: | - JSON_STRING=$( jq --null-input --compact-output \ - --arg version "${{ github.ref_name }}" \ - --arg appName "meilisearch" \ - --arg environment "production" \ - --arg commitSha "${{ github.sha }}" \ - --arg repositoryFullName "${{ github.repository }}" \ - '{"version": $version, "appName": $appName, "environment": $environment, "commitSha": $commitSha, "repositoryFullName": $repositoryFullName}' ) + # - name: 'Setup jq' + # uses: dcarbone/install-jq-action + # - name: Send deployment to Swarmia + # if: github.event_name == 'push' && success() + # run: | + # JSON_STRING=$( jq --null-input --compact-output \ + # --arg version "${{ github.ref_name }}" \ + # --arg appName "meilisearch" \ + # --arg environment "production" \ + # --arg commitSha "${{ github.sha }}" \ + # --arg repositoryFullName "${{ github.repository }}" \ + # '{"version": $version, "appName": $appName, "environment": $environment, "commitSha": $commitSha, "repositoryFullName": $repositoryFullName}' ) - curl -H "Authorization: ${{ secrets.SWARMIA_DEPLOYMENTS_AUTHORIZATION }}" \ - -H "Content-Type: application/json" \ - -d "$JSON_STRING" \ - https://hook.swarmia.com/deployments + # curl -H "Authorization: ${{ secrets.SWARMIA_DEPLOYMENTS_AUTHORIZATION }}" \ + # -H "Content-Type: application/json" \ + # -d "$JSON_STRING" \ + # https://hook.swarmia.com/deployments From f26826f115afeecdb8868f2d5d7d98bca4d64565 Mon Sep 17 00:00:00 2001 From: CodeMan62 Date: Fri, 16 May 2025 18:18:11 +0530 Subject: [PATCH 021/292] fix issue 5555 --- .../milli/src/search/new/query_term/compute_derivations.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/milli/src/search/new/query_term/compute_derivations.rs b/crates/milli/src/search/new/query_term/compute_derivations.rs index 5edf85e97..0a39384bd 100644 --- a/crates/milli/src/search/new/query_term/compute_derivations.rs +++ b/crates/milli/src/search/new/query_term/compute_derivations.rs @@ -131,10 +131,11 @@ fn find_one_two_typo_derivations( while let Some((derived_word, state)) = stream.next() { let derived_word = std::str::from_utf8(derived_word)?; - let derived_word_interned = word_interner.insert(derived_word.to_owned()); + // No need to intern here // in the case the typo is on the first letter, we know the number of typo // is two if get_first(derived_word) != get_first(word) { + let derived_word_interned = word_interner.insert(derived_word.to_owned()); let cf = visit(derived_word_interned, NumberOfTypos::Two)?; if cf.is_break() { break; @@ -146,12 +147,14 @@ fn find_one_two_typo_derivations( match d.to_u8() { 0 => (), 1 => { + let derived_word_interned = word_interner.insert(derived_word.to_owned()); let cf = visit(derived_word_interned, NumberOfTypos::One)?; if cf.is_break() { break; } } 2 => { + let derived_word_interned = word_interner.insert(derived_word.to_owned()); let cf = visit(derived_word_interned, NumberOfTypos::Two)?; if cf.is_break() { break; From 2fe5c78cb645f102dec77be50e4704e71796aa76 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 20 May 2025 14:26:26 +0300 Subject: [PATCH 022/292] tests: Faster index::search::mod IT tests * Use shared index where possible. * Call .succeeded/.failed when waiting for a task. * Use newer format_args syntax * Do not use fully qualified name for meili_snap:: functions. The functions are already imported in scope Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/mod.rs | 19 ++ crates/meilisearch/tests/search/mod.rs | 293 ++++++++++++------------- 2 files changed, 154 insertions(+), 158 deletions(-) diff --git a/crates/meilisearch/tests/common/mod.rs b/crates/meilisearch/tests/common/mod.rs index 4d57a6163..da8beac3a 100644 --- a/crates/meilisearch/tests/common/mod.rs +++ b/crates/meilisearch/tests/common/mod.rs @@ -264,6 +264,25 @@ pub static SCORE_DOCUMENTS: Lazy = Lazy::new(|| { ]) }); +pub async fn shared_index_with_score_documents() -> &'static Index<'static, Shared> { + static INDEX: OnceCell> = OnceCell::const_new(); + INDEX.get_or_init(|| async { + let server = Server::new_shared(); + let index = server._index("SCORE_DOCUMENTS").to_shared(); + let documents = SCORE_DOCUMENTS.clone(); + let (response, _code) = index._add_documents(documents, None).await; + index.wait_task(response.uid()).await.succeeded(); + let (response, _code) = index + ._update_settings( + json!({"filterableAttributes": ["id", "title"], "sortableAttributes": ["id", "title"]}), + ) + .await; + index.wait_task(response.uid()).await.succeeded(); + index + }).await +} + + pub static NESTED_DOCUMENTS: Lazy = Lazy::new(|| { json!([ { diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index f1d9c8b3b..2ac0d0400 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -1,4 +1,4 @@ -// This modules contains all the test concerning search. Each particular feature of the search +// This module contains all the test concerning search. Each particular feature of the search // should be tested in its own module to isolate tests and keep the tests readable. mod distinct; @@ -21,8 +21,9 @@ use meilisearch::Opt; use tempfile::TempDir; use crate::common::{ - default_settings, shared_index_with_documents, shared_index_with_nested_documents, Server, - Value, DOCUMENTS, FRUITS_DOCUMENTS, NESTED_DOCUMENTS, SCORE_DOCUMENTS, VECTOR_DOCUMENTS, + default_settings, shared_index_with_documents, shared_index_with_nested_documents, + shared_index_with_score_documents, Server, Value, DOCUMENTS, FRUITS_DOCUMENTS, + NESTED_DOCUMENTS, SCORE_DOCUMENTS, VECTOR_DOCUMENTS, }; use crate::json; @@ -39,39 +40,33 @@ async fn test_settings_documents_indexing_swapping_and_search( let index = server.index("test"); let (task, code) = index.add_documents(documents.clone(), None).await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + assert_eq!(code, 202, "{task}"); + index.wait_task(task.uid()).await.succeeded(); let (task, code) = index.update_settings(settings.clone()).await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + assert_eq!(code, 202, "{task}"); + index.wait_task(task.uid()).await.succeeded(); index.search(query.clone(), test.clone()).await; let (task, code) = server.delete_index("test").await; - assert_eq!(code, 202, "{}", task); - let response = server.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + assert_eq!(code, 202, "{task}"); + server.wait_task(task.uid()).await.succeeded(); eprintln!("Settings -> Documents -> test"); let index = server.index("test"); let (task, code) = index.update_settings(settings.clone()).await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + assert_eq!(code, 202, "{task}"); + index.wait_task(task.uid()).await.succeeded(); let (task, code) = index.add_documents(documents.clone(), None).await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + assert_eq!(code, 202, "{task}"); + index.wait_task(task.uid()).await.succeeded(); index.search(query.clone(), test.clone()).await; let (task, code) = server.delete_index("test").await; - assert_eq!(code, 202, "{}", task); - let response = server.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + assert_eq!(code, 202, "{task}"); + server.wait_task(task.uid()).await.succeeded(); } #[actix_rt::test] @@ -79,7 +74,7 @@ async fn simple_placeholder_search() { let index = shared_index_with_documents().await; index .search(json!({}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 5); }) .await; @@ -87,7 +82,7 @@ async fn simple_placeholder_search() { let index = shared_index_with_nested_documents().await; index .search(json!({}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 4); }) .await; @@ -98,7 +93,7 @@ async fn simple_search() { let index = shared_index_with_documents().await; index .search(json!({"q": "glass"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }) .await; @@ -106,7 +101,7 @@ async fn simple_search() { let index = shared_index_with_nested_documents().await; index .search(json!({"q": "pésti"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 2); }) .await; @@ -141,7 +136,7 @@ async fn search_with_stop_word() { let (_, code) = index .update_settings(json!({"stopWords": ["the", "The", "a", "an", "to", "in", "of"]})) .await; - meili_snap::snapshot!(code, @"202 Accepted"); + snapshot!(code, @"202 Accepted"); let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; @@ -150,7 +145,7 @@ async fn search_with_stop_word() { // prefix search index .search(json!({"q": "to the", "attributesToHighlight": ["title"], "attributesToRetrieve": ["title"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @"[]"); }) .await; @@ -158,7 +153,7 @@ async fn search_with_stop_word() { // non-prefix search index .search(json!({"q": "to the ", "attributesToHighlight": ["title"], "attributesToRetrieve": ["title"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -206,7 +201,7 @@ async fn search_with_typo_settings() { let (_, code) = index .update_settings(json!({"typoTolerance": { "disableOnAttributes": ["title", "id"]}})) .await; - meili_snap::snapshot!(code, @"202 Accepted"); + snapshot!(code, @"202 Accepted"); let documents = DOCUMENTS.clone(); let (task, _status_code) = index.add_documents(documents, None).await; @@ -214,7 +209,7 @@ async fn search_with_typo_settings() { index .search(json!({"q": "287947" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -238,7 +233,7 @@ async fn phrase_search_with_stop_word() { let index = server.index("test"); let (_, code) = index.update_settings(json!({"stopWords": ["the", "of"]})).await; - meili_snap::snapshot!(code, @"202 Accepted"); + snapshot!(code, @"202 Accepted"); let documents = DOCUMENTS.clone(); let (task, _status_code) = index.add_documents(documents, None).await; @@ -246,7 +241,7 @@ async fn phrase_search_with_stop_word() { index .search(json!({"q": "how \"to\" train \"the" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }) .await; @@ -257,7 +252,7 @@ async fn negative_phrase_search() { let index = shared_index_with_documents().await; index .search(json!({"q": "-\"train your dragon\"" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let hits = response["hits"].as_array().unwrap(); assert_eq!(hits.len(), 4); assert_eq!(hits[0]["id"], "287947"); @@ -273,7 +268,7 @@ async fn negative_word_search() { let index = shared_index_with_documents().await; index .search(json!({"q": "-escape" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let hits = response["hits"].as_array().unwrap(); assert_eq!(hits.len(), 4); assert_eq!(hits[0]["id"], "287947"); @@ -286,7 +281,7 @@ async fn negative_word_search() { // Everything that contains derivates of escape but not escape: nothing index .search(json!({"q": "-escape escape" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let hits = response["hits"].as_array().unwrap(); assert_eq!(hits.len(), 0); }) @@ -298,7 +293,7 @@ async fn non_negative_search() { let index = shared_index_with_documents().await; index .search(json!({"q": "- escape" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let hits = response["hits"].as_array().unwrap(); assert_eq!(hits.len(), 1); assert_eq!(hits[0]["id"], "522681"); @@ -307,7 +302,7 @@ async fn non_negative_search() { index .search(json!({"q": "- \"train your dragon\"" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let hits = response["hits"].as_array().unwrap(); assert_eq!(hits.len(), 1); assert_eq!(hits[0]["id"], "166428"); @@ -331,7 +326,7 @@ async fn negative_special_cases_search() { // There is a synonym for escape -> glass but we don't want "escape", only the derivates: glass index .search(json!({"q": "-escape escape" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let hits = response["hits"].as_array().unwrap(); assert_eq!(hits.len(), 1); assert_eq!(hits[0]["id"], "450465"); @@ -356,7 +351,7 @@ async fn test_kanji_language_detection() { index .search(json!({"q": "東京"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }) .await; @@ -382,7 +377,7 @@ async fn test_thai_language() { index .search(json!({"q": "สบู"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); }) .await; } @@ -400,7 +395,7 @@ async fn search_multiple_params() { "offset": 0, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }, ) @@ -417,7 +412,7 @@ async fn search_multiple_params() { "offset": 0, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 2); }, ) @@ -433,7 +428,7 @@ async fn search_with_sort_on_numbers() { "sort": ["id:asc"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 5); }, ) @@ -446,7 +441,7 @@ async fn search_with_sort_on_numbers() { "sort": ["doggos.age:asc"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 4); }, ) @@ -462,7 +457,7 @@ async fn search_with_sort_on_strings() { "sort": ["title:desc"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 5); }, ) @@ -475,7 +470,7 @@ async fn search_with_sort_on_strings() { "sort": ["doggos.name:asc"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 4); }, ) @@ -490,7 +485,7 @@ async fn search_with_multiple_sort() { "sort": ["id:asc", "title:desc"] })) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 5); } @@ -503,7 +498,7 @@ async fn search_facet_distribution() { "facets": ["title"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let dist = response["facetDistribution"].as_object().unwrap(); assert_eq!(dist.len(), 1); assert!(dist.get("title").is_some()); @@ -521,7 +516,7 @@ async fn search_facet_distribution() { "facets": ["father"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let dist = response["facetDistribution"].as_object().unwrap(); assert_eq!(dist.len(), 1); assert_eq!( @@ -544,9 +539,9 @@ async fn search_facet_distribution() { "facets": ["doggos.name"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let dist = response["facetDistribution"].as_object().unwrap(); - assert_eq!(dist.len(), 1, "{:?}", dist); + assert_eq!(dist.len(), 1, "{dist:?}"); assert_eq!( dist["doggos.name"], json!({ "bobby": 1, "buddy": 1, "gros bill": 1, "turbo": 1, "fast": 1}) @@ -561,9 +556,9 @@ async fn search_facet_distribution() { "facets": ["doggos"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let dist = response["facetDistribution"].as_object().unwrap(); - assert_eq!(dist.len(), 3, "{:?}", dist); + assert_eq!(dist.len(), 3, "{dist:?}"); assert_eq!( dist["doggos.name"], json!({ "bobby": 1, "buddy": 1, "gros bill": 1, "turbo": 1, "fast": 1}) @@ -579,7 +574,7 @@ async fn search_facet_distribution() { "facets": ["doggos.name"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let dist = response["facetDistribution"].as_object().unwrap(); assert_eq!(dist.len(), 1); assert_eq!( @@ -604,7 +599,7 @@ async fn displayed_attributes() { let (response, code) = index.search_post(json!({ "attributesToRetrieve": ["title", "id"] })).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert!(response["hits"][0].get("title").is_some()); } @@ -623,7 +618,7 @@ async fn placeholder_search_is_hard_limited() { "limit": 1500, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1000); }, ) @@ -636,7 +631,7 @@ async fn placeholder_search_is_hard_limited() { "limit": 400, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 200); }, ) @@ -652,7 +647,7 @@ async fn placeholder_search_is_hard_limited() { "limit": 1500, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1200); }, ) @@ -665,7 +660,7 @@ async fn placeholder_search_is_hard_limited() { "limit": 400, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 200); }, ) @@ -688,7 +683,7 @@ async fn search_is_hard_limited() { "limit": 1500, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1000); }, ) @@ -702,7 +697,7 @@ async fn search_is_hard_limited() { "limit": 400, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 200); }, ) @@ -719,7 +714,7 @@ async fn search_is_hard_limited() { "limit": 1500, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1200); }, ) @@ -733,7 +728,7 @@ async fn search_is_hard_limited() { "limit": 400, }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 200); }, ) @@ -757,7 +752,7 @@ async fn faceting_max_values_per_facet() { "facets": ["number"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let numbers = response["facetDistribution"]["number"].as_object().unwrap(); assert_eq!(numbers.len(), 100); }, @@ -774,7 +769,7 @@ async fn faceting_max_values_per_facet() { "facets": ["number"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let numbers = &response["facetDistribution"]["number"].as_object().unwrap(); assert_eq!(numbers.len(), 10_000); }, @@ -784,13 +779,7 @@ async fn faceting_max_values_per_facet() { #[actix_rt::test] async fn test_score_details() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - - let res = index.add_documents(json!(documents), None).await; - index.wait_task(res.0.uid()).await.succeeded(); + let index = shared_index_with_documents().await; index .search( @@ -799,8 +788,8 @@ async fn test_score_details() { "showRankingScoreDetails": true, }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "How to Train Your Dragon: The Hidden World", @@ -850,13 +839,7 @@ async fn test_score_details() { #[actix_rt::test] async fn test_score() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = SCORE_DOCUMENTS.clone(); - - let res = index.add_documents(json!(documents), None).await; - index.wait_task(res.0.uid()).await.succeeded(); + let index = shared_index_with_score_documents().await; index .search( @@ -865,8 +848,8 @@ async fn test_score() { "showRankingScore": true, }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "Batman the dark knight returns: Part 1", @@ -903,13 +886,7 @@ async fn test_score() { #[actix_rt::test] async fn test_score_threshold() { let query = "Badman dark returns 1"; - let server = Server::new().await; - let index = server.index("test"); - - let documents = SCORE_DOCUMENTS.clone(); - - let res = index.add_documents(json!(documents), None).await; - index.wait_task(res.0.uid()).await.succeeded(); + let index = shared_index_with_score_documents().await; index .search( @@ -919,9 +896,9 @@ async fn test_score_threshold() { "rankingScoreThreshold": 0.0 }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["estimatedTotalHits"]), @"5"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["estimatedTotalHits"]), @"5"); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "Batman the dark knight returns: Part 1", @@ -962,9 +939,9 @@ async fn test_score_threshold() { "rankingScoreThreshold": 0.2 }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["estimatedTotalHits"]), @r###"3"###); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["estimatedTotalHits"]), @r###"3"###); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "Batman the dark knight returns: Part 1", @@ -995,9 +972,9 @@ async fn test_score_threshold() { "rankingScoreThreshold": 0.5 }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["estimatedTotalHits"]), @r###"2"###); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["estimatedTotalHits"]), @r###"2"###); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "Batman the dark knight returns: Part 1", @@ -1023,9 +1000,9 @@ async fn test_score_threshold() { "rankingScoreThreshold": 0.8 }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["estimatedTotalHits"]), @r###"1"###); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["estimatedTotalHits"]), @r###"1"###); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "Batman the dark knight returns: Part 1", @@ -1046,10 +1023,10 @@ async fn test_score_threshold() { "rankingScoreThreshold": 1.0 }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["estimatedTotalHits"]), @r###"0"###); + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["estimatedTotalHits"]), @r###"0"###); // nobody is perfect - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @"[]"); + snapshot!(json_string!(response["hits"]), @"[]"); }, ) .await; @@ -1075,8 +1052,8 @@ async fn test_degraded_score_details() { "showRankingScoreDetails": true, }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -1162,8 +1139,8 @@ async fn camelcased_words() { index .search(json!({"q": "deLonghi"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 0, @@ -1180,8 +1157,8 @@ async fn camelcased_words() { index .search(json!({"q": "dellonghi"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 0, @@ -1198,8 +1175,8 @@ async fn camelcased_words() { index .search(json!({"q": "testa"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 2, @@ -1220,8 +1197,8 @@ async fn camelcased_words() { index .search(json!({"q": "testab"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 2, @@ -1242,8 +1219,8 @@ async fn camelcased_words() { index .search(json!({"q": "TestaB"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 2, @@ -1264,8 +1241,8 @@ async fn camelcased_words() { index .search(json!({"q": "Testab"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 2, @@ -1286,8 +1263,8 @@ async fn camelcased_words() { index .search(json!({"q": "TestAb"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 2, @@ -1309,8 +1286,8 @@ async fn camelcased_words() { // with Typos index .search(json!({"q": "dellonghi"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 0, @@ -1327,8 +1304,8 @@ async fn camelcased_words() { index .search(json!({"q": "TetsAB"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 2, @@ -1349,8 +1326,8 @@ async fn camelcased_words() { index .search(json!({"q": "TetsAB"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 2, @@ -1377,8 +1354,8 @@ async fn simple_search_with_strange_synonyms() { let (task, _status_code) = index.update_settings(json!({ "synonyms": {"&": ["to"], "to": ["&"]} })).await; - let r = index.wait_task(task.uid()).await; - meili_snap::snapshot!(r["status"], @r###""succeeded""###); + let r = index.wait_task(task.uid()).await.succeeded(); + snapshot!(r["status"], @r###""succeeded""###); let documents = DOCUMENTS.clone(); let (task, _status_code) = index.add_documents(documents, None).await; @@ -1386,8 +1363,8 @@ async fn simple_search_with_strange_synonyms() { index .search(json!({"q": "How to train"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "How to Train Your Dragon: The Hidden World", @@ -1404,8 +1381,8 @@ async fn simple_search_with_strange_synonyms() { index .search(json!({"q": "How & train"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "How to Train Your Dragon: The Hidden World", @@ -1422,8 +1399,8 @@ async fn simple_search_with_strange_synonyms() { index .search(json!({"q": "to"}), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" [ { "title": "How to Train Your Dragon: The Hidden World", @@ -1462,8 +1439,8 @@ async fn change_attributes_settings() { "attributesToRetrieve": ["id", "doggos"] }), |response, code| { - assert_eq!(code, 200, "{}", response); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + assert_eq!(code, 200, "{response}"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 852, @@ -1493,8 +1470,8 @@ async fn change_attributes_settings() { "attributesToRetrieve": ["id", "doggos"] }), |response, code| { - assert_eq!(code, 200, "{}", response); - meili_snap::snapshot!(meili_snap::json_string!(response["hits"]), @r###" + assert_eq!(code, 200, "{response}"); + snapshot!(json_string!(response["hits"]), @r###" [ { "id": 852, @@ -1563,7 +1540,7 @@ async fn test_nested_fields() { &settings, &json!({"q": "document"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1609,7 +1586,7 @@ async fn test_nested_fields() { &settings, &json!({"q": "zeroth"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1627,7 +1604,7 @@ async fn test_nested_fields() { &settings, &json!({"q": "first"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1650,7 +1627,7 @@ async fn test_nested_fields() { &settings, &json!({"q": "field"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1686,7 +1663,7 @@ async fn test_nested_fields() { &settings, &json!({"q": "array"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); // nested is not searchable snapshot!(json_string!(response["hits"]), @"[]"); }, @@ -1698,7 +1675,7 @@ async fn test_nested_fields() { &settings, &json!({"q": "lied"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); // nested is not searchable snapshot!(json_string!(response["hits"]), @"[]"); }, @@ -1711,7 +1688,7 @@ async fn test_nested_fields() { &settings, &json!({"filter": "nested.object = field"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1747,7 +1724,7 @@ async fn test_nested_fields() { &settings, &json!({"filter": "nested.machin = bidule"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1770,7 +1747,7 @@ async fn test_nested_fields() { &settings, &json!({"filter": "nested = array"}), |response, code| { - assert_eq!(code, 400, "{}", response); + assert_eq!(code, 400, "{response}"); snapshot!(json_string!(response), @r###" { "message": "Index `test`: Attribute `nested` is not filterable. Available filterable attribute patterns are: `nested.machin`, `nested.object`, `title`.\n1:7 nested = array", @@ -1789,7 +1766,7 @@ async fn test_nested_fields() { &settings, &json!({"filter": r#"nested = "I lied""#}), |response, code| { - assert_eq!(code, 400, "{}", response); + assert_eq!(code, 400, "{response}"); snapshot!(json_string!(response), @r###" { "message": "Index `test`: Attribute `nested` is not filterable. Available filterable attribute patterns are: `nested.machin`, `nested.object`, `title`.\n1:7 nested = \"I lied\"", @@ -1850,7 +1827,7 @@ async fn test_typo_settings() { }), &json!({"q": "document"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1902,7 +1879,7 @@ async fn test_typo_settings() { }), &json!({"q": "docume"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -1955,7 +1932,7 @@ async fn change_facet_casing() { })) .await; assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, _code) = index .add_documents( @@ -1968,7 +1945,7 @@ async fn change_facet_casing() { None, ) .await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, _code) = index .add_documents( @@ -1981,12 +1958,12 @@ async fn change_facet_casing() { None, ) .await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); index .search(json!({ "facets": ["dog"] }), |response, code| { - meili_snap::snapshot!(code, @"200 OK"); - meili_snap::snapshot!(meili_snap::json_string!(response["facetDistribution"]), @r###" + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["facetDistribution"]), @r###" { "dog": { "bouvier bernois": 1 @@ -2045,7 +2022,7 @@ async fn test_exact_typos_terms() { }), &json!({"q": "12345"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -2080,7 +2057,7 @@ async fn test_exact_typos_terms() { }), &json!({"q": "123457"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###"[]"###); }, ) From 57eecd61970c51bd19a4b16e54595be9a32da1f5 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 20 May 2025 14:37:45 +0300 Subject: [PATCH 023/292] Remove an empty line Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/meilisearch/tests/common/mod.rs b/crates/meilisearch/tests/common/mod.rs index da8beac3a..046519a0e 100644 --- a/crates/meilisearch/tests/common/mod.rs +++ b/crates/meilisearch/tests/common/mod.rs @@ -282,7 +282,6 @@ pub async fn shared_index_with_score_documents() -> &'static Index<'static, Shar }).await } - pub static NESTED_DOCUMENTS: Lazy = Lazy::new(|| { json!([ { From 8c8d98eeaa839f71db7395a65c1801811e161432 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 21 May 2025 10:48:20 +0300 Subject: [PATCH 024/292] Use shared server and unique indices for all tests where possible Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/mod.rs | 64 +++++++++++++------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index 2ac0d0400..70d76db0c 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -110,8 +110,8 @@ async fn simple_search() { /// See #[actix_rt::test] async fn bug_5547() { - let server = Server::new().await; - let index = server.index("big_fst"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, _code) = index.create(None).await; index.wait_task(response.uid()).await.succeeded(); @@ -130,8 +130,8 @@ async fn bug_5547() { #[actix_rt::test] async fn search_with_stop_word() { // related to https://github.com/meilisearch/meilisearch/issues/4984 - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (_, code) = index .update_settings(json!({"stopWords": ["the", "The", "a", "an", "to", "in", "of"]})) @@ -195,8 +195,8 @@ async fn search_with_stop_word() { #[actix_rt::test] async fn search_with_typo_settings() { // related to https://github.com/meilisearch/meilisearch/issues/5240 - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (_, code) = index .update_settings(json!({"typoTolerance": { "disableOnAttributes": ["title", "id"]}})) @@ -229,8 +229,8 @@ async fn search_with_typo_settings() { #[actix_rt::test] async fn phrase_search_with_stop_word() { // related to https://github.com/meilisearch/meilisearch/issues/3521 - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (_, code) = index.update_settings(json!({"stopWords": ["the", "of"]})).await; snapshot!(code, @"202 Accepted"); @@ -312,8 +312,8 @@ async fn non_negative_search() { #[actix_rt::test] async fn negative_special_cases_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); let (task, _status_code) = index.add_documents(documents, None).await; @@ -338,8 +338,8 @@ async fn negative_special_cases_search() { #[cfg(not(feature = "chinese-pinyin"))] #[actix_rt::test] async fn test_kanji_language_detection() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { "id": 0, "title": "The quick (\"brown\") fox can't jump 32.3 feet, right? Brr, it's 29.3°F!" }, @@ -360,8 +360,8 @@ async fn test_kanji_language_detection() { #[cfg(feature = "default")] #[actix_rt::test] async fn test_thai_language() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); // We don't need documents, the issue is on the query side only. let documents = json!([ @@ -588,8 +588,8 @@ async fn search_facet_distribution() { #[actix_rt::test] async fn displayed_attributes() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.update_settings(json!({ "displayedAttributes": ["title"] })).await; @@ -605,8 +605,8 @@ async fn displayed_attributes() { #[actix_rt::test] async fn placeholder_search_is_hard_limited() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents: Vec<_> = (0..1200).map(|i| json!({ "id": i, "text": "I am unique!" })).collect(); let (task, _status_code) = index.add_documents(documents.into(), None).await; @@ -669,8 +669,8 @@ async fn placeholder_search_is_hard_limited() { #[actix_rt::test] async fn search_is_hard_limited() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents: Vec<_> = (0..1200).map(|i| json!({ "id": i, "text": "I am unique!" })).collect(); let (task, _status_code) = index.add_documents(documents.into(), None).await; @@ -737,8 +737,8 @@ async fn search_is_hard_limited() { #[actix_rt::test] async fn faceting_max_values_per_facet() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.update_settings(json!({ "filterableAttributes": ["number"] })).await; @@ -1034,8 +1034,8 @@ async fn test_score_threshold() { #[actix_rt::test] async fn test_degraded_score_details() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); @@ -1123,8 +1123,8 @@ async fn test_degraded_score_details() { #[cfg(feature = "default")] #[actix_rt::test] async fn camelcased_words() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); // related to https://github.com/meilisearch/meilisearch/issues/3818 let documents = json!([ @@ -1349,8 +1349,8 @@ async fn camelcased_words() { #[actix_rt::test] async fn simple_search_with_strange_synonyms() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.update_settings(json!({ "synonyms": {"&": ["to"], "to": ["&"]} })).await; @@ -1418,8 +1418,8 @@ async fn simple_search_with_strange_synonyms() { #[actix_rt::test] async fn change_attributes_settings() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.update_settings(json!({ "searchableAttributes": ["father", "mother"] })).await; @@ -1923,8 +1923,8 @@ async fn test_typo_settings() { /// Modifying facets with different casing should work correctly #[actix_rt::test] async fn change_facet_casing() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ From a964251cee096877f140cc5934a6d7bf48b1d7f4 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Mon, 5 May 2025 16:22:13 +0200 Subject: [PATCH 025/292] Remove useless reset fixes https://github.com/meilisearch/meilisearch/pull/5494#discussion_r2069373494 --- crates/milli/src/update/settings.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index 51d9aed27..fce2989b1 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -884,7 +884,6 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { disabled_typos_terms.disable_on_numbers = disable_on_numbers; } Setting::Reset => { - self.index.delete_disabled_typos_terms(self.wtxn)?; disabled_typos_terms.disable_on_numbers = DisabledTyposTerms::default().disable_on_numbers; } From 73e4206b3c09cc4f02aa6290e3b236e81f5da65d Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Mon, 5 May 2025 16:23:01 +0200 Subject: [PATCH 026/292] Pass a progress callback to recompute_word_fst_from_word_docids_database fixes https://github.com/meilisearch/meilisearch/pull/5494#discussion_r2069377991 --- .../milli/src/update/new/indexer/post_processing.rs | 7 ++++++- crates/milli/src/update/upgrade/v1_15.rs | 11 ++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/crates/milli/src/update/new/indexer/post_processing.rs b/crates/milli/src/update/new/indexer/post_processing.rs index b5c89d0d9..288b9c5ed 100644 --- a/crates/milli/src/update/new/indexer/post_processing.rs +++ b/crates/milli/src/update/new/indexer/post_processing.rs @@ -131,7 +131,12 @@ fn compute_word_fst( } } -pub fn recompute_word_fst_from_word_docids_database(index: &Index, wtxn: &mut RwTxn) -> Result<()> { +pub fn recompute_word_fst_from_word_docids_database( + index: &Index, + wtxn: &mut RwTxn, + progress: &Progress, +) -> Result<()> { + progress.update_progress(PostProcessingWords::WordFst); let fst = fst::Set::default().map_data(std::borrow::Cow::Owned)?; let mut word_fst_builder = WordFstBuilder::new(&fst)?; let words = index.word_docids.iter(wtxn)?.remap_data_type::(); diff --git a/crates/milli/src/update/upgrade/v1_15.rs b/crates/milli/src/update/upgrade/v1_15.rs index 2c3cff355..cea4783a1 100644 --- a/crates/milli/src/update/upgrade/v1_15.rs +++ b/crates/milli/src/update/upgrade/v1_15.rs @@ -3,7 +3,7 @@ use heed::RwTxn; use super::UpgradeIndex; use crate::progress::Progress; use crate::update::new::indexer::recompute_word_fst_from_word_docids_database; -use crate::{make_enum_progress, Index, Result}; +use crate::{Index, Result}; #[allow(non_camel_case_types)] pub(super) struct Latest_V1_14_To_Latest_V1_15(); @@ -17,14 +17,7 @@ impl UpgradeIndex for Latest_V1_14_To_Latest_V1_15 { progress: Progress, ) -> Result { // Recompute the word FST from the word docids database. - make_enum_progress! { - enum TypoTolerance { - RecomputeWordFst, - } - }; - - progress.update_progress(TypoTolerance::RecomputeWordFst); - recompute_word_fst_from_word_docids_database(index, wtxn)?; + recompute_word_fst_from_word_docids_database(index, wtxn, &progress)?; Ok(false) } From 699ec18de80d967dc7193791e5dadbf0f9f9fde2 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 6 May 2025 14:39:47 +0200 Subject: [PATCH 027/292] Fix warnings --- crates/milli/src/disabled_typos_terms.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/milli/src/disabled_typos_terms.rs b/crates/milli/src/disabled_typos_terms.rs index 3a0d0c0f5..7ae35f828 100644 --- a/crates/milli/src/disabled_typos_terms.rs +++ b/crates/milli/src/disabled_typos_terms.rs @@ -33,13 +33,6 @@ impl Index { Ok(()) } - - pub(crate) fn delete_disabled_typos_terms(&self, txn: &mut RwTxn<'_>) -> heed::Result<()> { - self.main - .remap_types::>() - .delete(txn, main_key::DISABLED_TYPOS_TERMS)?; - Ok(()) - } } impl DisabledTyposTerms { From 293a42518303ae4850f89d3d53983a54b75df1e9 Mon Sep 17 00:00:00 2001 From: Many the fish Date: Tue, 20 May 2025 14:17:27 +0200 Subject: [PATCH 028/292] Apply suggestions from code review Co-authored-by: Martin Grigorov --- crates/meilisearch/tests/search/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index f1d9c8b3b..ff6d3e2b8 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -2045,7 +2045,7 @@ async fn test_exact_typos_terms() { }), &json!({"q": "12345"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###" [ { @@ -2080,7 +2080,7 @@ async fn test_exact_typos_terms() { }), &json!({"q": "123457"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["hits"]), @r###"[]"###); }, ) From 01ef055f4083c1d884ba1717c78baa98fa9ddaab Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 13 May 2025 16:22:33 +0200 Subject: [PATCH 029/292] Update charabia v0.9.4 --- Cargo.lock | 794 ++++++++++++++++++++++++---------------- crates/milli/Cargo.toml | 2 +- 2 files changed, 486 insertions(+), 310 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b23f7e83..8a8608e63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.8.5", "sha1", "smallvec", "tokio", @@ -241,6 +241,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aes" version = "0.8.4" @@ -363,9 +369,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" dependencies = [ "backtrace", ] @@ -405,11 +411,11 @@ dependencies = [ "nohash", "ordered-float", "page_size", - "rand", + "rand 0.8.5", "rayon", "roaring", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "tracing", ] @@ -498,7 +504,7 @@ dependencies = [ "memmap2", "milli", "mimalloc", - "rand", + "rand 0.8.5", "rand_chacha", "reqwest", "roaring", @@ -830,7 +836,7 @@ dependencies = [ "memmap2", "num-traits", "num_cpus", - "rand", + "rand 0.8.5", "rand_distr", "rayon", "safetensors", @@ -876,7 +882,7 @@ dependencies = [ "candle-nn", "fancy-regex", "num-traits", - "rand", + "rand 0.8.5", "rayon", "serde", "serde_json", @@ -904,7 +910,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.9", + "thiserror 2.0.12", ] [[package]] @@ -976,9 +982,9 @@ dependencies = [ [[package]] name = "charabia" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650d52f87a36472ea1c803dee49d6bfd23d426efa9363e2f4c4a0e6a236d3407" +checksum = "adcfced86045084567f803789cb562f9cbae263efd2bc5c1e8ed8fd99e19baf5" dependencies = [ "aho-corasick", "csv", @@ -1178,12 +1184,31 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -1413,6 +1438,12 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "dary_heap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728" + [[package]] name = "deadpool" version = "0.10.0" @@ -1668,7 +1699,7 @@ dependencies = [ "serde_json", "tar", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tracing", "uuid", @@ -1765,9 +1796,9 @@ checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -1857,7 +1888,7 @@ name = "file-store" version = "1.15.0" dependencies = [ "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "tracing", "uuid", ] @@ -1886,12 +1917,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.2", + "miniz_oxide 0.8.8", ] [[package]] @@ -1923,6 +1954,21 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2253,9 +2299,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "grenad" @@ -2324,7 +2370,7 @@ dependencies = [ "cfg-if", "crunchy", "num-traits", - "rand", + "rand 0.8.5", "rand_distr", ] @@ -2454,7 +2500,7 @@ dependencies = [ "http 1.2.0", "indicatif", "log", - "rand", + "rand 0.8.5", "serde", "serde_json", "thiserror 1.0.69", @@ -2566,6 +2612,22 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.10" @@ -2736,6 +2798,29 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" +[[package]] +name = "include-flate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df49c16750695486c1f34de05da5b7438096156466e7f76c38fcdf285cf0113e" +dependencies = [ + "include-flate-codegen", + "lazy_static", + "libflate", +] + +[[package]] +name = "include-flate-codegen" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c5b246c6261be723b85c61ecf87804e8ea4a35cb68be0ff282ed84b95ffe7d7" +dependencies = [ + "libflate", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "index-scheduler" version = "1.15.0" @@ -2768,7 +2853,7 @@ dependencies = [ "serde_json", "synchronoise", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tracing", "ureq", @@ -2912,17 +2997,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "jieba-rs" -version = "0.7.0" +name = "jieba-macros" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e2b0210dc78b49337af9e49d7ae41a39dceac6e5985613f1cf7763e2f76a25" +checksum = "7c676b32a471d3cfae8dac2ad2f8334cd52e53377733cca8c1fb0a5062fec192" +dependencies = [ + "phf_codegen", +] + +[[package]] +name = "jieba-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1bcad6332969e4d48ee568d430e14ee6dea70740c2549d005d87677ebefb0c" dependencies = [ "cedarwood", - "derive_builder 0.20.2", "fxhash", + "include-flate", + "jieba-macros", "lazy_static", "phf", - "phf_codegen", "regex", ] @@ -3014,6 +3108,30 @@ version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +[[package]] +name = "libflate" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" +dependencies = [ + "core2", + "hashbrown 0.14.3", + "rle-decode-fast", +] + [[package]] name = "libgit2-sys" version = "0.17.0+1.8.1" @@ -3077,155 +3195,52 @@ dependencies = [ [[package]] name = "lindera" -version = "0.32.3" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "832c220475557e3b44a46cad1862b57f010f0c6e93d771d0e628e08689c068b1" -dependencies = [ - "lindera-analyzer", - "lindera-core", - "lindera-dictionary", - "lindera-filter", - "lindera-tokenizer", -] - -[[package]] -name = "lindera-analyzer" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e26651714abf5167e6b6a80f5cdaa0cad41c5fcb84d8ba96bebafcb9029339" +checksum = "7a2505be2fdb869346a4cc36d99a7a76609f616fb7630d3e8c638ffd3a90b19c" dependencies = [ "anyhow", "bincode", "byteorder", - "encoding", + "csv", "kanaria", - "lindera-cc-cedict-builder", - "lindera-core", + "lindera-cc-cedict", "lindera-dictionary", - "lindera-filter", - "lindera-ipadic-builder", - "lindera-ko-dic-builder", - "lindera-tokenizer", - "lindera-unidic-builder", + "lindera-ipadic", + "lindera-ipadic-neologd", + "lindera-ko-dic", + "lindera-unidic", "once_cell", "regex", "serde", "serde_json", - "thiserror 1.0.69", + "serde_yaml", + "strum", + "strum_macros", "unicode-blocks", "unicode-normalization", "unicode-segmentation", "yada", ] -[[package]] -name = "lindera-assets" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb01f1ca53c1e642234c6c7fdb9ac664ad0c1ab9502f33e4200201bac7e6ce7" -dependencies = [ - "encoding", - "flate2", - "lindera-core", - "tar", - "ureq", -] - [[package]] name = "lindera-cc-cedict" -version = "0.32.3" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7618d9aa947fdd7c38eae2b79f0fd237ecb5067608f1363610ba20d20ab5a8" +checksum = "b36cb64b16e964154962074065ce102ccf6b8abe2cbc3f0269bef65b3f754e0b" dependencies = [ "bincode", "byteorder", - "lindera-cc-cedict-builder", - "lindera-core", - "lindera-decompress", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-cc-cedict-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efdbcb809d81428935d601a78c94bfb39500749213f7320705f427a7a1d31aec" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", -] - -[[package]] -name = "lindera-compress" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac178afa2456dac469d3b1a2d7fbaf3e1ea796a1f52321e8ac29545a53c239c" -dependencies = [ - "anyhow", - "flate2", - "lindera-decompress", -] - -[[package]] -name = "lindera-core" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "649777465f48147ce593ab6db347e235e3af8f693a23f4437be94a1cdbdf5fdf" -dependencies = [ - "anyhow", - "bincode", - "byteorder", - "encoding_rs", - "log", - "once_cell", - "serde", - "thiserror 1.0.69", - "yada", -] - -[[package]] -name = "lindera-decompress" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3faaceb85e43ac250021866c6db3cdc9997b44b3d3ea498594d04edc91fc45" -dependencies = [ - "anyhow", - "flate2", - "serde", + "tokio", ] [[package]] name = "lindera-dictionary" -version = "0.32.3" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e15b2d2d8a4ad45f2e373a084931cf3dfbde15f124044e2436bb920af3366c" -dependencies = [ - "anyhow", - "bincode", - "byteorder", - "lindera-cc-cedict", - "lindera-cc-cedict-builder", - "lindera-core", - "lindera-ipadic", - "lindera-ipadic-builder", - "lindera-ipadic-neologd", - "lindera-ipadic-neologd-builder", - "lindera-ko-dic", - "lindera-ko-dic-builder", - "lindera-unidic", - "lindera-unidic-builder", - "serde", - "strum", - "strum_macros", -] - -[[package]] -name = "lindera-dictionary-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59802949110545b59b663917ed3fd55dc3b3a8cde6bd20137d7fe24372cfb9aa" +checksum = "8c8b9410fe52fe4ee794a585e436f9d6470e6209a598b303d01ba39a66354c15" dependencies = [ "anyhow", "bincode", @@ -3235,157 +3250,70 @@ dependencies = [ "encoding", "encoding_rs", "encoding_rs_io", + "flate2", "glob", - "lindera-compress", - "lindera-core", - "lindera-decompress", "log", - "yada", -] - -[[package]] -name = "lindera-filter" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1320f118c3fc9e897f4ebfc16864e5ef8c0b06ba769c0a50e53f193f9d682bf8" -dependencies = [ - "anyhow", - "csv", - "kanaria", - "lindera-cc-cedict-builder", - "lindera-core", - "lindera-dictionary", - "lindera-ipadic-builder", - "lindera-ko-dic-builder", - "lindera-unidic-builder", + "md5", "once_cell", - "regex", + "rand 0.9.1", + "reqwest", "serde", - "serde_json", - "unicode-blocks", - "unicode-normalization", - "unicode-segmentation", + "tar", + "thiserror 2.0.12", + "tokio", "yada", ] [[package]] name = "lindera-ipadic" -version = "0.32.3" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4731bf3730f1f38266d7ee9bca7d460cd336645c9dfd4e6a1082e58ab1e993" +checksum = "5044434614e3d4aa241d354c2903c2cd33544c35c5181ba315ca10b619beec2f" dependencies = [ "bincode", "byteorder", - "lindera-core", - "lindera-decompress", - "lindera-ipadic-builder", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-ipadic-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "309966c12e682f67205c3cd3c8dc55bbdcd1eb3b5c7c5cb41fb8acd18906d340" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", + "tokio", ] [[package]] name = "lindera-ipadic-neologd" -version = "0.32.3" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90e919b4cfb9962d24ee1e1d50a7c163bbf356376495ad66d1996e20b9f9e44" +checksum = "080e312e163efb82a3b939dbcc2d0121edbc6a0f538ac3f00c5db808ed60fe15" dependencies = [ "bincode", "byteorder", - "lindera-core", - "lindera-decompress", - "lindera-ipadic-neologd-builder", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-ipadic-neologd-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e517df0d501f9f8bf3126da20fc8cb9a5e37921e0eec1824d7a62f096463e02" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", + "tokio", ] [[package]] name = "lindera-ko-dic" -version = "0.32.3" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c6da4e68bc8b452a54b96d65361ebdceb4b6f36ecf262425c0e1f77960ae82" +checksum = "a31e3abc0125607eb482a7b184523d6f6f15cd7b05a7ae01cf4c3561eefecb64" dependencies = [ "bincode", "byteorder", - "lindera-assets", - "lindera-core", - "lindera-decompress", - "lindera-ko-dic-builder", - "once_cell", -] - -[[package]] -name = "lindera-ko-dic-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc95884cc8f6dfb176caf5991043a4acf94c359215bbd039ea765e00454f271" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", -] - -[[package]] -name = "lindera-tokenizer" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122042e1232a55c3604692445952a134e523822e9b4b9ab32a53ff890037ad4" -dependencies = [ - "bincode", - "lindera-core", "lindera-dictionary", "once_cell", - "serde", - "serde_json", + "tokio", ] [[package]] name = "lindera-unidic" -version = "0.32.3" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffae1fb2f2614abdcb50f99b138476dbac19862ffa57bfdc9c7b5d5b22a90c" +checksum = "840102fd33c56bb9ea9f977168922e1ee3374a2e0db33e9b9c8913226522961f" dependencies = [ "bincode", "byteorder", - "lindera-assets", - "lindera-core", - "lindera-decompress", - "lindera-unidic-builder", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-unidic-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe50055327712ebd1bcc74b657cf78c728a78b9586e3f99d5dd0b6a0be221c5d" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", + "tokio", ] [[package]] @@ -3510,9 +3438,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" @@ -3645,7 +3573,7 @@ dependencies = [ "pin-project-lite", "platform-dirs", "prometheus", - "rand", + "rand 0.8.5", "rayon", "regex", "reqwest", @@ -3667,7 +3595,7 @@ dependencies = [ "temp-env", "tempfile", "termcolor", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tokio", "toml", @@ -3694,12 +3622,12 @@ dependencies = [ "hmac", "maplit", "meilisearch-types", - "rand", + "rand 0.8.5", "roaring", "serde", "serde_json", "sha2", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "uuid", ] @@ -3731,7 +3659,7 @@ dependencies = [ "serde_json", "tar", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tokio", "utoipa", @@ -3824,7 +3752,7 @@ dependencies = [ "obkv", "once_cell", "ordered-float", - "rand", + "rand 0.8.5", "rayon", "rayon-par-bridge", "rhai", @@ -3838,7 +3766,7 @@ dependencies = [ "smallvec", "smartstring", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "thread_local", "tiktoken-rs", "time", @@ -3893,9 +3821,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -3956,6 +3884,23 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nohash" version = "0.2.0" @@ -4146,9 +4091,9 @@ checksum = "ae4512a8f418ac322335255a72361b9ac927e106f4d7fe6ab4d8ac59cb01f7a9" [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "onig" @@ -4178,6 +4123,50 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags 2.9.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -4364,7 +4353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] @@ -4565,7 +4554,7 @@ dependencies = [ "parking_lot", "procfs", "protobuf", - "thiserror 2.0.9", + "thiserror 2.0.12", ] [[package]] @@ -4644,7 +4633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", - "rand", + "rand 0.8.5", "ring", "rustc-hash 2.1.0", "rustls", @@ -4690,7 +4679,16 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_core 0.9.3", ] [[package]] @@ -4700,7 +4698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -4712,6 +4710,12 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" + [[package]] name = "rand_distr" version = "0.4.3" @@ -4719,7 +4723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -4852,25 +4856,29 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.12" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ "base64 0.22.1", "bytes", + "encoding_rs", "futures-channel", "futures-core", "futures-util", + "h2 0.4.5", "http 1.2.0", "http-body", "http-body-util", "hyper", "hyper-rustls", + "hyper-tls", "hyper-util", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -4882,7 +4890,9 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", + "system-configuration", "tokio", + "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -4966,6 +4976,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + [[package]] name = "roaring" version = "0.10.10" @@ -4999,7 +5015,7 @@ dependencies = [ "borsh", "bytes", "num-traits", - "rand", + "rand 0.8.5", "rkyv", "serde", "serde_json", @@ -5117,6 +5133,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -5129,6 +5154,29 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "segment" version = "0.2.5" @@ -5139,7 +5187,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", ] @@ -5230,6 +5278,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha-1" version = "0.10.1" @@ -5464,20 +5525,20 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", @@ -5581,6 +5642,27 @@ dependencies = [ "windows", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -5589,9 +5671,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.43" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", @@ -5650,11 +5732,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.9" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.9", + "thiserror-impl 2.0.12", ] [[package]] @@ -5670,9 +5752,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.9" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -5798,7 +5880,7 @@ dependencies = [ "monostate", "onig", "paste", - "rand", + "rand 0.8.5", "rayon", "rayon-cond", "regex", @@ -5814,9 +5896,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.43.1" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "492a604e2fd7f814268a378409e6c92b5525d747d10db9a229723f55a417958c" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", @@ -5841,6 +5923,16 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" @@ -6167,6 +6259,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -6570,14 +6668,20 @@ dependencies = [ ] [[package]] -name = "windows-registry" -version = "0.2.0" +name = "windows-link" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result 0.2.0", + "windows-result 0.3.2", "windows-strings", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] @@ -6591,21 +6695,20 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.2.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -6635,6 +6738,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -6674,13 +6786,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -6699,6 +6827,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -6717,6 +6851,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -6735,12 +6875,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -6759,6 +6911,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -6777,6 +6935,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -6795,6 +6959,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -6813,6 +6983,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.5.40" @@ -7089,7 +7265,7 @@ dependencies = [ "memchr", "pbkdf2", "sha1", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "xz2", "zeroize", diff --git a/crates/milli/Cargo.toml b/crates/milli/Cargo.toml index 909a5f8f9..06808f075 100644 --- a/crates/milli/Cargo.toml +++ b/crates/milli/Cargo.toml @@ -18,7 +18,7 @@ bincode = "1.3.3" bstr = "1.11.3" bytemuck = { version = "1.21.0", features = ["extern_crate_alloc"] } byteorder = "1.5.0" -charabia = { version = "0.9.3", default-features = false } +charabia = { version = "0.9.4", default-features = false } concat-arrays = "0.1.2" convert_case = "0.6.0" crossbeam-channel = "0.5.15" From 1b718afd11a2b803ba399fe8b6841256c5d337f2 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Wed, 21 May 2025 11:52:03 +0200 Subject: [PATCH 030/292] Update charabia removing a lot of dependencies --- Cargo.lock | 205 ++++------------------------------------ crates/milli/Cargo.toml | 2 +- 2 files changed, 18 insertions(+), 189 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a8608e63..84e13a78c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -982,9 +982,9 @@ dependencies = [ [[package]] name = "charabia" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcfced86045084567f803789cb562f9cbae263efd2bc5c1e8ed8fd99e19baf5" +checksum = "4da3b398d57d5526189869b32ac0b4f7fb436f490f47a2a19685cee634df72d2" dependencies = [ "aho-corasick", "csv", @@ -1184,16 +1184,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1954,21 +1944,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2612,22 +2587,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.10" @@ -3195,9 +3154,9 @@ dependencies = [ [[package]] name = "lindera" -version = "0.42.2" +version = "0.42.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2505be2fdb869346a4cc36d99a7a76609f616fb7630d3e8c638ffd3a90b19c" +checksum = "8fa3936dbcfc54b90a53da68ec8fe209656cfa691147f951944f48c61dcde317" dependencies = [ "anyhow", "bincode", @@ -3225,9 +3184,9 @@ dependencies = [ [[package]] name = "lindera-cc-cedict" -version = "0.42.2" +version = "0.42.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b36cb64b16e964154962074065ce102ccf6b8abe2cbc3f0269bef65b3f754e0b" +checksum = "7a4720c69e32b278614eefb8181e0ef78907fa115d947edaeaedb1150785b902" dependencies = [ "bincode", "byteorder", @@ -3238,9 +3197,9 @@ dependencies = [ [[package]] name = "lindera-dictionary" -version = "0.42.2" +version = "0.42.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c8b9410fe52fe4ee794a585e436f9d6470e6209a598b303d01ba39a66354c15" +checksum = "b123ac54a74c9418616c96d0d7cf5eb8fbf372211c07032d1e174c94e40ff030" dependencies = [ "anyhow", "bincode", @@ -3266,9 +3225,9 @@ dependencies = [ [[package]] name = "lindera-ipadic" -version = "0.42.2" +version = "0.42.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5044434614e3d4aa241d354c2903c2cd33544c35c5181ba315ca10b619beec2f" +checksum = "71c3786e6cf65dd1e8537c3c35637f887289bf83687f6fbcac3a6679bfa33265" dependencies = [ "bincode", "byteorder", @@ -3279,9 +3238,9 @@ dependencies = [ [[package]] name = "lindera-ipadic-neologd" -version = "0.42.2" +version = "0.42.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e312e163efb82a3b939dbcc2d0121edbc6a0f538ac3f00c5db808ed60fe15" +checksum = "42646cc30bf8ceabf3db1154358329e1031f2af25ca1721ddba8ee3666881a08" dependencies = [ "bincode", "byteorder", @@ -3292,9 +3251,9 @@ dependencies = [ [[package]] name = "lindera-ko-dic" -version = "0.42.2" +version = "0.42.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31e3abc0125607eb482a7b184523d6f6f15cd7b05a7ae01cf4c3561eefecb64" +checksum = "10f94a00fc5931636c10d2e6af4cfa43fbf95f8a529caa45d10600f3cb2853c9" dependencies = [ "bincode", "byteorder", @@ -3305,9 +3264,9 @@ dependencies = [ [[package]] name = "lindera-unidic" -version = "0.42.2" +version = "0.42.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "840102fd33c56bb9ea9f977168922e1ee3374a2e0db33e9b9c8913226522961f" +checksum = "e5933014ca145351d59bb50a6e509a53af1f89ceda687fe9efd6d534e6b59a27" dependencies = [ "bincode", "byteorder", @@ -3884,23 +3843,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nohash" version = "0.2.0" @@ -4123,50 +4065,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "openssl" -version = "0.10.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" -dependencies = [ - "bitflags 2.9.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -4862,23 +4760,19 @@ checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ "base64 0.22.1", "bytes", - "encoding_rs", "futures-channel", "futures-core", "futures-util", - "h2 0.4.5", "http 1.2.0", "http-body", "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -4890,9 +4784,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", - "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -5133,15 +5025,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -5154,29 +5037,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "segment" version = "0.2.5" @@ -5642,27 +5502,6 @@ dependencies = [ "windows", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -5700,7 +5539,7 @@ dependencies = [ "getrandom 0.2.15", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5923,16 +5762,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.0" diff --git a/crates/milli/Cargo.toml b/crates/milli/Cargo.toml index 06808f075..3ce02b444 100644 --- a/crates/milli/Cargo.toml +++ b/crates/milli/Cargo.toml @@ -18,7 +18,7 @@ bincode = "1.3.3" bstr = "1.11.3" bytemuck = { version = "1.21.0", features = ["extern_crate_alloc"] } byteorder = "1.5.0" -charabia = { version = "0.9.4", default-features = false } +charabia = { version = "0.9.5", default-features = false } concat-arrays = "0.1.2" convert_case = "0.6.0" crossbeam-channel = "0.5.15" From c9b78970c94a10adc7dcf4fc3c3fa0ab0eb423e5 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 22 May 2025 10:52:21 +0200 Subject: [PATCH 031/292] Remove lambdas from the `find_*_derivations` Make sure their number of insert in the interner are bounded --- .../new/query_term/compute_derivations.rs | 93 ++++++------------- 1 file changed, 29 insertions(+), 64 deletions(-) diff --git a/crates/milli/src/search/new/query_term/compute_derivations.rs b/crates/milli/src/search/new/query_term/compute_derivations.rs index 0a39384bd..dcb68f2ea 100644 --- a/crates/milli/src/search/new/query_term/compute_derivations.rs +++ b/crates/milli/src/search/new/query_term/compute_derivations.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeSet; -use std::ops::ControlFlow; use fst::automaton::Str; use fst::{IntoStreamer, Streamer}; @@ -16,12 +15,6 @@ use crate::search::new::{limits, SearchContext}; use crate::search::{build_dfa, get_first}; use crate::{Result, MAX_WORD_LENGTH}; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum NumberOfTypos { - One, - Two, -} - impl Interned { pub fn compute_fully_if_needed(self, ctx: &mut SearchContext<'_>) -> Result<()> { let s = ctx.term_interner.get_mut(self); @@ -45,7 +38,7 @@ impl Interned { fn find_zero_typo_prefix_derivations( ctx: &mut SearchContext<'_>, word_interned: Interned, - mut visit: impl FnMut(Interned) -> Result>, + prefix_of: &mut BTreeSet>, ) -> Result<()> { let word = ctx.word_interner.get(word_interned).to_owned(); let word = word.as_str(); @@ -65,8 +58,8 @@ fn find_zero_typo_prefix_derivations( let derived_word = derived_word.to_string(); let derived_word_interned = ctx.word_interner.insert(derived_word); if derived_word_interned != word_interned { - let cf = visit(derived_word_interned)?; - if cf.is_break() { + prefix_of.insert(derived_word_interned); + if prefix_of.len() >= limits::MAX_PREFIX_COUNT { break; } } @@ -81,7 +74,7 @@ fn find_one_typo_derivations( ctx: &mut SearchContext<'_>, word_interned: Interned, is_prefix: bool, - mut visit: impl FnMut(Interned) -> Result>, + one_typo_words: &mut BTreeSet>, ) -> Result<()> { let fst = ctx.get_words_fst()?; let word = ctx.word_interner.get(word_interned).to_owned(); @@ -98,8 +91,8 @@ fn find_one_typo_derivations( 1 => { let derived_word = std::str::from_utf8(derived_word)?; let derived_word = ctx.word_interner.insert(derived_word.to_owned()); - let cf = visit(derived_word)?; - if cf.is_break() { + one_typo_words.insert(derived_word); + if one_typo_words.len() >= limits::MAX_ONE_TYPO_COUNT { break; } } @@ -116,7 +109,8 @@ fn find_one_two_typo_derivations( is_prefix: bool, fst: fst::Set>, word_interner: &mut DedupInterner, - mut visit: impl FnMut(Interned, NumberOfTypos) -> Result>, + one_typo_words: &mut BTreeSet>, + two_typo_words: &mut BTreeSet>, ) -> Result<()> { let word = word_interner.get(word_interned).to_owned(); let word = word.as_str(); @@ -130,16 +124,20 @@ fn find_one_two_typo_derivations( let mut stream = fst.search_with_state(automaton).into_stream(); while let Some((derived_word, state)) = stream.next() { + let finished_one_typo_words = one_typo_words.len() >= limits::MAX_ONE_TYPO_COUNT; + let finished_two_typo_words = two_typo_words.len() >= limits::MAX_TWO_TYPOS_COUNT; + if finished_one_typo_words && finished_two_typo_words { + // No chance we will add either one- or two-typo derivations anymore, stop iterating. + break; + } let derived_word = std::str::from_utf8(derived_word)?; // No need to intern here // in the case the typo is on the first letter, we know the number of typo // is two - if get_first(derived_word) != get_first(word) { + if get_first(derived_word) != get_first(word) && !finished_two_typo_words { let derived_word_interned = word_interner.insert(derived_word.to_owned()); - let cf = visit(derived_word_interned, NumberOfTypos::Two)?; - if cf.is_break() { - break; - } + two_typo_words.insert(derived_word_interned); + continue; } else { // Else, we know that it is the second dfa that matched and compute the // correct distance @@ -147,18 +145,18 @@ fn find_one_two_typo_derivations( match d.to_u8() { 0 => (), 1 => { - let derived_word_interned = word_interner.insert(derived_word.to_owned()); - let cf = visit(derived_word_interned, NumberOfTypos::One)?; - if cf.is_break() { - break; + if finished_one_typo_words { + continue; } + let derived_word_interned = word_interner.insert(derived_word.to_owned()); + one_typo_words.insert(derived_word_interned); } 2 => { - let derived_word_interned = word_interner.insert(derived_word.to_owned()); - let cf = visit(derived_word_interned, NumberOfTypos::Two)?; - if cf.is_break() { - break; + if finished_two_typo_words { + continue; } + let derived_word_interned = word_interner.insert(derived_word.to_owned()); + two_typo_words.insert(derived_word_interned); } _ => unreachable!("2 typos DFA produced a distance greater than 2"), } @@ -214,14 +212,7 @@ pub fn partially_initialized_term_from_word( } if is_prefix && use_prefix_db.is_none() { - find_zero_typo_prefix_derivations(ctx, word_interned, |derived_word| { - if prefix_of.len() < limits::MAX_PREFIX_COUNT { - prefix_of.insert(derived_word); - Ok(ControlFlow::Continue(())) - } else { - Ok(ControlFlow::Break(())) - } - })?; + find_zero_typo_prefix_derivations(ctx, word_interned, &mut prefix_of)?; } let synonyms = ctx.index.synonyms(ctx.txn)?; let mut synonym_word_count = 0; @@ -284,14 +275,7 @@ impl Interned { let mut one_typo_words = BTreeSet::new(); if *max_nbr_typos > 0 { - find_one_typo_derivations(ctx, original, is_prefix, |derived_word| { - if one_typo_words.len() < limits::MAX_ONE_TYPO_COUNT { - one_typo_words.insert(derived_word); - Ok(ControlFlow::Continue(())) - } else { - Ok(ControlFlow::Break(())) - } - })?; + find_one_typo_derivations(ctx, original, is_prefix, &mut one_typo_words)?; } let split_words = if allows_split_words { @@ -346,27 +330,8 @@ impl Interned { *is_prefix, ctx.index.words_fst(ctx.txn)?, &mut ctx.word_interner, - |derived_word, nbr_typos| { - if one_typo_words.len() >= limits::MAX_ONE_TYPO_COUNT - && two_typo_words.len() >= limits::MAX_TWO_TYPOS_COUNT - { - // No chance we will add either one- or two-typo derivations anymore, stop iterating. - return Ok(ControlFlow::Break(())); - } - match nbr_typos { - NumberOfTypos::One => { - if one_typo_words.len() < limits::MAX_ONE_TYPO_COUNT { - one_typo_words.insert(derived_word); - } - } - NumberOfTypos::Two => { - if two_typo_words.len() < limits::MAX_TWO_TYPOS_COUNT { - two_typo_words.insert(derived_word); - } - } - } - Ok(ControlFlow::Continue(())) - }, + &mut one_typo_words, + &mut two_typo_words, )?; } From 4d761d344400c35d371ee4221cb53e78da82e1cc Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 22 May 2025 12:19:54 +0200 Subject: [PATCH 032/292] Rename `batch_creation_complete` to `batch_strategy` --- crates/meilisearch-types/src/batch_view.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch-types/src/batch_view.rs b/crates/meilisearch-types/src/batch_view.rs index 791e1d4ec..f0a5f364b 100644 --- a/crates/meilisearch-types/src/batch_view.rs +++ b/crates/meilisearch-types/src/batch_view.rs @@ -22,7 +22,7 @@ pub struct BatchView { #[serde(with = "time::serde::rfc3339::option", default)] pub finished_at: Option, #[serde(default = "meilisearch_types::batches::default_stop_reason")] - pub batch_creation_complete: String, + pub batch_strategy: String, } impl BatchView { @@ -35,7 +35,7 @@ impl BatchView { duration: batch.finished_at.map(|finished_at| finished_at - batch.started_at), started_at: batch.started_at, finished_at: batch.finished_at, - batch_creation_complete: batch.stop_reason.clone(), + batch_strategy: batch.stop_reason.clone(), } } } From cf4798bd2bf7e58699a0517882964617b8d9f0bc Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 22 May 2025 12:20:17 +0200 Subject: [PATCH 033/292] Change batch stop reason messages to match the new `batch_strategy` API name --- crates/meilisearch-types/src/tasks.rs | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/meilisearch-types/src/tasks.rs b/crates/meilisearch-types/src/tasks.rs index 6e10f2606..24254d36e 100644 --- a/crates/meilisearch-types/src/tasks.rs +++ b/crates/meilisearch-types/src/tasks.rs @@ -746,70 +746,70 @@ impl Display for BatchStopReason { match self { BatchStopReason::Unspecified => f.write_str("unspecified"), BatchStopReason::TaskKindCannotBeBatched { kind } => { - write!(f, "a batch of tasks of type `{kind}` cannot be batched with any other type of task") + write!(f, "stopped after the last task of type `{kind}` because they cannot be batched with tasks of any other type.") } BatchStopReason::TaskCannotBeBatched { kind, id } => { - write!(f, "task with id {id} of type `{kind}` cannot be batched") + write!(f, "created batch containing only task with id {id} of type `{kind}` that cannot be batched with any other task.") } BatchStopReason::ExhaustedEnqueuedTasks => f.write_str("batched all enqueued tasks"), BatchStopReason::ExhaustedEnqueuedTasksForIndex { index } => { write!(f, "batched all enqueued tasks for index `{index}`") } BatchStopReason::ReachedTaskLimit { task_limit } => { - write!(f, "reached configured batch limit of {task_limit} tasks") + write!(f, "batched up to configured batch limit of {task_limit} tasks") } BatchStopReason::ReachedSizeLimit { size_limit, size } => write!( f, - "reached configured batch size limit of {size_limit}B with a total of {size}B" + "batched up to configured batch size limit of {size_limit}B with a total of {size}B", ), BatchStopReason::PrimaryKeyIndexMismatch { id, in_index, in_task } => { - write!(f, "primary key `{in_task}` in task with id {id} is different from the primary key of the index `{in_index}`") + write!(f, "stopped batching before task with id {id} because its primary key `{in_task}` is different from the primary key of the index `{in_index}`") } BatchStopReason::IndexCreationMismatch { id } => { - write!(f, "task with id {id} has different index creation rules as in the batch") + write!(f, "stopped batching before task with id {id} because its index creation rules differ from the ones from the batch") } BatchStopReason::PrimaryKeyMismatch { reason, id } => match reason { PrimaryKeyMismatchReason::TaskPrimaryKeyDifferFromIndexPrimaryKey { task_pk, index_pk, } => { - write!(f, "primary key `{task_pk}` in task with id {id} is different from the primary key of the index `{index_pk}`") + write!(f, "stopped batching before task with id {id} because its primary key `{task_pk}` is different from the primary key of the index `{index_pk}`") } PrimaryKeyMismatchReason::TaskPrimaryKeyDifferFromCurrentBatchPrimaryKey { task_pk, batch_pk, } => { - write!(f, "primary key `{task_pk}` in task with id {id} is different from the primary key of the batch `{batch_pk}`") + write!(f, "stopped batching before task with id {id} because its primary key `{task_pk}` is different from the primary key of the batch `{batch_pk}`") } PrimaryKeyMismatchReason::CannotInterfereWithPrimaryKeyGuessing { task_pk } => { - write!(f, "task with id {id} is setting the `{task_pk}` primary key but cannot interfere with primary key guessing of the batch") + write!(f, "stopped batching before task with id {id} because it is setting the `{task_pk}` primary key and it would interfere with primary key guessing of the batch") } }, BatchStopReason::IndexDeletion { id } => { - write!(f, "task with id {id} deletes the index") + write!(f, "stopped after task with id {id} because it deletes the index") } BatchStopReason::DocumentOperationWithSettings { id } => { write!( f, - "task with id {id} is a settings change in a batch of document operations" + "stopped before task with id {id} because it is a settings change which cannot be batched with document operations" ) } BatchStopReason::DocumentOperationWithDeletionByFilter { id } => { write!( f, - "task with id {id} is a deletion by filter in a batch of document operations" + "stopped before task with id {id} because it is a deletion by filter which cannot be batched with document operations" ) } BatchStopReason::DeletionByFilterWithDocumentOperation { id } => { write!( f, - "task with id {id} is a document operation in a batch of deletions by filter" + "stopped before task with id {id} because it is a document operation which cannot be batched with deletions by filter" ) } BatchStopReason::SettingsWithDocumentOperation { id } => { write!( f, - "task with id {id} is a document operation in a batch of settings changes" + "stopped before task with id {id} because it is a document operation which cannot be batched with settings changes" ) } } From c204a7bb12d04f47877720c5a4f856245172d521 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 22 May 2025 12:39:37 +0200 Subject: [PATCH 034/292] Update snapshots --- .../index-scheduler/src/queue/batches_test.rs | 2 +- .../query_batches_canceled_by/start.snap | 4 +- .../processed_all_tasks.snap | 6 +-- .../after-advancing-a-bit.snap | 4 +- .../query_batches_simple/end.snap | 6 +-- .../after-processing-everything.snap | 8 +-- .../query_tasks_canceled_by/start.snap | 4 +- .../processed_all_tasks.snap | 6 +-- .../tasks_test.rs/query_tasks_simple/end.snap | 6 +-- .../cancel_processed.snap | 2 +- .../cancel_mix_of_tasks/cancel_processed.snap | 2 +- .../cancel_processed.snap | 2 +- .../cancel_registered.snap | 2 +- .../cancel_processed.snap | 2 +- .../cancel_processed.snap | 2 +- .../all_tasks_processed.snap | 6 +-- .../before_index_creation.snap | 2 +- .../both_task_succeeded.snap | 4 +- .../2.snap | 2 +- .../after_batch_creation.snap | 2 +- .../registered_the_second_task.snap | 2 +- .../registered_the_third_task.snap | 2 +- .../processed_the_first_task.snap | 2 +- .../processed_the_second_task.snap | 4 +- .../processed_the_third_task.snap | 6 +-- .../first.snap | 2 +- .../fourth.snap | 6 +-- .../second.snap | 4 +- .../third.snap | 6 +-- .../test.rs/swap_indexes/create_a.snap | 2 +- .../test.rs/swap_indexes/create_b.snap | 4 +- .../test.rs/swap_indexes/create_c.snap | 6 +-- .../test.rs/swap_indexes/create_d.snap | 8 +-- .../swap_indexes/first_swap_processed.snap | 10 ++-- .../swap_indexes/first_swap_registered.snap | 8 +-- .../swap_indexes/second_swap_processed.snap | 12 ++--- .../third_empty_swap_processed.snap | 14 +++--- .../swap_indexes/two_swaps_registered.snap | 8 +-- .../after_the_index_creation.snap | 8 +-- .../first_swap_failed.snap | 10 ++-- .../initial_tasks_processed.snap | 8 +-- .../task_deletion_processed.snap | 2 +- .../task_deletion_processed.snap | 2 +- .../task_deletion_done.snap | 2 +- .../task_deletion_processing.snap | 2 +- .../after_restart.snap | 2 +- .../after_failing_the_deletion.snap | 2 +- .../after_last_successful_addition.snap | 2 +- .../after_processing_the_10_tasks.snap | 2 +- .../after_registering_the_10_tasks.snap | 2 +- .../processed_the_first_task.snap | 2 +- .../after_registering_the_10_tasks.snap | 2 +- .../all_tasks_processed.snap | 20 ++++---- .../five_tasks_processed.snap | 12 ++--- .../processed_the_first_task.snap | 2 +- .../all_tasks_processed.snap | 18 +++---- .../five_tasks_processed.snap | 10 ++-- .../all_tasks_processed.snap | 2 +- .../only_first_task_failed.snap | 2 +- .../after_registering_the_10_tasks.snap | 2 +- .../all_tasks_processed.snap | 2 +- .../processed_the_first_task.snap | 2 +- .../fifth_task_succeeds.snap | 6 +-- .../first_and_second_task_fails.snap | 2 +- .../fourth_task_fails.snap | 6 +-- .../third_task_succeeds.snap | 4 +- .../only_first_task_succeed.snap | 2 +- .../second_task_fails.snap | 4 +- .../third_task_fails.snap | 6 +-- .../only_first_task_succeed.snap | 2 +- .../second_and_third_tasks_fails.snap | 4 +- .../all_other_tasks_succeeds.snap | 4 +- .../first_task_fails.snap | 2 +- .../second_task_fails.snap | 4 +- .../all_other_tasks_succeeds.snap | 4 +- .../first_task_succeed.snap | 2 +- .../second_task_fails.snap | 4 +- .../all_tasks_processed.snap | 18 +++---- .../five_tasks_processed.snap | 10 ++-- .../all_tasks_processed.snap | 18 +++---- .../five_tasks_processed.snap | 10 ++-- .../after_adding_the_documents.snap | 2 +- .../after_adding_the_settings.snap | 2 +- .../after_removing_the_documents.snap | 2 +- .../registered_the_document_deletions.snap | 2 +- .../index_creation_failed.snap | 2 +- .../index_creation_failed.snap | 2 +- .../after_processing_everything.snap | 10 ++-- .../after_removing_the_upgrade_tasks.snap | 10 ++-- .../upgrade_failure/upgrade_task_failed.snap | 2 +- .../upgrade_task_failed_again.snap | 2 +- .../upgrade_task_succeeded.snap | 2 +- crates/meilisearch/tests/batches/mod.rs | 42 ++++++++-------- .../batches.snap | 6 +-- ...rEnqueuedAt_equal_2025-01-16T16_47_41.snap | 40 +++++++-------- ...rFinishedAt_equal_2025-01-16T16_47_41.snap | 40 +++++++-------- ...erStartedAt_equal_2025-01-16T16_47_41.snap | 40 +++++++-------- .../batches_filter_batchUids_equal_10.snap | 2 +- ...eEnqueuedAt_equal_2025-01-16T16_47_41.snap | 4 +- ...eFinishedAt_equal_2025-01-16T16_47_41.snap | 4 +- ...reStartedAt_equal_2025-01-16T16_47_41.snap | 4 +- .../batches_filter_canceledBy_equal_19.snap | 2 +- ...atches_filter_statuses_equal_canceled.snap | 2 +- .../batches_filter_uids_equal_10.snap | 2 +- ...ue_once_everything_has_been_processed.snap | 50 +++++++++---------- 105 files changed, 344 insertions(+), 344 deletions(-) diff --git a/crates/index-scheduler/src/queue/batches_test.rs b/crates/index-scheduler/src/queue/batches_test.rs index 73567ef78..782acb4b1 100644 --- a/crates/index-scheduler/src/queue/batches_test.rs +++ b/crates/index-scheduler/src/queue/batches_test.rs @@ -127,7 +127,7 @@ fn query_batches_simple() { "startedAt": "1970-01-01T00:00:00Z", "finishedAt": null, "enqueuedAt": null, - "stopReason": "task with id 0 of type `indexCreation` cannot be batched" + "stopReason": "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task." } "###); diff --git a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_canceled_by/start.snap b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_canceled_by/start.snap index 2dafc2719..48d1ccaab 100644 --- a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_canceled_by/start.snap +++ b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_canceled_by/start.snap @@ -48,8 +48,8 @@ catto: { number_of_documents: 0, field_distribution: {} } [timestamp] [1,2,3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"sheep","matchedTasks":3,"canceledTasks":2,"originalFilter":"test_query","swaps":[{"indexes":["catto","doggo"]}]}, stats: {"totalNbTasks":3,"status":{"succeeded":1,"canceled":2},"types":{"indexCreation":1,"indexSwap":1,"taskCancelation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 3 of type `taskCancelation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"sheep","matchedTasks":3,"canceledTasks":2,"originalFilter":"test_query","swaps":[{"indexes":["catto","doggo"]}]}, stats: {"totalNbTasks":3,"status":{"succeeded":1,"canceled":2},"types":{"indexCreation":1,"indexSwap":1,"taskCancelation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 3 of type `taskCancelation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_from_and_limit/processed_all_tasks.snap b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_from_and_limit/processed_all_tasks.snap index 56fed6a13..4c54de49a 100644 --- a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_from_and_limit/processed_all_tasks.snap +++ b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_from_and_limit/processed_all_tasks.snap @@ -47,9 +47,9 @@ whalo: { number_of_documents: 0, field_distribution: {} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"plankton"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"his_own_vomit"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"plankton"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"his_own_vomit"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/after-advancing-a-bit.snap b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/after-advancing-a-bit.snap index 7ef7b4905..7ce0d3ca3 100644 --- a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/after-advancing-a-bit.snap +++ b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/after-advancing-a-bit.snap @@ -4,7 +4,7 @@ source: crates/index-scheduler/src/queue/batches_test.rs ### Autobatching Enabled = true ### Processing batch Some(1): [1,] -{uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } +{uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### All Tasks: 0 {uid: 0, batch_uid: 0, status: succeeded, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} @@ -42,7 +42,7 @@ catto: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/end.snap b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/end.snap index fef01fe95..603544991 100644 --- a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/end.snap +++ b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_simple/end.snap @@ -47,9 +47,9 @@ doggo: { number_of_documents: 0, field_distribution: {} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"fish"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"fish"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_special_rules/after-processing-everything.snap b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_special_rules/after-processing-everything.snap index 87c841ba9..84d6c7878 100644 --- a/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_special_rules/after-processing-everything.snap +++ b/crates/index-scheduler/src/queue/snapshots/batches_test.rs/query_batches_special_rules/after-processing-everything.snap @@ -52,10 +52,10 @@ doggo: { number_of_documents: 0, field_distribution: {} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"swaps":[{"indexes":["catto","doggo"]}]}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 2 of type `indexSwap` cannot be batched", } -3 {uid: 3, details: {"swaps":[{"indexes":["catto","whalo"]}]}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 3 of type `indexSwap` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"swaps":[{"indexes":["catto","doggo"]}]}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 2 of type `indexSwap` that cannot be batched with any other task.", } +3 {uid: 3, details: {"swaps":[{"indexes":["catto","whalo"]}]}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 3 of type `indexSwap` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_canceled_by/start.snap b/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_canceled_by/start.snap index 292382fac..e3c26b2b3 100644 --- a/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_canceled_by/start.snap +++ b/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_canceled_by/start.snap @@ -48,8 +48,8 @@ catto: { number_of_documents: 0, field_distribution: {} } [timestamp] [1,2,3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"sheep","matchedTasks":3,"canceledTasks":2,"originalFilter":"test_query","swaps":[{"indexes":["catto","doggo"]}]}, stats: {"totalNbTasks":3,"status":{"succeeded":1,"canceled":2},"types":{"indexCreation":1,"indexSwap":1,"taskCancelation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 3 of type `taskCancelation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"sheep","matchedTasks":3,"canceledTasks":2,"originalFilter":"test_query","swaps":[{"indexes":["catto","doggo"]}]}, stats: {"totalNbTasks":3,"status":{"succeeded":1,"canceled":2},"types":{"indexCreation":1,"indexSwap":1,"taskCancelation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 3 of type `taskCancelation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_from_and_limit/processed_all_tasks.snap b/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_from_and_limit/processed_all_tasks.snap index 18358c998..4475c71fc 100644 --- a/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_from_and_limit/processed_all_tasks.snap +++ b/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_from_and_limit/processed_all_tasks.snap @@ -47,9 +47,9 @@ whalo: { number_of_documents: 0, field_distribution: {} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"plankton"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"his_own_vomit"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"plankton"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"his_own_vomit"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_simple/end.snap b/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_simple/end.snap index dd31e587c..4ac6201a6 100644 --- a/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_simple/end.snap +++ b/crates/index-scheduler/src/queue/snapshots/tasks_test.rs/query_tasks_simple/end.snap @@ -47,9 +47,9 @@ doggo: { number_of_documents: 0, field_distribution: {} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"fish"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"sheep"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"fish"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"whalo":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_enqueued_task/cancel_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_enqueued_task/cancel_processed.snap index 3a31c50c9..168b01b29 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_enqueued_task/cancel_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_enqueued_task/cancel_processed.snap @@ -39,7 +39,7 @@ catto [0,] [timestamp] [0,1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0,"matchedTasks":1,"canceledTasks":1,"originalFilter":"test_query"}, stats: {"totalNbTasks":2,"status":{"succeeded":1,"canceled":1},"types":{"documentAdditionOrUpdate":1,"taskCancelation":1},"indexUids":{"catto":1}}, stop reason: "task with id 1 of type `taskCancelation` cannot be batched", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0,"matchedTasks":1,"canceledTasks":1,"originalFilter":"test_query"}, stats: {"totalNbTasks":2,"status":{"succeeded":1,"canceled":1},"types":{"documentAdditionOrUpdate":1,"taskCancelation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 1 of type `taskCancelation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_mix_of_tasks/cancel_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_mix_of_tasks/cancel_processed.snap index fa6d17476..4d41a9807 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_mix_of_tasks/cancel_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_mix_of_tasks/cancel_processed.snap @@ -50,7 +50,7 @@ catto: { number_of_documents: 1, field_distribution: {"id": 1} } ---------------------------------------------------------------------- ### All Batches: 0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"catto":1}}, stop reason: "batched all enqueued tasks for index `catto`", } -1 {uid: 1, details: {"receivedDocuments":2,"indexedDocuments":0,"matchedTasks":3,"canceledTasks":2,"originalFilter":"test_query"}, stats: {"totalNbTasks":3,"status":{"succeeded":1,"canceled":2},"types":{"documentAdditionOrUpdate":2,"taskCancelation":1},"indexUids":{"beavero":1,"wolfo":1}}, stop reason: "task with id 3 of type `taskCancelation` cannot be batched", } +1 {uid: 1, details: {"receivedDocuments":2,"indexedDocuments":0,"matchedTasks":3,"canceledTasks":2,"originalFilter":"test_query"}, stats: {"totalNbTasks":3,"status":{"succeeded":1,"canceled":2},"types":{"documentAdditionOrUpdate":2,"taskCancelation":1},"indexUids":{"beavero":1,"wolfo":1}}, stop reason: "created batch containing only task with id 3 of type `taskCancelation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_processed.snap index 9ee3f9816..cbf0b6114 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_processed.snap @@ -38,7 +38,7 @@ canceled [0,] [timestamp] [0,1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"matchedTasks":1,"canceledTasks":1,"originalFilter":"cancel dump"}, stats: {"totalNbTasks":2,"status":{"succeeded":1,"canceled":1},"types":{"taskCancelation":1,"dumpCreation":1},"indexUids":{}}, stop reason: "task with id 1 of type `taskCancelation` cannot be batched", } +0 {uid: 0, details: {"matchedTasks":1,"canceledTasks":1,"originalFilter":"cancel dump"}, stats: {"totalNbTasks":2,"status":{"succeeded":1,"canceled":1},"types":{"taskCancelation":1,"dumpCreation":1},"indexUids":{}}, stop reason: "created batch containing only task with id 1 of type `taskCancelation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_registered.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_registered.snap index 9ca235e15..94efa13ab 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_registered.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_dump/cancel_registered.snap @@ -4,7 +4,7 @@ source: crates/index-scheduler/src/scheduler/test.rs ### Autobatching Enabled = true ### Processing batch Some(0): [0,] -{uid: 0, details: {"dumpUid":null}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"dumpCreation":1},"indexUids":{}}, stop reason: "task with id 0 of type `dumpCreation` cannot be batched", } +{uid: 0, details: {"dumpUid":null}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"dumpCreation":1},"indexUids":{}}, stop reason: "created batch containing only task with id 0 of type `dumpCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### All Tasks: 0 {uid: 0, status: enqueued, details: { dump_uid: None }, kind: DumpCreation { keys: [], instance_uid: None }} diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_task/cancel_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_task/cancel_processed.snap index 1111edd98..362cd018e 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_task/cancel_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_processing_task/cancel_processed.snap @@ -40,7 +40,7 @@ catto: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0,"matchedTasks":1,"canceledTasks":1,"originalFilter":"test_query"}, stats: {"totalNbTasks":2,"status":{"succeeded":1,"canceled":1},"types":{"documentAdditionOrUpdate":1,"taskCancelation":1},"indexUids":{"catto":1}}, stop reason: "task with id 1 of type `taskCancelation` cannot be batched", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0,"matchedTasks":1,"canceledTasks":1,"originalFilter":"test_query"}, stats: {"totalNbTasks":2,"status":{"succeeded":1,"canceled":1},"types":{"documentAdditionOrUpdate":1,"taskCancelation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 1 of type `taskCancelation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_succeeded_task/cancel_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_succeeded_task/cancel_processed.snap index d4dc3452f..91291fe62 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_succeeded_task/cancel_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/cancel_succeeded_task/cancel_processed.snap @@ -41,7 +41,7 @@ catto: { number_of_documents: 1, field_distribution: {"id": 1} } ---------------------------------------------------------------------- ### All Batches: 0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"catto":1}}, stop reason: "batched all enqueued tasks", } -1 {uid: 1, details: {"matchedTasks":1,"canceledTasks":0,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskCancelation":1},"indexUids":{}}, stop reason: "task with id 1 of type `taskCancelation` cannot be batched", } +1 {uid: 1, details: {"matchedTasks":1,"canceledTasks":0,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskCancelation":1},"indexUids":{}}, stop reason: "created batch containing only task with id 1 of type `taskCancelation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/do_not_batch_task_of_different_indexes/all_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/do_not_batch_task_of_different_indexes/all_tasks_processed.snap index ad3fb246f..ed6e75a3d 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/do_not_batch_task_of_different_indexes/all_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/do_not_batch_task_of_different_indexes/all_tasks_processed.snap @@ -60,9 +60,9 @@ girafos: { number_of_documents: 0, field_distribution: {} } [timestamp] [5,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"cattos":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"girafos":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"cattos":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"girafos":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } 3 {uid: 3, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks for index `doggos`", } 4 {uid: 4, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"cattos":1}}, stop reason: "batched all enqueued tasks for index `cattos`", } 5 {uid: 5, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"girafos":1}}, stop reason: "batched all enqueued tasks", } diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/before_index_creation.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/before_index_creation.snap index 8a8d58c99..f98e5d308 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/before_index_creation.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/before_index_creation.snap @@ -41,7 +41,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/both_task_succeeded.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/both_task_succeeded.snap index 6f13e4492..ae1139c0c 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/both_task_succeeded.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion/both_task_succeeded.snap @@ -42,8 +42,8 @@ doggos [0,1,2,] [timestamp] [1,2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0,"deletedDocuments":0}, stats: {"totalNbTasks":2,"status":{"succeeded":2},"types":{"documentAdditionOrUpdate":1,"indexDeletion":1},"indexUids":{"doggos":2}}, stop reason: "task with id 2 deletes the index", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0,"deletedDocuments":0}, stats: {"totalNbTasks":2,"status":{"succeeded":2},"types":{"documentAdditionOrUpdate":1,"indexDeletion":1},"indexUids":{"doggos":2}}, stop reason: "stopped after task with id 2 because it deletes the index", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion_on_unexisting_index/2.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion_on_unexisting_index/2.snap index 93dbc831e..a35727f22 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion_on_unexisting_index/2.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/document_addition_and_index_deletion_on_unexisting_index/2.snap @@ -37,7 +37,7 @@ doggos [0,1,] [timestamp] [0,1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0,"deletedDocuments":0}, stats: {"totalNbTasks":2,"status":{"succeeded":2},"types":{"documentAdditionOrUpdate":1,"indexDeletion":1},"indexUids":{"doggos":2}}, stop reason: "task with id 1 deletes the index", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0,"deletedDocuments":0}, stats: {"totalNbTasks":2,"status":{"succeeded":2},"types":{"documentAdditionOrUpdate":1,"indexDeletion":1},"indexUids":{"doggos":2}}, stop reason: "stopped after task with id 1 because it deletes the index", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/after_batch_creation.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/after_batch_creation.snap index e9b3e0285..17b69061a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/after_batch_creation.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/after_batch_creation.snap @@ -4,7 +4,7 @@ source: crates/index-scheduler/src/scheduler/test.rs ### Autobatching Enabled = true ### Processing batch Some(0): [0,] -{uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"index_a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +{uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"index_a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### All Tasks: 0 {uid: 0, status: enqueued, details: { primary_key: Some("id") }, kind: IndexCreation { index_uid: "index_a", primary_key: Some("id") }} diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_second_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_second_task.snap index 24e885c46..c8a407554 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_second_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_second_task.snap @@ -4,7 +4,7 @@ source: crates/index-scheduler/src/scheduler/test.rs ### Autobatching Enabled = true ### Processing batch Some(0): [0,] -{uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"index_a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +{uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"index_a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### All Tasks: 0 {uid: 0, status: enqueued, details: { primary_key: Some("id") }, kind: IndexCreation { index_uid: "index_a", primary_key: Some("id") }} diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_third_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_third_task.snap index 6ef7b5a38..0cae69a70 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_third_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/insert_task_while_another_task_is_processing/registered_the_third_task.snap @@ -4,7 +4,7 @@ source: crates/index-scheduler/src/scheduler/test.rs ### Autobatching Enabled = true ### Processing batch Some(0): [0,] -{uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"index_a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +{uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"indexCreation":1},"indexUids":{"index_a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### All Tasks: 0 {uid: 0, status: enqueued, details: { primary_key: Some("id") }, kind: IndexCreation { index_uid: "index_a", primary_key: Some("id") }} diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_first_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_first_task.snap index ae64e6fbd..c5e3e66c8 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_first_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_first_task.snap @@ -41,7 +41,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_second_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_second_task.snap index 8b099633a..8da1b6ca8 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_second_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_second_task.snap @@ -44,8 +44,8 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"cattos":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"cattos":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_third_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_third_task.snap index e809b28cb..8ee0bfcef 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_third_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_inserted_without_new_signal/processed_the_third_task.snap @@ -45,9 +45,9 @@ cattos: { number_of_documents: 0, field_distribution: {} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"cattos":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexDeletion":1},"indexUids":{"doggos":1}}, stop reason: "task with id 2 deletes the index", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"cattos":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexDeletion":1},"indexUids":{"doggos":1}}, stop reason: "stopped after task with id 2 because it deletes the index", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/first.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/first.snap index bf183802b..a7215f32c 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/first.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/first.snap @@ -42,7 +42,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/fourth.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/fourth.snap index 03f29dd0e..1c14b091f 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/fourth.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/fourth.snap @@ -48,9 +48,9 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } 3 {uid: 3, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/second.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/second.snap index 2ff261d43..da91440ab 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/second.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/second.snap @@ -44,8 +44,8 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/third.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/third.snap index c9663ca65..95bc1f7f5 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/third.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/process_tasks_without_autobatching/third.snap @@ -46,9 +46,9 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_a.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_a.snap index bc6e9b8b4..4878bbe28 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_a.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_a.snap @@ -44,7 +44,7 @@ a: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_b.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_b.snap index b6af0c6a6..5a851f373 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_b.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_b.snap @@ -47,8 +47,8 @@ b: { number_of_documents: 0, field_distribution: {} } [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_c.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_c.snap index d3f714ace..dad7609d2 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_c.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_c.snap @@ -50,9 +50,9 @@ c: { number_of_documents: 0, field_distribution: {} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_d.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_d.snap index 15a1cf2ae..ee0a12692 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_d.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/create_d.snap @@ -53,10 +53,10 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_processed.snap index 6b9899418..39d1b3339 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_processed.snap @@ -60,11 +60,11 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } -4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","d"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 4 of type `indexSwap` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } +4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","d"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 4 of type `indexSwap` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_registered.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_registered.snap index 3091b061b..5d292fe21 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_registered.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/first_swap_registered.snap @@ -56,10 +56,10 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/second_swap_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/second_swap_processed.snap index 20e9d1076..9327015c4 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/second_swap_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/second_swap_processed.snap @@ -62,12 +62,12 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [5,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } -4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","d"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 4 of type `indexSwap` cannot be batched", } -5 {uid: 5, details: {"swaps":[{"indexes":["a","c"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 5 of type `indexSwap` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } +4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","d"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 4 of type `indexSwap` that cannot be batched with any other task.", } +5 {uid: 5, details: {"swaps":[{"indexes":["a","c"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 5 of type `indexSwap` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/third_empty_swap_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/third_empty_swap_processed.snap index 27e42139c..f85735397 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/third_empty_swap_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/third_empty_swap_processed.snap @@ -66,13 +66,13 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [6,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } -4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","d"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 4 of type `indexSwap` cannot be batched", } -5 {uid: 5, details: {"swaps":[{"indexes":["a","c"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 5 of type `indexSwap` cannot be batched", } -6 {uid: 6, details: {"swaps":[]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 6 of type `indexSwap` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } +4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","d"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 4 of type `indexSwap` that cannot be batched with any other task.", } +5 {uid: 5, details: {"swaps":[{"indexes":["a","c"]}]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 5 of type `indexSwap` that cannot be batched with any other task.", } +6 {uid: 6, details: {"swaps":[]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 6 of type `indexSwap` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/two_swaps_registered.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/two_swaps_registered.snap index aa8fb4dc1..46d70dceb 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/two_swaps_registered.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes/two_swaps_registered.snap @@ -58,10 +58,10 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/after_the_index_creation.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/after_the_index_creation.snap index 15a1cf2ae..ee0a12692 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/after_the_index_creation.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/after_the_index_creation.snap @@ -53,10 +53,10 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/first_swap_failed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/first_swap_failed.snap index 1e4a4a6f3..da9340f3b 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/first_swap_failed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/first_swap_failed.snap @@ -61,11 +61,11 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } -4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","e"]},{"indexes":["d","f"]}]}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "task with id 4 of type `indexSwap` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } +4 {uid: 4, details: {"swaps":[{"indexes":["a","b"]},{"indexes":["c","e"]},{"indexes":["d","f"]}]}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexSwap":1},"indexUids":{}}, stop reason: "created batch containing only task with id 4 of type `indexSwap` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/initial_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/initial_tasks_processed.snap index 15a1cf2ae..ee0a12692 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/initial_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/swap_indexes_errors/initial_tasks_processed.snap @@ -53,10 +53,10 @@ d: { number_of_documents: 0, field_distribution: {} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"a":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"b":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"c":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"id"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"d":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_delete_same_task_twice/task_deletion_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_delete_same_task_twice/task_deletion_processed.snap index d5143a4a3..f6182e515 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_delete_same_task_twice/task_deletion_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_delete_same_task_twice/task_deletion_processed.snap @@ -40,7 +40,7 @@ catto: { number_of_documents: 1, field_distribution: {"id": 1} } [timestamp] [2,3,] ---------------------------------------------------------------------- ### All Batches: -1 {uid: 1, details: {"matchedTasks":2,"deletedTasks":1,"originalFilter":"test_query&test_query"}, stats: {"totalNbTasks":2,"status":{"succeeded":2},"types":{"taskDeletion":2},"indexUids":{}}, stop reason: "a batch of tasks of type `taskDeletion` cannot be batched with any other type of task", } +1 {uid: 1, details: {"matchedTasks":2,"deletedTasks":1,"originalFilter":"test_query&test_query"}, stats: {"totalNbTasks":2,"status":{"succeeded":2},"types":{"taskDeletion":2},"indexUids":{}}, stop reason: "stopped after the last task of type `taskDeletion` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 1 [2,3,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_deleteable/task_deletion_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_deleteable/task_deletion_processed.snap index 414d2e488..cae9c296b 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_deleteable/task_deletion_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_deleteable/task_deletion_processed.snap @@ -38,7 +38,7 @@ catto: { number_of_documents: 1, field_distribution: {"id": 1} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -1 {uid: 1, details: {"matchedTasks":1,"deletedTasks":1,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "a batch of tasks of type `taskDeletion` cannot be batched with any other type of task", } +1 {uid: 1, details: {"matchedTasks":1,"deletedTasks":1,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "stopped after the last task of type `taskDeletion` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 1 [2,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_done.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_done.snap index 0a24f1993..3b89fe1e7 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_done.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_done.snap @@ -43,7 +43,7 @@ doggo [2,] [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"matchedTasks":2,"deletedTasks":0,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "a batch of tasks of type `taskDeletion` cannot be batched with any other type of task", } +0 {uid: 0, details: {"matchedTasks":2,"deletedTasks":0,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "stopped after the last task of type `taskDeletion` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [3,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_processing.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_processing.snap index 33b65bfe4..d8abc1314 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_processing.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/task_deletion_undeleteable/task_deletion_processing.snap @@ -4,7 +4,7 @@ source: crates/index-scheduler/src/scheduler/test.rs ### Autobatching Enabled = true ### Processing batch Some(0): [3,] -{uid: 0, details: {"matchedTasks":2,"deletedTasks":null,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "a batch of tasks of type `taskDeletion` cannot be batched with any other type of task", } +{uid: 0, details: {"matchedTasks":2,"deletedTasks":null,"originalFilter":"test_query"}, stats: {"totalNbTasks":1,"status":{"processing":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "stopped after the last task of type `taskDeletion` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### All Tasks: 0 {uid: 0, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap index d955557c7..1dde1a394 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_scheduler_doesnt_run_with_zero_batched_tasks/after_restart.snap @@ -35,7 +35,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_failing_the_deletion.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_failing_the_deletion.snap index b83fa60f1..7ad5046e1 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_failing_the_deletion.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_failing_the_deletion.snap @@ -37,7 +37,7 @@ doggos [0,1,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"providedIds":2,"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 has different index creation rules as in the batch", } +0 {uid: 0, details: {"providedIds":2,"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its index creation rules differ from the ones from the batch", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_last_successful_addition.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_last_successful_addition.snap index f97b536f0..9d94cffaf 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_last_successful_addition.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/document_deletion_and_document_addition/after_last_successful_addition.snap @@ -41,7 +41,7 @@ doggos: { number_of_documents: 3, field_distribution: {"catto": 1, "doggo": 2, " [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"providedIds":2,"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 has different index creation rules as in the batch", } +0 {uid: 0, details: {"providedIds":2,"deletedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentDeletion":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its index creation rules differ from the ones from the batch", } 1 {uid: 1, details: {"receivedDocuments":3,"indexedDocuments":3}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_processing_the_10_tasks.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_processing_the_10_tasks.snap index 0f9d93068..f8caaa995 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_processing_the_10_tasks.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_processing_the_10_tasks.snap @@ -58,7 +58,7 @@ doggos: { number_of_documents: 10, field_distribution: {"doggo": 10, "id": 10} } [timestamp] [1,2,3,4,5,6,7,8,9,10,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } 1 {uid: 1, details: {"receivedDocuments":10,"indexedDocuments":10}, stats: {"totalNbTasks":10,"status":{"succeeded":10},"types":{"documentAdditionOrUpdate":10},"indexUids":{"doggos":10}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_registering_the_10_tasks.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_registering_the_10_tasks.snap index df75e6cf0..d987d66c0 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_registering_the_10_tasks.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/after_registering_the_10_tasks.snap @@ -56,7 +56,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/processed_the_first_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/processed_the_first_task.snap index f8bcf6646..d1369460f 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/processed_the_first_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index/processed_the_first_task.snap @@ -35,7 +35,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/after_registering_the_10_tasks.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/after_registering_the_10_tasks.snap index 091346cc0..136777fcf 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/after_registering_the_10_tasks.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/after_registering_the_10_tasks.snap @@ -56,7 +56,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/all_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/all_tasks_processed.snap index 8c30b10fa..0b4fc96b5 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/all_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/all_tasks_processed.snap @@ -76,16 +76,16 @@ doggos: { number_of_documents: 10, field_distribution: {"doggo": 10, "id": 10} } [timestamp] [10,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -9 {uid: 9, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +9 {uid: 9, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } 10 {uid: 10, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/five_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/five_tasks_processed.snap index 34e09660d..d938ca288 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/five_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/five_tasks_processed.snap @@ -66,12 +66,12 @@ doggos: { number_of_documents: 5, field_distribution: {"doggo": 5, "id": 5} } [timestamp] [5,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/processed_the_first_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/processed_the_first_task.snap index 38081c7d7..2d936ba68 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/processed_the_first_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_with_index_without_autobatching/processed_the_first_task.snap @@ -35,7 +35,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/all_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/all_tasks_processed.snap index 2b5a673d6..fc16063e7 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/all_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/all_tasks_processed.snap @@ -70,15 +70,15 @@ doggos [0,1,2,3,4,5,6,7,8,9,] [timestamp] [9,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } 9 {uid: 9, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/five_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/five_tasks_processed.snap index e2ecfcdab..19d45a0d3 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/five_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_cant_create_index_without_index_without_autobatching/five_tasks_processed.snap @@ -60,11 +60,11 @@ doggos [0,1,2,3,4,5,6,7,8,9,] [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/all_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/all_tasks_processed.snap index db8192fc6..d007e673a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/all_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/all_tasks_processed.snap @@ -56,7 +56,7 @@ doggos: { number_of_documents: 9, field_distribution: {"doggo": 9, "id": 9} } [timestamp] [1,2,3,4,5,6,7,8,9,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 has different index creation rules as in the batch", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its index creation rules differ from the ones from the batch", } 1 {uid: 1, details: {"receivedDocuments":9,"indexedDocuments":9}, stats: {"totalNbTasks":9,"status":{"succeeded":9},"types":{"documentAdditionOrUpdate":9},"indexUids":{"doggos":9}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/only_first_task_failed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/only_first_task_failed.snap index 2e23d7cbf..57f7be034 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/only_first_task_failed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_right_without_index_starts_with_cant_create/only_first_task_failed.snap @@ -52,7 +52,7 @@ doggos [0,1,2,3,4,5,6,7,8,9,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 has different index creation rules as in the batch", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its index creation rules differ from the ones from the batch", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/after_registering_the_10_tasks.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/after_registering_the_10_tasks.snap index 5cf951bfd..6add8a2a5 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/after_registering_the_10_tasks.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/after_registering_the_10_tasks.snap @@ -56,7 +56,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/all_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/all_tasks_processed.snap index 274d93f7e..197ed0679 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/all_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/all_tasks_processed.snap @@ -58,7 +58,7 @@ doggos: { number_of_documents: 10, field_distribution: {"doggo": 10, "id": 10} } [timestamp] [1,2,3,4,5,6,7,8,9,10,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } 1 {uid: 1, details: {"receivedDocuments":10,"indexedDocuments":10}, stats: {"totalNbTasks":10,"status":{"succeeded":10},"types":{"documentAdditionOrUpdate":10},"indexUids":{"doggos":10}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/processed_the_first_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/processed_the_first_task.snap index f8bcf6646..d1369460f 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/processed_the_first_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_mixed_rights_with_index/processed_the_first_task.snap @@ -35,7 +35,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggos":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fifth_task_succeeds.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fifth_task_succeeds.snap index d8090b209..f0807b5fd 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fifth_task_succeeds.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fifth_task_succeeds.snap @@ -50,9 +50,9 @@ doggos: { number_of_documents: 2, field_distribution: {"doggo": 2, "id": 2} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "primary key `id` in task with id 2 is different from the primary key of the batch `bork`", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 3 is different from the primary key of the batch `id`", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 3 is different from the primary key of the index `id`", } +0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "stopped batching before task with id 2 because its primary key `id` is different from the primary key of the batch `bork`", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 3 because its primary key `bork` is different from the primary key of the batch `id`", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 3 because its primary key `bork` is different from the primary key of the index `id`", } 3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/first_and_second_task_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/first_and_second_task_fails.snap index 9707adba1..17a6ce83e 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/first_and_second_task_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/first_and_second_task_fails.snap @@ -43,7 +43,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "primary key `id` in task with id 2 is different from the primary key of the batch `bork`", } +0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "stopped batching before task with id 2 because its primary key `id` is different from the primary key of the batch `bork`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fourth_task_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fourth_task_fails.snap index df012bc42..7f5c4bfc7 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fourth_task_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/fourth_task_fails.snap @@ -48,9 +48,9 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [3,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "primary key `id` in task with id 2 is different from the primary key of the batch `bork`", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 3 is different from the primary key of the batch `id`", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 3 is different from the primary key of the index `id`", } +0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "stopped batching before task with id 2 because its primary key `id` is different from the primary key of the batch `bork`", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 3 because its primary key `bork` is different from the primary key of the batch `id`", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 3 because its primary key `bork` is different from the primary key of the index `id`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/third_task_succeeds.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/third_task_succeeds.snap index aae598a0e..cfe41f168 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/third_task_succeeds.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_bad_primary_key/third_task_succeeds.snap @@ -46,8 +46,8 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "primary key `id` in task with id 2 is different from the primary key of the batch `bork`", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 3 is different from the primary key of the batch `id`", } +0 {uid: 0, details: {"receivedDocuments":2,"indexedDocuments":0}, stats: {"totalNbTasks":2,"status":{"failed":2},"types":{"documentAdditionOrUpdate":2},"indexUids":{"doggos":2}}, stop reason: "stopped batching before task with id 2 because its primary key `id` is different from the primary key of the batch `bork`", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 3 because its primary key `bork` is different from the primary key of the batch `id`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/only_first_task_succeed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/only_first_task_succeed.snap index 4c36fcd06..0f7aac17a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/only_first_task_succeed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/only_first_task_succeed.snap @@ -39,7 +39,7 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the batch `id`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the batch `id`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/second_task_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/second_task_fails.snap index f7033bee5..2a714664f 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/second_task_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/second_task_fails.snap @@ -42,8 +42,8 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the batch `id`", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the index `id`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the batch `id`", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the index `id`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/third_task_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/third_task_fails.snap index c3360c7cf..3c0cb0add 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/third_task_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key/third_task_fails.snap @@ -44,9 +44,9 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [2,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the batch `id`", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the index `id`", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bloup` in task with id 2 is different from the primary key of the index `id`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the batch `id`", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the index `id`", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 2 because its primary key `bloup` is different from the primary key of the index `id`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/only_first_task_succeed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/only_first_task_succeed.snap index 706f71e53..67637d5ef 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/only_first_task_succeed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/only_first_task_succeed.snap @@ -39,7 +39,7 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the batch `id`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the batch `id`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/second_and_third_tasks_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/second_and_third_tasks_fails.snap index 0823ebbbf..b552f1abf 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/second_and_third_tasks_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_multiple_primary_key_batch_wrong_key/second_and_third_tasks_fails.snap @@ -42,8 +42,8 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the batch `id`", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the index `id`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the batch `id`", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the index `id`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/all_other_tasks_succeeds.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/all_other_tasks_succeeds.snap index fc58f2b52..0c02c8165 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/all_other_tasks_succeeds.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/all_other_tasks_succeeds.snap @@ -50,8 +50,8 @@ doggos: { number_of_documents: 4, field_distribution: {"doggo": 4, "paw": 4} } [timestamp] [2,3,4,5,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is setting the `bork` primary key but cannot interfere with primary key guessing of the batch", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `paw` in task with id 2 is different from the primary key of the batch `bork`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because it is setting the `bork` primary key and it would interfere with primary key guessing of the batch", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 2 because its primary key `paw` is different from the primary key of the batch `bork`", } 2 {uid: 2, details: {"receivedDocuments":4,"indexedDocuments":4}, stats: {"totalNbTasks":4,"status":{"succeeded":4},"types":{"documentAdditionOrUpdate":4},"indexUids":{"doggos":4}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/first_task_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/first_task_fails.snap index d8271492c..1268e11ef 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/first_task_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/first_task_fails.snap @@ -45,7 +45,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is setting the `bork` primary key but cannot interfere with primary key guessing of the batch", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because it is setting the `bork` primary key and it would interfere with primary key guessing of the batch", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/second_task_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/second_task_fails.snap index 484c9ada0..20fdfdcc6 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/second_task_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key/second_task_fails.snap @@ -47,8 +47,8 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is setting the `bork` primary key but cannot interfere with primary key guessing of the batch", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `paw` in task with id 2 is different from the primary key of the batch `bork`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because it is setting the `bork` primary key and it would interfere with primary key guessing of the batch", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 2 because its primary key `paw` is different from the primary key of the batch `bork`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/all_other_tasks_succeeds.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/all_other_tasks_succeeds.snap index 5c0046af1..5b2946de9 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/all_other_tasks_succeeds.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/all_other_tasks_succeeds.snap @@ -50,8 +50,8 @@ doggos: { number_of_documents: 5, field_distribution: {"doggo": 5, "doggoid": 5} [timestamp] [2,3,4,5,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is setting the `bork` primary key but cannot interfere with primary key guessing of the batch", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the index `doggoid`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because it is setting the `bork` primary key and it would interfere with primary key guessing of the batch", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the index `doggoid`", } 2 {uid: 2, details: {"receivedDocuments":4,"indexedDocuments":4}, stats: {"totalNbTasks":4,"status":{"succeeded":4},"types":{"documentAdditionOrUpdate":4},"indexUids":{"doggos":4}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/first_task_succeed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/first_task_succeed.snap index 5bdbe2943..c71bf9097 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/first_task_succeed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/first_task_succeed.snap @@ -45,7 +45,7 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "doggoid": 1} [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is setting the `bork` primary key but cannot interfere with primary key guessing of the batch", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because it is setting the `bork` primary key and it would interfere with primary key guessing of the batch", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/second_task_fails.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/second_task_fails.snap index 849eddebe..5d67361b0 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/second_task_fails.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_addition_with_set_and_null_primary_key_inference_works/second_task_fails.snap @@ -48,8 +48,8 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "doggoid": 1} [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is setting the `bork` primary key but cannot interfere with primary key guessing of the batch", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "primary key `bork` in task with id 1 is different from the primary key of the index `doggoid`", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because it is setting the `bork` primary key and it would interfere with primary key guessing of the batch", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":0}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped batching before task with id 1 because its primary key `bork` is different from the primary key of the index `doggoid`", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/all_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/all_tasks_processed.snap index 6ac284c38..d7218ab46 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/all_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/all_tasks_processed.snap @@ -71,15 +71,15 @@ doggos: { number_of_documents: 10, field_distribution: {"doggo": 10, "id": 10} } [timestamp] [9,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } 9 {uid: 9, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/five_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/five_tasks_processed.snap index ac239f3d6..2ffdfc986 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/five_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_replace_without_autobatching/five_tasks_processed.snap @@ -61,11 +61,11 @@ doggos: { number_of_documents: 5, field_distribution: {"doggo": 5, "id": 5} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/all_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/all_tasks_processed.snap index 43d09fafa..4987b26f7 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/all_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/all_tasks_processed.snap @@ -71,15 +71,15 @@ doggos: { number_of_documents: 10, field_distribution: {"doggo": 10, "id": 10} } [timestamp] [9,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +5 {uid: 5, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +6 {uid: 6, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +7 {uid: 7, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +8 {uid: 8, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } 9 {uid: 9, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/five_tasks_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/five_tasks_processed.snap index bf0da7815..8b73a24ee 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/five_tasks_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_document_addition.rs/test_document_update_without_autobatching/five_tasks_processed.snap @@ -61,11 +61,11 @@ doggos: { number_of_documents: 5, field_distribution: {"doggo": 5, "id": 5} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } -4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "reached configured batch limit of 1 tasks", } +0 {uid: 0, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +1 {uid: 1, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +2 {uid: 2, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +3 {uid: 3, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } +4 {uid: 4, details: {"receivedDocuments":1,"indexedDocuments":1}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched up to configured batch limit of 1 tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap index 4f60fd009..c5696578a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap @@ -40,7 +40,7 @@ doggos: { number_of_documents: 3, field_distribution: {"catto": 1, "doggo": 2, " [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is a document operation in a batch of settings changes", } +0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped before task with id 1 because it is a document operation which cannot be batched with settings changes", } 1 {uid: 1, details: {"receivedDocuments":3,"indexedDocuments":3}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap index d502215b5..edabbfa3c 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap @@ -38,7 +38,7 @@ doggos: { number_of_documents: 0, field_distribution: {} } [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is a document operation in a batch of settings changes", } +0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped before task with id 1 because it is a document operation which cannot be batched with settings changes", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap index 3bfeed9c8..aa86c61be 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap @@ -52,7 +52,7 @@ doggos: { number_of_documents: 1, field_distribution: {"doggo": 1, "id": 1} } [timestamp] [2,3,4,5,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is a document operation in a batch of settings changes", } +0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped before task with id 1 because it is a document operation which cannot be batched with settings changes", } 1 {uid: 1, details: {"receivedDocuments":3,"indexedDocuments":3}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } 2 {uid: 2, details: {"providedIds":1,"deletedDocuments":2,"originalFilter":"true&\"id = 2\"&\"catto EXISTS\""}, stats: {"totalNbTasks":4,"status":{"succeeded":2,"failed":2},"types":{"documentDeletion":4},"indexUids":{"doggos":4}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap index 8b55d9796..410c9c68e 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap @@ -49,7 +49,7 @@ doggos: { number_of_documents: 3, field_distribution: {"catto": 1, "doggo": 2, " [timestamp] [1,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "task with id 1 is a document operation in a batch of settings changes", } +0 {uid: 0, details: {"filterableAttributes":["catto"]}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"settingsUpdate":1},"indexUids":{"doggos":1}}, stop reason: "stopped before task with id 1 because it is a document operation which cannot be batched with settings changes", } 1 {uid: 1, details: {"receivedDocuments":3,"indexedDocuments":3}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"documentAdditionOrUpdate":1},"indexUids":{"doggos":1}}, stop reason: "batched all enqueued tasks", } ---------------------------------------------------------------------- ### Batch to tasks mapping: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_index_creation/index_creation_failed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_index_creation/index_creation_failed.snap index 7db4a4edf..8feeaf990 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_index_creation/index_creation_failed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_index_creation/index_creation_failed.snap @@ -34,7 +34,7 @@ catto [0,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/panic_in_process_batch_for_index_creation/index_creation_failed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/panic_in_process_batch_for_index_creation/index_creation_failed.snap index 77a444451..201680d7a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/panic_in_process_batch_for_index_creation/index_creation_failed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/panic_in_process_batch_for_index_creation/index_creation_failed.snap @@ -34,7 +34,7 @@ catto [0,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 0 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap index 178ec8166..30abdb36b 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap @@ -57,11 +57,11 @@ girafo: { number_of_documents: 0, field_distribution: {} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task", } -1 {uid: 1, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } -4 {uid: 4, details: {"primaryKey":"leaves"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"girafo":1}}, stop reason: "task with id 4 of type `indexCreation` cannot be batched", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +1 {uid: 1, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } +4 {uid: 4, details: {"primaryKey":"leaves"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"girafo":1}}, stop reason: "created batch containing only task with id 4 of type `indexCreation` that cannot be batched with any other task.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_removing_the_upgrade_tasks.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_removing_the_upgrade_tasks.snap index 26984f2e5..fb682053c 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_removing_the_upgrade_tasks.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_removing_the_upgrade_tasks.snap @@ -58,11 +58,11 @@ girafo: { number_of_documents: 0, field_distribution: {} } [timestamp] [5,] ---------------------------------------------------------------------- ### All Batches: -1 {uid: 1, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "task with id 1 of type `indexCreation` cannot be batched", } -2 {uid: 2, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 2 of type `indexCreation` cannot be batched", } -3 {uid: 3, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "task with id 3 of type `indexCreation` cannot be batched", } -4 {uid: 4, details: {"primaryKey":"leaves"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"girafo":1}}, stop reason: "task with id 4 of type `indexCreation` cannot be batched", } -5 {uid: 5, details: {"matchedTasks":1,"deletedTasks":1,"originalFilter":"types=upgradeDatabase"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "a batch of tasks of type `taskDeletion` cannot be batched with any other type of task", } +1 {uid: 1, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } +2 {uid: 2, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } +3 {uid: 3, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } +4 {uid: 4, details: {"primaryKey":"leaves"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"girafo":1}}, stop reason: "created batch containing only task with id 4 of type `indexCreation` that cannot be batched with any other task.", } +5 {uid: 5, details: {"matchedTasks":1,"deletedTasks":1,"originalFilter":"types=upgradeDatabase"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"taskDeletion":1},"indexUids":{}}, stop reason: "stopped after the last task of type `taskDeletion` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 1 [1,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap index 899a507f5..beb1176c2 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap @@ -37,7 +37,7 @@ catto [1,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap index e3244fc28..faa3ea23d 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap @@ -40,7 +40,7 @@ doggo [2,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap index 9d78f6bbf..ee569fdc4 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap @@ -43,7 +43,7 @@ doggo [2,3,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/meilisearch/tests/batches/mod.rs b/crates/meilisearch/tests/batches/mod.rs index e775d1ea4..50c9bdafd 100644 --- a/crates/meilisearch/tests/batches/mod.rs +++ b/crates/meilisearch/tests/batches/mod.rs @@ -310,7 +310,7 @@ async fn test_summarized_document_addition_or_update() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); @@ -353,7 +353,7 @@ async fn test_summarized_document_addition_or_update() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); } @@ -398,7 +398,7 @@ async fn test_summarized_delete_documents_by_batch() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); @@ -440,7 +440,7 @@ async fn test_summarized_delete_documents_by_batch() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); } @@ -488,7 +488,7 @@ async fn test_summarized_delete_documents_by_filter() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); @@ -532,7 +532,7 @@ async fn test_summarized_delete_documents_by_filter() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); @@ -576,7 +576,7 @@ async fn test_summarized_delete_documents_by_filter() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); } @@ -622,7 +622,7 @@ async fn test_summarized_delete_document_by_id() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); @@ -664,7 +664,7 @@ async fn test_summarized_delete_document_by_id() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); } @@ -731,7 +731,7 @@ async fn test_summarized_settings_update() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" } "###); } @@ -773,7 +773,7 @@ async fn test_summarized_index_creation() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 0 of type `indexCreation` cannot be batched" + "batchStrategy": "created batch containing only task with id 0 of type `indexCreation` that cannot be batched with any other task." } "###); @@ -812,7 +812,7 @@ async fn test_summarized_index_creation() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 1 of type `indexCreation` cannot be batched" + "batchStrategy": "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task." } "###); } @@ -964,7 +964,7 @@ async fn test_summarized_index_update() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 0 of type `indexUpdate` cannot be batched" + "batchStrategy": "created batch containing only task with id 0 of type `indexUpdate` that cannot be batched with any other task." } "###); @@ -1003,7 +1003,7 @@ async fn test_summarized_index_update() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 1 of type `indexUpdate` cannot be batched" + "batchStrategy": "created batch containing only task with id 1 of type `indexUpdate` that cannot be batched with any other task." } "###); @@ -1043,7 +1043,7 @@ async fn test_summarized_index_update() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 3 of type `indexUpdate` cannot be batched" + "batchStrategy": "created batch containing only task with id 3 of type `indexUpdate` that cannot be batched with any other task." } "###); @@ -1082,7 +1082,7 @@ async fn test_summarized_index_update() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 4 of type `indexUpdate` cannot be batched" + "batchStrategy": "created batch containing only task with id 4 of type `indexUpdate` that cannot be batched with any other task." } "###); } @@ -1134,7 +1134,7 @@ async fn test_summarized_index_swap() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 0 of type `indexSwap` cannot be batched" + "batchStrategy": "created batch containing only task with id 0 of type `indexSwap` that cannot be batched with any other task." } "###); @@ -1177,7 +1177,7 @@ async fn test_summarized_index_swap() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 1 of type `indexCreation` cannot be batched" + "batchStrategy": "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task." } "###); } @@ -1224,7 +1224,7 @@ async fn test_summarized_batch_cancelation() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 1 of type `taskCancelation` cannot be batched" + "batchStrategy": "created batch containing only task with id 1 of type `taskCancelation` that cannot be batched with any other task." } "###); } @@ -1271,7 +1271,7 @@ async fn test_summarized_batch_deletion() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "a batch of tasks of type `taskDeletion` cannot be batched with any other type of task" + "batchStrategy": "stopped after the last task of type `taskDeletion` because they cannot be batched with tasks of any other type." } "###); } @@ -1313,7 +1313,7 @@ async fn test_summarized_dump_creation() { "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "task with id 0 of type `dumpCreation` cannot be batched" + "batchStrategy": "created batch containing only task with id 0 of type `dumpCreation` that cannot be batched with any other task." } "###); } diff --git a/crates/meilisearch/tests/dumps/snapshots/mod.rs/import_dump_v6_containing_batches_and_enqueued_tasks/batches.snap b/crates/meilisearch/tests/dumps/snapshots/mod.rs/import_dump_v6_containing_batches_and_enqueued_tasks/batches.snap index 2f3b0a7f9..81d3a1981 100644 --- a/crates/meilisearch/tests/dumps/snapshots/mod.rs/import_dump_v6_containing_batches_and_enqueued_tasks/batches.snap +++ b/crates/meilisearch/tests/dumps/snapshots/mod.rs/import_dump_v6_containing_batches_and_enqueued_tasks/batches.snap @@ -27,7 +27,7 @@ source: crates/meilisearch/tests/dumps/mod.rs "duration": "[date]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "batched all enqueued tasks" + "batchStrategy": "batched all enqueued tasks" }, { "uid": 1, @@ -51,7 +51,7 @@ source: crates/meilisearch/tests/dumps/mod.rs "duration": "PT0.144827890S", "startedAt": "2025-02-04T10:15:21.275640274Z", "finishedAt": "2025-02-04T10:15:21.420468164Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 0, @@ -72,7 +72,7 @@ source: crates/meilisearch/tests/dumps/mod.rs "duration": "PT0.032902186S", "startedAt": "2025-02-04T10:14:43.559526162Z", "finishedAt": "2025-02-04T10:14:43.592428348Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 3, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap index 1d89e6838..f7f678e36 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap @@ -24,7 +24,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task" + "batchStrategy": "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type." }, { "uid": 23, @@ -47,7 +47,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.004146631S", "startedAt": "2025-01-23T11:38:57.012591321Z", "finishedAt": "2025-01-23T11:38:57.016737952Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 22, @@ -71,7 +71,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.102738497S", "startedAt": "2025-01-23T11:36:22.551906856Z", "finishedAt": "2025-01-23T11:36:22.654645353Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 21, @@ -95,7 +95,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.005108474S", "startedAt": "2025-01-23T11:36:04.132670526Z", "finishedAt": "2025-01-23T11:36:04.137779Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 20, @@ -119,7 +119,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.027954894S", "startedAt": "2025-01-23T11:35:53.631082795Z", "finishedAt": "2025-01-23T11:35:53.659037689Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 19, @@ -142,7 +142,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.006903297S", "startedAt": "2025-01-20T11:50:52.874106134Z", "finishedAt": "2025-01-20T11:50:52.881009431Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 18, @@ -171,7 +171,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000481257S", "startedAt": "2025-01-20T11:48:04.92820416Z", "finishedAt": "2025-01-20T11:48:04.928685417Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 17, @@ -194,7 +194,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000407005S", "startedAt": "2025-01-20T11:47:53.509403957Z", "finishedAt": "2025-01-20T11:47:53.509810962Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 16, @@ -217,7 +217,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000403716S", "startedAt": "2025-01-20T11:47:48.430653005Z", "finishedAt": "2025-01-20T11:47:48.431056721Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 15, @@ -240,7 +240,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000417016S", "startedAt": "2025-01-20T11:47:42.429678617Z", "finishedAt": "2025-01-20T11:47:42.430095633Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 14, @@ -264,7 +264,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT12.086284842S", "startedAt": "2025-01-20T11:47:03.092181576Z", "finishedAt": "2025-01-20T11:47:15.178466418Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 13, @@ -296,7 +296,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.011506614S", "startedAt": "2025-01-16T17:18:43.29334923Z", "finishedAt": "2025-01-16T17:18:43.304855844Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 12, @@ -324,7 +324,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007640163S", "startedAt": "2025-01-16T17:02:52.539749853Z", "finishedAt": "2025-01-16T17:02:52.547390016Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 11, @@ -347,7 +347,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007307840S", "startedAt": "2025-01-16T17:01:14.112756687Z", "finishedAt": "2025-01-16T17:01:14.120064527Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 10, @@ -375,7 +375,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007391353S", "startedAt": "2025-01-16T17:00:29.201180268Z", "finishedAt": "2025-01-16T17:00:29.208571621Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 9, @@ -403,7 +403,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007445825S", "startedAt": "2025-01-16T17:00:15.77629445Z", "finishedAt": "2025-01-16T17:00:15.783740275Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 8, @@ -436,7 +436,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.012020083S", "startedAt": "2025-01-16T16:59:42.744086671Z", "finishedAt": "2025-01-16T16:59:42.756106754Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 7, @@ -463,7 +463,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007440092S", "startedAt": "2025-01-16T16:58:41.2155771Z", "finishedAt": "2025-01-16T16:58:41.223017192Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 6, @@ -490,7 +490,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007565161S", "startedAt": "2025-01-16T16:54:51.940332781Z", "finishedAt": "2025-01-16T16:54:51.947897942Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 5, @@ -516,7 +516,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.016307263S", "startedAt": "2025-01-16T16:53:19.913351957Z", "finishedAt": "2025-01-16T16:53:19.92965922Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 23, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap index 1d89e6838..f7f678e36 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap @@ -24,7 +24,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task" + "batchStrategy": "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type." }, { "uid": 23, @@ -47,7 +47,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.004146631S", "startedAt": "2025-01-23T11:38:57.012591321Z", "finishedAt": "2025-01-23T11:38:57.016737952Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 22, @@ -71,7 +71,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.102738497S", "startedAt": "2025-01-23T11:36:22.551906856Z", "finishedAt": "2025-01-23T11:36:22.654645353Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 21, @@ -95,7 +95,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.005108474S", "startedAt": "2025-01-23T11:36:04.132670526Z", "finishedAt": "2025-01-23T11:36:04.137779Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 20, @@ -119,7 +119,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.027954894S", "startedAt": "2025-01-23T11:35:53.631082795Z", "finishedAt": "2025-01-23T11:35:53.659037689Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 19, @@ -142,7 +142,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.006903297S", "startedAt": "2025-01-20T11:50:52.874106134Z", "finishedAt": "2025-01-20T11:50:52.881009431Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 18, @@ -171,7 +171,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000481257S", "startedAt": "2025-01-20T11:48:04.92820416Z", "finishedAt": "2025-01-20T11:48:04.928685417Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 17, @@ -194,7 +194,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000407005S", "startedAt": "2025-01-20T11:47:53.509403957Z", "finishedAt": "2025-01-20T11:47:53.509810962Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 16, @@ -217,7 +217,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000403716S", "startedAt": "2025-01-20T11:47:48.430653005Z", "finishedAt": "2025-01-20T11:47:48.431056721Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 15, @@ -240,7 +240,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000417016S", "startedAt": "2025-01-20T11:47:42.429678617Z", "finishedAt": "2025-01-20T11:47:42.430095633Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 14, @@ -264,7 +264,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT12.086284842S", "startedAt": "2025-01-20T11:47:03.092181576Z", "finishedAt": "2025-01-20T11:47:15.178466418Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 13, @@ -296,7 +296,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.011506614S", "startedAt": "2025-01-16T17:18:43.29334923Z", "finishedAt": "2025-01-16T17:18:43.304855844Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 12, @@ -324,7 +324,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007640163S", "startedAt": "2025-01-16T17:02:52.539749853Z", "finishedAt": "2025-01-16T17:02:52.547390016Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 11, @@ -347,7 +347,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007307840S", "startedAt": "2025-01-16T17:01:14.112756687Z", "finishedAt": "2025-01-16T17:01:14.120064527Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 10, @@ -375,7 +375,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007391353S", "startedAt": "2025-01-16T17:00:29.201180268Z", "finishedAt": "2025-01-16T17:00:29.208571621Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 9, @@ -403,7 +403,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007445825S", "startedAt": "2025-01-16T17:00:15.77629445Z", "finishedAt": "2025-01-16T17:00:15.783740275Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 8, @@ -436,7 +436,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.012020083S", "startedAt": "2025-01-16T16:59:42.744086671Z", "finishedAt": "2025-01-16T16:59:42.756106754Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 7, @@ -463,7 +463,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007440092S", "startedAt": "2025-01-16T16:58:41.2155771Z", "finishedAt": "2025-01-16T16:58:41.223017192Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 6, @@ -490,7 +490,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007565161S", "startedAt": "2025-01-16T16:54:51.940332781Z", "finishedAt": "2025-01-16T16:54:51.947897942Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 5, @@ -516,7 +516,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.016307263S", "startedAt": "2025-01-16T16:53:19.913351957Z", "finishedAt": "2025-01-16T16:53:19.92965922Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 23, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap index 1d89e6838..f7f678e36 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap @@ -24,7 +24,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task" + "batchStrategy": "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type." }, { "uid": 23, @@ -47,7 +47,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.004146631S", "startedAt": "2025-01-23T11:38:57.012591321Z", "finishedAt": "2025-01-23T11:38:57.016737952Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 22, @@ -71,7 +71,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.102738497S", "startedAt": "2025-01-23T11:36:22.551906856Z", "finishedAt": "2025-01-23T11:36:22.654645353Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 21, @@ -95,7 +95,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.005108474S", "startedAt": "2025-01-23T11:36:04.132670526Z", "finishedAt": "2025-01-23T11:36:04.137779Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 20, @@ -119,7 +119,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.027954894S", "startedAt": "2025-01-23T11:35:53.631082795Z", "finishedAt": "2025-01-23T11:35:53.659037689Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 19, @@ -142,7 +142,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.006903297S", "startedAt": "2025-01-20T11:50:52.874106134Z", "finishedAt": "2025-01-20T11:50:52.881009431Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 18, @@ -171,7 +171,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000481257S", "startedAt": "2025-01-20T11:48:04.92820416Z", "finishedAt": "2025-01-20T11:48:04.928685417Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 17, @@ -194,7 +194,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000407005S", "startedAt": "2025-01-20T11:47:53.509403957Z", "finishedAt": "2025-01-20T11:47:53.509810962Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 16, @@ -217,7 +217,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000403716S", "startedAt": "2025-01-20T11:47:48.430653005Z", "finishedAt": "2025-01-20T11:47:48.431056721Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 15, @@ -240,7 +240,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000417016S", "startedAt": "2025-01-20T11:47:42.429678617Z", "finishedAt": "2025-01-20T11:47:42.430095633Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 14, @@ -264,7 +264,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT12.086284842S", "startedAt": "2025-01-20T11:47:03.092181576Z", "finishedAt": "2025-01-20T11:47:15.178466418Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 13, @@ -296,7 +296,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.011506614S", "startedAt": "2025-01-16T17:18:43.29334923Z", "finishedAt": "2025-01-16T17:18:43.304855844Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 12, @@ -324,7 +324,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007640163S", "startedAt": "2025-01-16T17:02:52.539749853Z", "finishedAt": "2025-01-16T17:02:52.547390016Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 11, @@ -347,7 +347,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007307840S", "startedAt": "2025-01-16T17:01:14.112756687Z", "finishedAt": "2025-01-16T17:01:14.120064527Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 10, @@ -375,7 +375,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007391353S", "startedAt": "2025-01-16T17:00:29.201180268Z", "finishedAt": "2025-01-16T17:00:29.208571621Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 9, @@ -403,7 +403,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007445825S", "startedAt": "2025-01-16T17:00:15.77629445Z", "finishedAt": "2025-01-16T17:00:15.783740275Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 8, @@ -436,7 +436,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.012020083S", "startedAt": "2025-01-16T16:59:42.744086671Z", "finishedAt": "2025-01-16T16:59:42.756106754Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 7, @@ -463,7 +463,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007440092S", "startedAt": "2025-01-16T16:58:41.2155771Z", "finishedAt": "2025-01-16T16:58:41.223017192Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 6, @@ -490,7 +490,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007565161S", "startedAt": "2025-01-16T16:54:51.940332781Z", "finishedAt": "2025-01-16T16:54:51.947897942Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 5, @@ -516,7 +516,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.016307263S", "startedAt": "2025-01-16T16:53:19.913351957Z", "finishedAt": "2025-01-16T16:53:19.92965922Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 23, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_batchUids_equal_10.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_batchUids_equal_10.snap index 341085c87..7688b3c36 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_batchUids_equal_10.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_batchUids_equal_10.snap @@ -29,7 +29,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeEnqueuedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeEnqueuedAt_equal_2025-01-16T16_47_41.snap index 15ae9c34d..78a98cb3d 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeEnqueuedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeEnqueuedAt_equal_2025-01-16T16_47_41.snap @@ -25,7 +25,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 0, @@ -49,7 +49,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.111055654S", "startedAt": "2025-01-16T16:45:16.020248085Z", "finishedAt": "2025-01-16T16:45:16.131303739Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 2, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeFinishedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeFinishedAt_equal_2025-01-16T16_47_41.snap index 15ae9c34d..78a98cb3d 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeFinishedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeFinishedAt_equal_2025-01-16T16_47_41.snap @@ -25,7 +25,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 0, @@ -49,7 +49,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.111055654S", "startedAt": "2025-01-16T16:45:16.020248085Z", "finishedAt": "2025-01-16T16:45:16.131303739Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 2, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeStartedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeStartedAt_equal_2025-01-16T16_47_41.snap index 15ae9c34d..78a98cb3d 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeStartedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_beforeStartedAt_equal_2025-01-16T16_47_41.snap @@ -25,7 +25,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 0, @@ -49,7 +49,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.111055654S", "startedAt": "2025-01-16T16:45:16.020248085Z", "finishedAt": "2025-01-16T16:45:16.131303739Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 2, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_canceledBy_equal_19.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_canceledBy_equal_19.snap index 04795c285..9dafa709b 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_canceledBy_equal_19.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_canceledBy_equal_19.snap @@ -30,7 +30,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_statuses_equal_canceled.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_statuses_equal_canceled.snap index 04795c285..9dafa709b 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_statuses_equal_canceled.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_statuses_equal_canceled.snap @@ -30,7 +30,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_uids_equal_10.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_uids_equal_10.snap index 341085c87..7688b3c36 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_uids_equal_10.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_uids_equal_10.snap @@ -29,7 +29,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap index 068dd0d82..78cb4e656 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap @@ -24,7 +24,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "[duration]", "startedAt": "[date]", "finishedAt": "[date]", - "batchCreationComplete": "a batch of tasks of type `upgradeDatabase` cannot be batched with any other type of task" + "batchStrategy": "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type." }, { "uid": 23, @@ -47,7 +47,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.004146631S", "startedAt": "2025-01-23T11:38:57.012591321Z", "finishedAt": "2025-01-23T11:38:57.016737952Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 22, @@ -71,7 +71,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.102738497S", "startedAt": "2025-01-23T11:36:22.551906856Z", "finishedAt": "2025-01-23T11:36:22.654645353Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 21, @@ -95,7 +95,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.005108474S", "startedAt": "2025-01-23T11:36:04.132670526Z", "finishedAt": "2025-01-23T11:36:04.137779Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 20, @@ -119,7 +119,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.027954894S", "startedAt": "2025-01-23T11:35:53.631082795Z", "finishedAt": "2025-01-23T11:35:53.659037689Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 19, @@ -142,7 +142,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.006903297S", "startedAt": "2025-01-20T11:50:52.874106134Z", "finishedAt": "2025-01-20T11:50:52.881009431Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 18, @@ -171,7 +171,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000481257S", "startedAt": "2025-01-20T11:48:04.92820416Z", "finishedAt": "2025-01-20T11:48:04.928685417Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 17, @@ -194,7 +194,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000407005S", "startedAt": "2025-01-20T11:47:53.509403957Z", "finishedAt": "2025-01-20T11:47:53.509810962Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 16, @@ -217,7 +217,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000403716S", "startedAt": "2025-01-20T11:47:48.430653005Z", "finishedAt": "2025-01-20T11:47:48.431056721Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 15, @@ -240,7 +240,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.000417016S", "startedAt": "2025-01-20T11:47:42.429678617Z", "finishedAt": "2025-01-20T11:47:42.430095633Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 14, @@ -264,7 +264,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT12.086284842S", "startedAt": "2025-01-20T11:47:03.092181576Z", "finishedAt": "2025-01-20T11:47:15.178466418Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 13, @@ -296,7 +296,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.011506614S", "startedAt": "2025-01-16T17:18:43.29334923Z", "finishedAt": "2025-01-16T17:18:43.304855844Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 12, @@ -324,7 +324,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007640163S", "startedAt": "2025-01-16T17:02:52.539749853Z", "finishedAt": "2025-01-16T17:02:52.547390016Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 11, @@ -347,7 +347,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007307840S", "startedAt": "2025-01-16T17:01:14.112756687Z", "finishedAt": "2025-01-16T17:01:14.120064527Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 10, @@ -375,7 +375,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007391353S", "startedAt": "2025-01-16T17:00:29.201180268Z", "finishedAt": "2025-01-16T17:00:29.208571621Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 9, @@ -403,7 +403,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007445825S", "startedAt": "2025-01-16T17:00:15.77629445Z", "finishedAt": "2025-01-16T17:00:15.783740275Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 8, @@ -436,7 +436,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.012020083S", "startedAt": "2025-01-16T16:59:42.744086671Z", "finishedAt": "2025-01-16T16:59:42.756106754Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 7, @@ -463,7 +463,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007440092S", "startedAt": "2025-01-16T16:58:41.2155771Z", "finishedAt": "2025-01-16T16:58:41.223017192Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 6, @@ -490,7 +490,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007565161S", "startedAt": "2025-01-16T16:54:51.940332781Z", "finishedAt": "2025-01-16T16:54:51.947897942Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 5, @@ -516,7 +516,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.016307263S", "startedAt": "2025-01-16T16:53:19.913351957Z", "finishedAt": "2025-01-16T16:53:19.92965922Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 4, @@ -540,7 +540,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.087655941S", "startedAt": "2025-01-16T16:52:32.631145531Z", "finishedAt": "2025-01-16T16:52:32.718801472Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 3, @@ -565,7 +565,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.007593573S", "startedAt": "2025-01-16T16:47:53.677901409Z", "finishedAt": "2025-01-16T16:47:53.685494982Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 2, @@ -591,7 +591,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.017769760S", "startedAt": "2025-01-16T16:47:41.211587682Z", "finishedAt": "2025-01-16T16:47:41.229357442Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 1, @@ -615,7 +615,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.066095506S", "startedAt": "2025-01-16T16:47:10.217299609Z", "finishedAt": "2025-01-16T16:47:10.283395115Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" }, { "uid": 0, @@ -639,7 +639,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "duration": "PT0.111055654S", "startedAt": "2025-01-16T16:45:16.020248085Z", "finishedAt": "2025-01-16T16:45:16.131303739Z", - "batchCreationComplete": "unspecified" + "batchStrategy": "unspecified" } ], "total": 25, From 1d5265caf412a64b5ab4e258117ae348914689ea Mon Sep 17 00:00:00 2001 From: mcmah309 Date: Thu, 22 May 2025 14:25:04 +0000 Subject: [PATCH 035/292] Fix typo in method name --- crates/meilisearch-types/src/settings.rs | 2 +- .../milli/src/search/new/tests/ngram_split_words.rs | 12 ++++++------ crates/milli/src/search/new/tests/typo.rs | 2 +- crates/milli/src/update/settings.rs | 2 +- crates/milli/src/update/test_settings.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/meilisearch-types/src/settings.rs b/crates/meilisearch-types/src/settings.rs index ccf0d75ee..97003074f 100644 --- a/crates/meilisearch-types/src/settings.rs +++ b/crates/meilisearch-types/src/settings.rs @@ -666,7 +666,7 @@ pub fn apply_settings_to_builder( match typo_tolerance { Setting::Set(ref value) => { match value.enabled { - Setting::Set(val) => builder.set_autorize_typos(val), + Setting::Set(val) => builder.set_authorize_typos(val), Setting::Reset => builder.reset_authorize_typos(), Setting::NotSet => (), } diff --git a/crates/milli/src/search/new/tests/ngram_split_words.rs b/crates/milli/src/search/new/tests/ngram_split_words.rs index 8427dd65b..0a89899ed 100644 --- a/crates/milli/src/search/new/tests/ngram_split_words.rs +++ b/crates/milli/src/search/new/tests/ngram_split_words.rs @@ -72,7 +72,7 @@ fn test_2gram_simple() { let index = create_index(); index .update_settings(|s| { - s.set_autorize_typos(false); + s.set_authorize_typos(false); }) .unwrap(); @@ -103,7 +103,7 @@ fn test_3gram_simple() { let index = create_index(); index .update_settings(|s| { - s.set_autorize_typos(false); + s.set_authorize_typos(false); }) .unwrap(); @@ -153,7 +153,7 @@ fn test_no_disable_ngrams() { let index = create_index(); index .update_settings(|s| { - s.set_autorize_typos(false); + s.set_authorize_typos(false); }) .unwrap(); @@ -179,7 +179,7 @@ fn test_2gram_prefix() { let index = create_index(); index .update_settings(|s| { - s.set_autorize_typos(false); + s.set_authorize_typos(false); }) .unwrap(); @@ -208,7 +208,7 @@ fn test_3gram_prefix() { let index = create_index(); index .update_settings(|s| { - s.set_autorize_typos(false); + s.set_authorize_typos(false); }) .unwrap(); @@ -260,7 +260,7 @@ fn test_disable_split_words() { let index = create_index(); index .update_settings(|s| { - s.set_autorize_typos(false); + s.set_authorize_typos(false); }) .unwrap(); diff --git a/crates/milli/src/search/new/tests/typo.rs b/crates/milli/src/search/new/tests/typo.rs index 1bbe08977..8dd93b102 100644 --- a/crates/milli/src/search/new/tests/typo.rs +++ b/crates/milli/src/search/new/tests/typo.rs @@ -151,7 +151,7 @@ fn test_no_typo() { let index = create_index(); index .update_settings(|s| { - s.set_autorize_typos(false); + s.set_authorize_typos(false); }) .unwrap(); diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index 51d9aed27..bb965ba69 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -333,7 +333,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { self.primary_key = Setting::Set(primary_key); } - pub fn set_autorize_typos(&mut self, val: bool) { + pub fn set_authorize_typos(&mut self, val: bool) { self.authorize_typos = Setting::Set(val); } diff --git a/crates/milli/src/update/test_settings.rs b/crates/milli/src/update/test_settings.rs index 2b9ee3a5e..1adb96366 100644 --- a/crates/milli/src/update/test_settings.rs +++ b/crates/milli/src/update/test_settings.rs @@ -792,7 +792,7 @@ fn test_disable_typo() { index .update_settings_using_wtxn(&mut txn, |settings| { - settings.set_autorize_typos(false); + settings.set_authorize_typos(false); }) .unwrap(); From 34d58f35c84f08184cd49d81395f7b2b204048dd Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Sun, 25 May 2025 15:48:55 +0300 Subject: [PATCH 036/292] Print `[uuid]` instead of the Uuid index name for MeilisearchHttpError::Milli errors This way the tests' assertions/snapshots for unique indices would be stable Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/src/error.rs | 10 +++++++++- crates/meilisearch/tests/search/errors.rs | 2 +- crates/meilisearch/tests/search/mod.rs | 17 ++++------------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/crates/meilisearch/src/error.rs b/crates/meilisearch/src/error.rs index b13eb8d7c..13800adc1 100644 --- a/crates/meilisearch/src/error.rs +++ b/crates/meilisearch/src/error.rs @@ -64,7 +64,7 @@ pub enum MeilisearchHttpError { #[error(transparent)] IndexScheduler(#[from] index_scheduler::Error), #[error("{}", match .index_name { - Some(name) if !name.is_empty() => format!("Index `{}`: {error}", name), + Some(name) if !name.is_empty() => format!("Index `{}`: {error}", MeilisearchHttpError::index_name(name)), _ => format!("{error}") })] Milli { error: milli::Error, index_name: Option }, @@ -84,6 +84,14 @@ impl MeilisearchHttpError { pub(crate) fn from_milli(error: milli::Error, index_name: Option) -> Self { Self::Milli { error, index_name } } + + fn index_name(index_name: &str) -> &str { + if let Ok(_) = uuid::Uuid::parse_str(index_name) { + "[uuid]" + } else { + index_name + } + } } impl ErrorCode for MeilisearchHttpError { diff --git a/crates/meilisearch/tests/search/errors.rs b/crates/meilisearch/tests/search/errors.rs index 2b63a07b1..bce03f56b 100644 --- a/crates/meilisearch/tests/search/errors.rs +++ b/crates/meilisearch/tests/search/errors.rs @@ -729,7 +729,7 @@ async fn filter_invalid_attribute_string() { |response, code| { snapshot!(response, @r###" { - "message": "Index `test`: Attribute `many` is not filterable. Available filterable attribute patterns are: `title`.\n1:5 many = Glass", + "message": "Index `[uuid]`: Attribute `many` is not filterable. Available filterable attribute patterns are: `title`.\n1:5 many = Glass", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index 70d76db0c..2cc882c71 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -17,11 +17,9 @@ mod restrict_searchable; mod search_queue; use meili_snap::{json_string, snapshot}; -use meilisearch::Opt; -use tempfile::TempDir; use crate::common::{ - default_settings, shared_index_with_documents, shared_index_with_nested_documents, + shared_index_with_documents, shared_index_with_nested_documents, shared_index_with_score_documents, Server, Value, DOCUMENTS, FRUITS_DOCUMENTS, NESTED_DOCUMENTS, SCORE_DOCUMENTS, VECTOR_DOCUMENTS, }; @@ -33,11 +31,10 @@ async fn test_settings_documents_indexing_swapping_and_search( query: &Value, test: impl Fn(Value, actix_http::StatusCode) + std::panic::UnwindSafe + Clone, ) { - let temp = TempDir::new().unwrap(); - let server = Server::new_with_options(Opt { ..default_settings(temp.path()) }).await.unwrap(); + let server = Server::new_shared(); eprintln!("Documents -> Settings -> test"); - let index = server.index("test"); + let index = server.unique_index(); let (task, code) = index.add_documents(documents.clone(), None).await; assert_eq!(code, 202, "{task}"); @@ -48,12 +45,9 @@ async fn test_settings_documents_indexing_swapping_and_search( index.wait_task(task.uid()).await.succeeded(); index.search(query.clone(), test.clone()).await; - let (task, code) = server.delete_index("test").await; - assert_eq!(code, 202, "{task}"); - server.wait_task(task.uid()).await.succeeded(); eprintln!("Settings -> Documents -> test"); - let index = server.index("test"); + let index = server.unique_index(); let (task, code) = index.update_settings(settings.clone()).await; assert_eq!(code, 202, "{task}"); @@ -64,9 +58,6 @@ async fn test_settings_documents_indexing_swapping_and_search( index.wait_task(task.uid()).await.succeeded(); index.search(query.clone(), test.clone()).await; - let (task, code) = server.delete_index("test").await; - assert_eq!(code, 202, "{task}"); - server.wait_task(task.uid()).await.succeeded(); } #[actix_rt::test] From 24e94b28c1c4ae30e4d3256f3af896b8446ba722 Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 26 May 2025 09:22:20 +0200 Subject: [PATCH 037/292] feat: uncouple geo extraction from full doc --- .../new/extract/faceted/extract_facets.rs | 248 ++++++++++++------ .../new/extract/faceted/facet_document.rs | 29 +- 2 files changed, 188 insertions(+), 89 deletions(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index 01cfe338f..aa7510863 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -8,7 +8,7 @@ use hashbrown::HashMap; use serde_json::Value; use super::super::cache::BalancedCaches; -use super::facet_document::extract_document_facets; +use super::facet_document::{extract_document_facets, extract_geo_document}; use super::FacetKind; use crate::fields_ids_map::metadata::Metadata; use crate::filterable_attributes_rules::match_faceted_field; @@ -90,53 +90,8 @@ impl FacetedDocidsExtractor { let mut cached_sorter = context.data.borrow_mut_or_yield(); let mut del_add_facet_value = DelAddFacetValue::new(&context.doc_alloc); let docid = document_change.docid(); - let res = match document_change { - DocumentChange::Deletion(inner) => extract_document_facets( - inner.current(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), - new_fields_ids_map.deref_mut(), - filterable_attributes, - sortable_fields, - asc_desc_fields, - distinct_field, - is_geo_enabled, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_del_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_del, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, - ), - DocumentChange::Update(inner) => { - let has_changed = inner.has_changed_for_fields( - &mut |field_name| { - match_faceted_field( - field_name, - filterable_attributes, - sortable_fields, - asc_desc_fields, - distinct_field, - ) - }, - rtxn, - index, - context.db_fields_ids_map, - )?; - let has_changed_for_geo_fields = - inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)?; - if !has_changed && !has_changed_for_geo_fields { - return Ok(()); - } - + match document_change { + DocumentChange::Deletion(inner) => { extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), @@ -145,7 +100,6 @@ impl FacetedDocidsExtractor { sortable_fields, asc_desc_fields, distinct_field, - is_geo_enabled, &mut |fid, meta, depth, value| { Self::facet_fn_with_options( &context.doc_alloc, @@ -163,15 +117,155 @@ impl FacetedDocidsExtractor { }, )?; + if is_geo_enabled { + extract_geo_document( + inner.current(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + asc_desc_fields, + &mut |fid, meta, depth, value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_del_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_del, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + }, + )?; + } + } + DocumentChange::Update(inner) => { + let has_changed = inner.has_changed_for_fields( + &mut |field_name| { + match_faceted_field( + field_name, + filterable_attributes, + sortable_fields, + asc_desc_fields, + distinct_field, + ) + }, + rtxn, + index, + context.db_fields_ids_map, + )?; + let has_changed_for_geo_fields = + inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)?; + + if has_changed { + extract_document_facets( + inner.current(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + filterable_attributes, + sortable_fields, + asc_desc_fields, + distinct_field, + &mut |fid, meta, depth, value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_del_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_del, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + }, + )?; + + extract_document_facets( + inner.merged(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + filterable_attributes, + sortable_fields, + asc_desc_fields, + distinct_field, + &mut |fid, meta, depth, value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_add_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_add, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + }, + )?; + } + + if is_geo_enabled && has_changed_for_geo_fields{ + extract_geo_document( + inner.current(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + asc_desc_fields, + &mut |fid, meta, depth, value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_del_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_del, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + }, + )?; + + extract_geo_document( + inner.merged(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + asc_desc_fields, + &mut |fid, meta, depth, value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_add_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_add, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + }, + )?; + } + } + DocumentChange::Insertion(inner) => { extract_document_facets( - inner.merged(rtxn, index, context.db_fields_ids_map)?, + inner.inserted(), inner.external_document_id(), new_fields_ids_map.deref_mut(), filterable_attributes, sortable_fields, asc_desc_fields, distinct_field, - is_geo_enabled, &mut |fid, meta, depth, value| { Self::facet_fn_with_options( &context.doc_alloc, @@ -187,37 +281,35 @@ impl FacetedDocidsExtractor { value, ) }, - ) + )?; + if is_geo_enabled { + extract_geo_document( + inner.inserted(), + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + asc_desc_fields, + &mut |fid, meta, depth, value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_add_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_add, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + }, + )?; + } } - DocumentChange::Insertion(inner) => extract_document_facets( - inner.inserted(), - inner.external_document_id(), - new_fields_ids_map.deref_mut(), - filterable_attributes, - sortable_fields, - asc_desc_fields, - distinct_field, - is_geo_enabled, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_add_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_add, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, - ), }; del_add_facet_value.send_data(docid, sender, &context.doc_alloc).unwrap(); - res + Ok(()) } #[allow(clippy::too_many_arguments)] diff --git a/crates/milli/src/update/new/extract/faceted/facet_document.rs b/crates/milli/src/update/new/extract/faceted/facet_document.rs index e74131402..30a5c462e 100644 --- a/crates/milli/src/update/new/extract/faceted/facet_document.rs +++ b/crates/milli/src/update/new/extract/faceted/facet_document.rs @@ -22,7 +22,6 @@ pub fn extract_document_facets<'doc>( sortable_fields: &HashSet, asc_desc_fields: &HashSet, distinct_field: &Option, - is_geo_enabled: bool, facet_fn: &mut impl FnMut(FieldId, Metadata, perm_json_p::Depth, &Value) -> Result<()>, ) -> Result<()> { // return the match result for the given field name. @@ -102,17 +101,25 @@ pub fn extract_document_facets<'doc>( } } - if is_geo_enabled { - if let Some(geo_value) = document.geo_field()? { - if let Some([lat, lng]) = extract_geo_coordinates(external_document_id, geo_value)? { - let ((lat_fid, lat_meta), (lng_fid, lng_meta)) = field_id_map - .id_with_metadata_or_insert("_geo.lat") - .zip(field_id_map.id_with_metadata_or_insert("_geo.lng")) - .ok_or(UserError::AttributeLimitReached)?; + Ok(()) +} - facet_fn(lat_fid, lat_meta, perm_json_p::Depth::OnBaseKey, &lat.into())?; - facet_fn(lng_fid, lng_meta, perm_json_p::Depth::OnBaseKey, &lng.into())?; - } +pub fn extract_geo_document<'doc>( + document: impl Document<'doc>, + external_document_id: &str, + field_id_map: &mut GlobalFieldsIdsMap, + asc_desc_fields: &HashSet, + facet_fn: &mut impl FnMut(FieldId, Metadata, perm_json_p::Depth, &Value) -> Result<()>, +) -> Result<()> { + if let Some(geo_value) = document.geo_field()? { + if let Some([lat, lng]) = extract_geo_coordinates(external_document_id, geo_value)? { + let ((lat_fid, lat_meta), (lng_fid, lng_meta)) = field_id_map + .id_with_metadata_or_insert("_geo.lat") + .zip(field_id_map.id_with_metadata_or_insert("_geo.lng")) + .ok_or(UserError::AttributeLimitReached)?; + + facet_fn(lat_fid, lat_meta, perm_json_p::Depth::OnBaseKey, &lat.into())?; + facet_fn(lng_fid, lng_meta, perm_json_p::Depth::OnBaseKey, &lng.into())?; } } From f690fa068631e8f324c37e1a7aeccb69d642288e Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 26 May 2025 09:46:14 +0200 Subject: [PATCH 038/292] feat: add macro_rules to factorize --- .../new/extract/faceted/extract_facets.rs | 207 ++++++------------ 1 file changed, 72 insertions(+), 135 deletions(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index aa7510863..241e0fd69 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -90,8 +90,48 @@ impl FacetedDocidsExtractor { let mut cached_sorter = context.data.borrow_mut_or_yield(); let mut del_add_facet_value = DelAddFacetValue::new(&context.doc_alloc); let docid = document_change.docid(); + + macro_rules! facet_fn_factory { + (del) => { + |fid: FieldId, meta: Metadata, depth: perm_json_p::Depth, value: &Value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_del_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_del, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + } + }; + (add) => { + |fid: FieldId, meta: Metadata, depth: perm_json_p::Depth, value: &Value| { + Self::facet_fn_with_options( + &context.doc_alloc, + cached_sorter.deref_mut(), + BalancedCaches::insert_add_u32, + &mut del_add_facet_value, + DelAddFacetValue::insert_add, + docid, + fid, + meta, + filterable_attributes, + depth, + value, + ) + } + }; + } + match document_change { DocumentChange::Deletion(inner) => { + let mut del = facet_fn_factory!(del); + extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), @@ -100,21 +140,7 @@ impl FacetedDocidsExtractor { sortable_fields, asc_desc_fields, distinct_field, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_del_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_del, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, + &mut del, )?; if is_geo_enabled { @@ -123,21 +149,7 @@ impl FacetedDocidsExtractor { inner.external_document_id(), new_fields_ids_map.deref_mut(), asc_desc_fields, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_del_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_del, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, + &mut del, )?; } } @@ -160,6 +172,9 @@ impl FacetedDocidsExtractor { inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)?; if has_changed { + // 1. Delete old facet values + let mut del = facet_fn_factory!(del); + extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), @@ -168,23 +183,21 @@ impl FacetedDocidsExtractor { sortable_fields, asc_desc_fields, distinct_field, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_del_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_del, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, + &mut del, )?; + if is_geo_enabled && has_changed_for_geo_fields { + extract_geo_document( + inner.current(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + asc_desc_fields, + &mut del, + )?; + } + + let mut add = facet_fn_factory!(add); + extract_document_facets( inner.merged(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), @@ -193,71 +206,23 @@ impl FacetedDocidsExtractor { sortable_fields, asc_desc_fields, distinct_field, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_add_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_add, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, - )?; - } - - if is_geo_enabled && has_changed_for_geo_fields{ - extract_geo_document( - inner.current(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), - new_fields_ids_map.deref_mut(), - asc_desc_fields, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_del_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_del, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, + &mut add, )?; - extract_geo_document( - inner.merged(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), - new_fields_ids_map.deref_mut(), - asc_desc_fields, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_add_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_add, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, - )?; + if is_geo_enabled && has_changed_for_geo_fields { + extract_geo_document( + inner.merged(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + asc_desc_fields, + &mut add, + )?; + } } } DocumentChange::Insertion(inner) => { + let mut add = facet_fn_factory!(add); + extract_document_facets( inner.inserted(), inner.external_document_id(), @@ -266,21 +231,7 @@ impl FacetedDocidsExtractor { sortable_fields, asc_desc_fields, distinct_field, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_add_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_add, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, + &mut add, )?; if is_geo_enabled { extract_geo_document( @@ -288,21 +239,7 @@ impl FacetedDocidsExtractor { inner.external_document_id(), new_fields_ids_map.deref_mut(), asc_desc_fields, - &mut |fid, meta, depth, value| { - Self::facet_fn_with_options( - &context.doc_alloc, - cached_sorter.deref_mut(), - BalancedCaches::insert_add_u32, - &mut del_add_facet_value, - DelAddFacetValue::insert_add, - docid, - fid, - meta, - filterable_attributes, - depth, - value, - ) - }, + &mut add, )?; } } From 95821d0bdebed6e9762183ddd46cce6d4c453adb Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 26 May 2025 10:07:13 +0200 Subject: [PATCH 039/292] refactor: update macro --- .../update/new/extract/faceted/extract_facets.rs | 16 +++++++--------- .../update/new/extract/faceted/facet_document.rs | 1 - 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index 241e0fd69..de0edc164 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -91,7 +91,8 @@ impl FacetedDocidsExtractor { let mut del_add_facet_value = DelAddFacetValue::new(&context.doc_alloc); let docid = document_change.docid(); - macro_rules! facet_fn_factory { + // Macro expanding to an insertion/deletion facet fn + macro_rules! facet_fn { (del) => { |fid: FieldId, meta: Metadata, depth: perm_json_p::Depth, value: &Value| { Self::facet_fn_with_options( @@ -130,7 +131,7 @@ impl FacetedDocidsExtractor { match document_change { DocumentChange::Deletion(inner) => { - let mut del = facet_fn_factory!(del); + let mut del = facet_fn!(del); extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, @@ -148,7 +149,6 @@ impl FacetedDocidsExtractor { inner.current(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), new_fields_ids_map.deref_mut(), - asc_desc_fields, &mut del, )?; } @@ -173,7 +173,7 @@ impl FacetedDocidsExtractor { if has_changed { // 1. Delete old facet values - let mut del = facet_fn_factory!(del); + let mut del = facet_fn!(del); extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, @@ -191,12 +191,12 @@ impl FacetedDocidsExtractor { inner.current(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), new_fields_ids_map.deref_mut(), - asc_desc_fields, &mut del, )?; } - let mut add = facet_fn_factory!(add); + // 2. Insert new facet values + let mut add = facet_fn!(add); extract_document_facets( inner.merged(rtxn, index, context.db_fields_ids_map)?, @@ -214,14 +214,13 @@ impl FacetedDocidsExtractor { inner.merged(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), new_fields_ids_map.deref_mut(), - asc_desc_fields, &mut add, )?; } } } DocumentChange::Insertion(inner) => { - let mut add = facet_fn_factory!(add); + let mut add = facet_fn!(add); extract_document_facets( inner.inserted(), @@ -238,7 +237,6 @@ impl FacetedDocidsExtractor { inner.inserted(), inner.external_document_id(), new_fields_ids_map.deref_mut(), - asc_desc_fields, &mut add, )?; } diff --git a/crates/milli/src/update/new/extract/faceted/facet_document.rs b/crates/milli/src/update/new/extract/faceted/facet_document.rs index 30a5c462e..68bc98b64 100644 --- a/crates/milli/src/update/new/extract/faceted/facet_document.rs +++ b/crates/milli/src/update/new/extract/faceted/facet_document.rs @@ -108,7 +108,6 @@ pub fn extract_geo_document<'doc>( document: impl Document<'doc>, external_document_id: &str, field_id_map: &mut GlobalFieldsIdsMap, - asc_desc_fields: &HashSet, facet_fn: &mut impl FnMut(FieldId, Metadata, perm_json_p::Depth, &Value) -> Result<()>, ) -> Result<()> { if let Some(geo_value) = document.geo_field()? { From f54b57e5be33258cb8ecd024626bd054f48355c2 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 26 May 2025 13:39:15 +0300 Subject: [PATCH 040/292] Use a Regex in insta dynamic redaction to replace Uuids with [uuid] (cherry picked from commit f8b8c6ab71a28052cf9b271ca8aa5d4175f9e8f9) Signed-off-by: Martin Tzvetanov Grigorov --- Cargo.lock | 2646 +++++++++++---------- crates/meili-snap/Cargo.toml | 1 + crates/meili-snap/src/lib.rs | 21 + crates/meilisearch/src/error.rs | 10 +- crates/meilisearch/tests/search/errors.rs | 2 +- 5 files changed, 1399 insertions(+), 1281 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b23f7e83..c73af51d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,11 +4,11 @@ version = 4 [[package]] name = "actix-codec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "bytes", "futures-core", "futures-sink", @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "actix-cors" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" +checksum = "daa239b93927be1ff123eebada5a3ff23e89f0124ccb8609234e5103d5a5ae6d" dependencies = [ "actix-utils", "actix-web", @@ -36,27 +36,27 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" +checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-tls", "actix-utils", - "ahash 0.8.11", "base64 0.22.1", - "bitflags 2.9.0", - "brotli", + "bitflags 2.9.1", + "brotli 8.0.1", "bytes", "bytestring", "derive_more", "encoding_rs", "flate2", + "foldhash", "futures-core", "h2 0.3.26", - "http 0.2.11", + "http 0.2.12", "httparse", "httpdate", "itoa", @@ -65,7 +65,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.9.1", "sha1", "smallvec", "tokio", @@ -80,7 +80,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -91,7 +91,7 @@ checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", "cfg-if", - "http 0.2.11", + "http 0.2.12", "regex-lite", "serde", "tracing", @@ -110,30 +110,28 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.2.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" dependencies = [ "actix-rt", "actix-service", "actix-utils", "futures-core", "futures-util", - "mio 0.8.11", - "num_cpus", - "socket2 0.4.9", + "mio", + "socket2", "tokio", "tracing", ] [[package]] name = "actix-service" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" dependencies = [ "futures-core", - "paste", "pin-project-lite", ] @@ -168,9 +166,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.9.0" +version = "4.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" +checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" dependencies = [ "actix-codec", "actix-http", @@ -182,13 +180,13 @@ dependencies = [ "actix-tls", "actix-utils", "actix-web-codegen", - "ahash 0.8.11", "bytes", "bytestring", "cfg-if", "cookie", "derive_more", "encoding_rs", + "foldhash", "futures-core", "futures-util", "impl-more", @@ -203,8 +201,9 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.5", + "socket2", "time", + "tracing", "url", ] @@ -217,30 +216,30 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "addr2line" -version = "0.20.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aes" version = "0.8.4" @@ -258,20 +257,20 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "const-random", - "getrandom 0.2.15", + "getrandom 0.3.3", "once_cell", "version_check", "zerocopy", @@ -315,15 +314,16 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] @@ -335,37 +335,38 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "once_cell_polyfill", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" dependencies = [ "backtrace", ] @@ -387,9 +388,9 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "arroy" @@ -405,11 +406,11 @@ dependencies = [ "nohash", "ordered-float", "page_size", - "rand", + "rand 0.8.5", "rayon", "roaring", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "tracing", ] @@ -425,13 +426,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -442,23 +443,23 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.2", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -491,15 +492,15 @@ dependencies = [ "anyhow", "bumpalo", "bytes", - "convert_case 0.6.0", + "convert_case", "criterion", "csv", "flate2", "memmap2", "milli", "mimalloc", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "reqwest", "roaring", "serde_json", @@ -536,7 +537,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.13.0", @@ -545,7 +546,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -582,9 +583,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -621,9 +622,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" dependencies = [ "borsh-derive", "cfg_aliases", @@ -631,16 +632,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", - "syn_derive", + "syn 2.0.101", ] [[package]] @@ -651,14 +651,35 @@ checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor", + "brotli-decompressor 4.0.3", +] + +[[package]] +name = "brotli" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 5.0.0", ] [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -666,9 +687,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -686,9 +707,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" dependencies = [ "allocator-api2", "serde", @@ -703,7 +724,7 @@ dependencies = [ "allocator-api2", "bitpacking", "bumpalo", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", "serde_json", ] @@ -743,15 +764,15 @@ dependencies = [ [[package]] name = "bytecount" -version = "0.6.3" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ "bytemuck_derive", ] @@ -764,7 +785,7 @@ checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -775,15 +796,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bytestring" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" dependencies = [ "bytes", ] @@ -809,55 +830,55 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "candle-core" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "855dfedff437d2681d68e1f34ae559d88b0dd84aa5a6b63f2c8e75ebdd875bbf" +checksum = "06ccf5ee3532e66868516d9b315f73aec9f34ea1a37ae98514534d458915dbf1" dependencies = [ "byteorder", "candle-kernels", "cudarc", - "gemm", - "half 2.4.1", + "gemm 0.17.1", + "half", "memmap2", "num-traits", "num_cpus", - "rand", + "rand 0.9.1", "rand_distr", "rayon", "safetensors", "thiserror 1.0.69", "ug", "ug-cuda", - "yoke", + "yoke 0.7.5", "zip 1.1.4", ] [[package]] name = "candle-kernels" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53343628fa470b7075c28c589b98735b4220b464e37ddbb8e117040e199f4787" +checksum = "a10885bd902fad1b8518ba2b22369aaed88a3d94e123533ad3ca73db33b1c8ca" dependencies = [ "bindgen_cuda", ] [[package]] name = "candle-nn" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd3c6b2ee0dfd64af12ae5b07e4b7c517898981cdaeffcb10b71d7dd5c8f359" +checksum = "be1160c3b63f47d40d91110a3e1e1e566ae38edddbbf492a60b40ffc3bc1ff38" dependencies = [ "candle-core", - "half 2.4.1", + "half", "num-traits", "rayon", "safetensors", @@ -867,16 +888,16 @@ dependencies = [ [[package]] name = "candle-transformers" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4270cc692c4a3df2051c2e8c3c4da3a189746af7ca3a547b99ecd335582b92e1" +checksum = "94a0900d49f8605e0e7e6693a1f560e6271279de98e5fa369e7abf3aac245020" dependencies = [ "byteorder", "candle-core", "candle-nn", "fancy-regex", "num-traits", - "rand", + "rand 0.9.1", "rayon", "serde", "serde_json", @@ -886,25 +907,25 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror 2.0.9", + "thiserror 2.0.12", ] [[package]] @@ -925,9 +946,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" dependencies = [ "jobserver", "libc", @@ -976,9 +997,9 @@ dependencies = [ [[package]] name = "charabia" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650d52f87a36472ea1c803dee49d6bfd23d426efa9363e2f4c4a0e6a236d3407" +checksum = "4da3b398d57d5526189869b32ac0b4f7fb436f490f47a2a19685cee634df72d2" dependencies = [ "aho-corasick", "csv", @@ -998,9 +1019,9 @@ dependencies = [ [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -1009,18 +1030,18 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", - "half 1.8.2", + "half", ] [[package]] @@ -1035,9 +1056,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -1046,9 +1067,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.24" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9560b07a799281c7e0958b9296854d6fafd4c5f31444a7e5bb1ad6dde5ccf1bd" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -1056,9 +1077,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.24" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874e0dd3eb68bf99058751ac9712f622e61e6f393a94f7128fa26e3f02f5c7cd" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -1068,14 +1089,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1086,9 +1107,9 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "color-spantrace" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" dependencies = [ "once_cell", "owo-colors", @@ -1098,9 +1119,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "concat-arrays" @@ -1115,15 +1136,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", + "once_cell", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.59.0", ] [[package]] @@ -1141,22 +1162,16 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "tiny-keccak", ] [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -1185,19 +1200,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "cpufeatures" -version = "0.2.12" +name = "core2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -1264,9 +1288,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1283,24 +1307,24 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -1326,20 +1350,20 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] [[package]] name = "cudarc" -version = "0.12.2" +version = "0.13.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd76de2aa3a7bdb9a65941ea5a3c688d941688f736a81b2fc5beb88747a7f25" +checksum = "486c221362668c63a1636cfa51463b09574433b39029326cff40864b3ba12b6e" dependencies = [ - "half 2.4.1", + "half", "libloading", ] @@ -1355,12 +1379,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] @@ -1379,16 +1403,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1404,15 +1428,21 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core 0.20.10", + "darling_core 0.20.11", "quote", - "syn 2.0.87", + "syn 2.0.101", ] +[[package]] +name = "dary_heap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728" + [[package]] name = "deadpool" version = "0.10.0" @@ -1448,9 +1478,9 @@ checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -1464,7 +1494,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1503,10 +1533,10 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling 0.20.10", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1526,20 +1556,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core 0.20.2", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ - "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version", - "syn 1.0.109", + "syn 2.0.101", + "unicode-xid", ] [[package]] @@ -1565,10 +1603,10 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aadef696fce456c704f10186def1bdc0a40e646c9f4f18cf091477acadb731d8" dependencies = [ - "convert_case 0.6.0", + "convert_case", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1632,15 +1670,9 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "doxygen-rs" version = "0.4.2" @@ -1657,7 +1689,7 @@ dependencies = [ "anyhow", "big_s", "flate2", - "http 1.2.0", + "http 1.3.1", "maplit", "meili-snap", "meilisearch-types", @@ -1668,7 +1700,7 @@ dependencies = [ "serde_json", "tar", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tracing", "uuid", @@ -1685,19 +1717,28 @@ dependencies = [ ] [[package]] -name = "either" -version = "1.13.0" +name = "dyn-stack" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "490bd48eb68fffcfed519b4edbfd82c69cbe741d175b84f0e0cbe8c57cbe0bdd" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" dependencies = [ "serde", ] [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding" @@ -1765,9 +1806,9 @@ checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -1783,14 +1824,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1810,23 +1851,23 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1857,21 +1898,21 @@ name = "file-store" version = "1.15.0" dependencies = [ "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "tracing", "uuid", ] [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -1886,12 +1927,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.2", + "miniz_oxide", ] [[package]] @@ -1919,9 +1960,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" @@ -2000,7 +2041,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -2063,7 +2104,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce20bbb48248608ba4908b45fe36e17e40f56f8c6bb385ecf5d3c4a1e8b05a22" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "debugid", "fxhash", "serde", @@ -2077,17 +2118,37 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ab24cc62135b40090e31a76a9b2766a501979f3070fa27f689c27ec04377d32" dependencies = [ - "dyn-stack", - "gemm-c32", - "gemm-c64", - "gemm-common", - "gemm-f16", - "gemm-f32", - "gemm-f64", + "dyn-stack 0.10.0", + "gemm-c32 0.17.1", + "gemm-c64 0.17.1", + "gemm-common 0.17.1", + "gemm-f16 0.17.1", + "gemm-f32 0.17.1", + "gemm-f64 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-c32 0.18.2", + "gemm-c64 0.18.2", + "gemm-common 0.18.2", + "gemm-f16 0.18.2", + "gemm-f32 0.18.2", + "gemm-f64 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2097,12 +2158,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9c030d0b983d1e34a546b86e08f600c11696fde16199f971cd46c12e67512c0" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2112,12 +2188,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbb5f2e79fefb9693d18e1066a557b4546cd334b226beadc68b11a8f9431852a" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2128,17 +2219,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2e7ea062c987abcd8db95db917b4ffb4ecdfd0668471d8dc54734fdff2354e8" dependencies = [ "bytemuck", - "dyn-stack", - "half 2.4.1", + "dyn-stack 0.10.0", + "half", "num-complex", "num-traits", "once_cell", "paste", - "pulp", - "raw-cpuid", + "pulp 0.18.22", + "raw-cpuid 10.7.0", "rayon", "seq-macro", - "sysctl", + "sysctl 0.5.5", +] + +[[package]] +name = "gemm-common" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3" +dependencies = [ + "bytemuck", + "dyn-stack 0.13.0", + "half", + "libm", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp 0.21.5", + "raw-cpuid 11.5.0", + "rayon", + "seq-macro", + "sysctl 0.6.0", ] [[package]] @@ -2147,14 +2259,32 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ca4c06b9b11952071d317604acb332e924e817bd891bec8dfb494168c7cedd4" dependencies = [ - "dyn-stack", - "gemm-common", - "gemm-f32", - "half 2.4.1", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "gemm-f32 0.17.1", + "half", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f16" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "gemm-f32 0.18.2", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "rayon", "seq-macro", ] @@ -2165,12 +2295,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9a69f51aaefbd9cf12d18faf273d3e982d9d711f60775645ed5c8047b4ae113" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2180,12 +2325,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa397a48544fadf0b81ec8741e5c0fba0043008113f71f2034def1935645d2b0" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2207,9 +2367,9 @@ checksum = "36d244a08113319b5ebcabad2b8b7925732d15eec46d7e7ac3c11734f3b7a6ad" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -2220,31 +2380,31 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.13.3+wasi-0.2.2", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", "wasm-bindgen", - "windows-targets 0.52.6", ] [[package]] name = "gimli" -version = "0.27.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git2" -version = "0.19.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "libgit2-sys", "log", @@ -2253,9 +2413,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "grenad" @@ -2281,7 +2441,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.11", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -2291,16 +2451,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.2.0", + "http 1.3.1", "indexmap", "slab", "tokio", @@ -2310,21 +2470,15 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "bytemuck", "cfg-if", "crunchy", "num-traits", - "rand", + "rand 0.9.1", "rand_distr", ] @@ -2348,19 +2502,19 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "allocator-api2", ] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -2378,12 +2532,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -2396,7 +2544,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a56c94661ddfb51aa9cdfbf102cfcc340aa69267f95ebccc4af08d7c530d393" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "heed-traits", "heed-types", @@ -2435,9 +2583,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -2451,10 +2599,10 @@ version = "0.3.2" source = "git+https://github.com/dureuill/hf-hub.git?branch=rust_tls#88d4f11cb9fa079f2912bacb96f5080b16825ce8" dependencies = [ "dirs", - "http 1.2.0", + "http 1.3.1", "indicatif", "log", - "rand", + "rand 0.8.5", "serde", "serde_json", "thiserror 1.0.69", @@ -2472,9 +2620,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -2483,9 +2631,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -2494,50 +2642,50 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http 1.3.1", ] [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", - "http 1.2.0", + "futures-core", + "http 1.3.1", "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.4.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", - "http 1.2.0", + "h2 0.4.10", + "http 1.3.1", "http-body", "httparse", "httpdate", @@ -2550,12 +2698,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ - "futures-util", - "http 1.2.0", + "http 1.3.1", "hyper", "hyper-util", "rustls", @@ -2563,23 +2710,24 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 1.0.0", ] [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "hyper", + "libc", "pin-project-lite", - "socket2 0.5.5", + "socket2", "tokio", "tower-service", "tracing", @@ -2587,21 +2735,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", - "yoke", + "potential_utf", + "yoke 0.8.0", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -2610,31 +2759,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -2642,67 +2771,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", - "yoke", + "yoke 0.8.0", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -2722,9 +2838,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -2732,9 +2848,32 @@ dependencies = [ [[package]] name = "impl-more" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" + +[[package]] +name = "include-flate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df49c16750695486c1f34de05da5b7438096156466e7f76c38fcdf285cf0113e" +dependencies = [ + "include-flate-codegen", + "lazy_static", + "libflate", +] + +[[package]] +name = "include-flate-codegen" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c5b246c6261be723b85c61ecf87804e8ea4a35cb68be0ff282ed84b95ffe7d7" +dependencies = [ + "libflate", + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] name = "index-scheduler" @@ -2746,7 +2885,7 @@ dependencies = [ "bumpalo", "bumparaw-collections", "byte-unit", - "convert_case 0.6.0", + "convert_case", "crossbeam-channel", "csv", "derive_builder 0.20.2", @@ -2768,7 +2907,7 @@ dependencies = [ "serde_json", "synchronoise", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tracing", "ureq", @@ -2777,33 +2916,33 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", ] [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", "unicode-width", + "web-time", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] @@ -2825,18 +2964,18 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "irg-kvariants" @@ -2851,15 +2990,21 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi 0.5.1", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -2907,31 +3052,41 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jieba-macros" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c676b32a471d3cfae8dac2ad2f8334cd52e53377733cca8c1fb0a5062fec192" +dependencies = [ + "phf_codegen", +] [[package]] name = "jieba-rs" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e2b0210dc78b49337af9e49d7ae41a39dceac6e5985613f1cf7763e2f76a25" +checksum = "6d1bcad6332969e4d48ee568d430e14ee6dea70740c2549d005d87677ebefb0c" dependencies = [ "cedarwood", - "derive_builder 0.20.2", "fxhash", + "include-flate", + "jieba-macros", "lazy_static", "phf", - "phf_codegen", "regex", ] [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] @@ -2955,11 +3110,11 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.3.0" +version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "js-sys", "pem", "ring", @@ -2979,9 +3134,9 @@ dependencies = [ [[package]] name = "kstring" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" dependencies = [ "serde", "static_assertions", @@ -3010,15 +3165,39 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libflate" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" +dependencies = [ + "core2", + "hashbrown 0.14.5", + "rle-decode-fast", +] [[package]] name = "libgit2-sys" -version = "0.17.0+1.8.1" +version = "0.18.1+1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" dependencies = [ "cc", "libc", @@ -3028,25 +3207,25 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] name = "libm" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.39" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" +checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" dependencies = [ "cc", "libc", @@ -3064,10 +3243,21 @@ dependencies = [ ] [[package]] -name = "libz-sys" -version = "1.1.15" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "libc", @@ -3077,155 +3267,52 @@ dependencies = [ [[package]] name = "lindera" -version = "0.32.3" +version = "0.42.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "832c220475557e3b44a46cad1862b57f010f0c6e93d771d0e628e08689c068b1" -dependencies = [ - "lindera-analyzer", - "lindera-core", - "lindera-dictionary", - "lindera-filter", - "lindera-tokenizer", -] - -[[package]] -name = "lindera-analyzer" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e26651714abf5167e6b6a80f5cdaa0cad41c5fcb84d8ba96bebafcb9029339" +checksum = "73b6ee48fa4ffaff0b34a0f56e8fe9e3a9f38ff097d7ffe11a189acac242efbf" dependencies = [ "anyhow", "bincode", "byteorder", - "encoding", + "csv", "kanaria", - "lindera-cc-cedict-builder", - "lindera-core", + "lindera-cc-cedict", "lindera-dictionary", - "lindera-filter", - "lindera-ipadic-builder", - "lindera-ko-dic-builder", - "lindera-tokenizer", - "lindera-unidic-builder", + "lindera-ipadic", + "lindera-ipadic-neologd", + "lindera-ko-dic", + "lindera-unidic", "once_cell", "regex", "serde", "serde_json", - "thiserror 1.0.69", + "serde_yaml", + "strum", + "strum_macros", "unicode-blocks", "unicode-normalization", "unicode-segmentation", "yada", ] -[[package]] -name = "lindera-assets" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb01f1ca53c1e642234c6c7fdb9ac664ad0c1ab9502f33e4200201bac7e6ce7" -dependencies = [ - "encoding", - "flate2", - "lindera-core", - "tar", - "ureq", -] - [[package]] name = "lindera-cc-cedict" -version = "0.32.3" +version = "0.42.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7618d9aa947fdd7c38eae2b79f0fd237ecb5067608f1363610ba20d20ab5a8" +checksum = "88fb51b5730fd63b1baf677fb19ce3f3f00616a3fbaf430f923b676dce5fab39" dependencies = [ "bincode", "byteorder", - "lindera-cc-cedict-builder", - "lindera-core", - "lindera-decompress", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-cc-cedict-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efdbcb809d81428935d601a78c94bfb39500749213f7320705f427a7a1d31aec" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", -] - -[[package]] -name = "lindera-compress" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac178afa2456dac469d3b1a2d7fbaf3e1ea796a1f52321e8ac29545a53c239c" -dependencies = [ - "anyhow", - "flate2", - "lindera-decompress", -] - -[[package]] -name = "lindera-core" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "649777465f48147ce593ab6db347e235e3af8f693a23f4437be94a1cdbdf5fdf" -dependencies = [ - "anyhow", - "bincode", - "byteorder", - "encoding_rs", - "log", - "once_cell", - "serde", - "thiserror 1.0.69", - "yada", -] - -[[package]] -name = "lindera-decompress" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3faaceb85e43ac250021866c6db3cdc9997b44b3d3ea498594d04edc91fc45" -dependencies = [ - "anyhow", - "flate2", - "serde", + "tokio", ] [[package]] name = "lindera-dictionary" -version = "0.32.3" +version = "0.42.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e15b2d2d8a4ad45f2e373a084931cf3dfbde15f124044e2436bb920af3366c" -dependencies = [ - "anyhow", - "bincode", - "byteorder", - "lindera-cc-cedict", - "lindera-cc-cedict-builder", - "lindera-core", - "lindera-ipadic", - "lindera-ipadic-builder", - "lindera-ipadic-neologd", - "lindera-ipadic-neologd-builder", - "lindera-ko-dic", - "lindera-ko-dic-builder", - "lindera-unidic", - "lindera-unidic-builder", - "serde", - "strum", - "strum_macros", -] - -[[package]] -name = "lindera-dictionary-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59802949110545b59b663917ed3fd55dc3b3a8cde6bd20137d7fe24372cfb9aa" +checksum = "d5dafa44610860d21f66dbfee1ad387fd127824b204137b540ada4c1a744b19c" dependencies = [ "anyhow", "bincode", @@ -3235,157 +3322,70 @@ dependencies = [ "encoding", "encoding_rs", "encoding_rs_io", + "flate2", "glob", - "lindera-compress", - "lindera-core", - "lindera-decompress", "log", - "yada", -] - -[[package]] -name = "lindera-filter" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1320f118c3fc9e897f4ebfc16864e5ef8c0b06ba769c0a50e53f193f9d682bf8" -dependencies = [ - "anyhow", - "csv", - "kanaria", - "lindera-cc-cedict-builder", - "lindera-core", - "lindera-dictionary", - "lindera-ipadic-builder", - "lindera-ko-dic-builder", - "lindera-unidic-builder", + "md5", "once_cell", - "regex", + "rand 0.9.1", + "reqwest", "serde", - "serde_json", - "unicode-blocks", - "unicode-normalization", - "unicode-segmentation", + "tar", + "thiserror 2.0.12", + "tokio", "yada", ] [[package]] name = "lindera-ipadic" -version = "0.32.3" +version = "0.42.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4731bf3730f1f38266d7ee9bca7d460cd336645c9dfd4e6a1082e58ab1e993" +checksum = "d273907fdf1c14a8244a370afd7ac79126337ad450d25888b1613aee17b1262a" dependencies = [ "bincode", "byteorder", - "lindera-core", - "lindera-decompress", - "lindera-ipadic-builder", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-ipadic-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "309966c12e682f67205c3cd3c8dc55bbdcd1eb3b5c7c5cb41fb8acd18906d340" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", + "tokio", ] [[package]] name = "lindera-ipadic-neologd" -version = "0.32.3" +version = "0.42.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90e919b4cfb9962d24ee1e1d50a7c163bbf356376495ad66d1996e20b9f9e44" +checksum = "9d4371fbd6dc3ac5cc76990ed41061c553635f67953771159e4061d7f568d14f" dependencies = [ "bincode", "byteorder", - "lindera-core", - "lindera-decompress", - "lindera-ipadic-neologd-builder", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-ipadic-neologd-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e517df0d501f9f8bf3126da20fc8cb9a5e37921e0eec1824d7a62f096463e02" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", + "tokio", ] [[package]] name = "lindera-ko-dic" -version = "0.32.3" +version = "0.42.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c6da4e68bc8b452a54b96d65361ebdceb4b6f36ecf262425c0e1f77960ae82" +checksum = "03f35d8e54e6d5f73e9f76da0fedfa336fa60a6d2ac7f7dcc8bcd15e338db291" dependencies = [ "bincode", "byteorder", - "lindera-assets", - "lindera-core", - "lindera-decompress", - "lindera-ko-dic-builder", - "once_cell", -] - -[[package]] -name = "lindera-ko-dic-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc95884cc8f6dfb176caf5991043a4acf94c359215bbd039ea765e00454f271" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", -] - -[[package]] -name = "lindera-tokenizer" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122042e1232a55c3604692445952a134e523822e9b4b9ab32a53ff890037ad4" -dependencies = [ - "bincode", - "lindera-core", "lindera-dictionary", "once_cell", - "serde", - "serde_json", + "tokio", ] [[package]] name = "lindera-unidic" -version = "0.32.3" +version = "0.42.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffae1fb2f2614abdcb50f99b138476dbac19862ffa57bfdc9c7b5d5b22a90c" +checksum = "661aa828cf6af7ccd1c0c1142c087fd048af5f83776ccec6af9f9c56448bc626" dependencies = [ "bincode", "byteorder", - "lindera-assets", - "lindera-core", - "lindera-decompress", - "lindera-unidic-builder", + "lindera-dictionary", "once_cell", -] - -[[package]] -name = "lindera-unidic-builder" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe50055327712ebd1bcc74b657cf78c728a78b9586e3f99d5dd0b6a0be221c5d" -dependencies = [ - "anyhow", - "lindera-core", - "lindera-decompress", - "lindera-dictionary-builder", + "tokio", ] [[package]] @@ -3396,17 +3396,22 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "liquid" -version = "0.26.9" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cdcc72b82748f47c2933c172313f5a9aea5b2c4eb3fa4c66b4ea55bb60bb4b1" +checksum = "2a494c3f9dad3cb7ed16f1c51812cbe4b29493d6c2e5cd1e2b87477263d9534d" dependencies = [ - "doc-comment", "liquid-core", "liquid-derive", "liquid-lib", @@ -3415,15 +3420,14 @@ dependencies = [ [[package]] name = "liquid-core" -version = "0.26.9" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2752e978ffc53670f3f2e8b3ef09f348d6f7b5474a3be3f8a5befe5382e4effb" +checksum = "fc623edee8a618b4543e8e8505584f4847a4e51b805db1af6d9af0a3395d0d57" dependencies = [ "anymap2", - "itertools 0.13.0", + "itertools 0.14.0", "kstring", "liquid-derive", - "num-traits", "pest", "pest_derive", "regex", @@ -3433,24 +3437,23 @@ dependencies = [ [[package]] name = "liquid-derive" -version = "0.26.8" +version = "0.26.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b51f1d220e3fa869e24cfd75915efe3164bd09bb11b3165db3f37f57bf673e3" +checksum = "de66c928222984aea59fcaed8ba627f388aaac3c1f57dcb05cc25495ef8faefe" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "liquid-lib" -version = "0.26.9" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b1a298d3d2287ee5b1e43840d885b8fdfc37d3f4e90d82aacfd04d021618da" +checksum = "9befeedd61f5995bc128c571db65300aeb50d62e4f0542c88282dbcb5f72372a" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "liquid-core", - "once_cell", "percent-encoding", "regex", "time", @@ -3459,9 +3462,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lmdb-master-sys" @@ -3476,43 +3479,36 @@ dependencies = [ [[package]] name = "local-channel" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" dependencies = [ "futures-core", "futures-sink", - "futures-util", "local-waker", ] [[package]] name = "local-waker" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" @@ -3520,9 +3516,15 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lzma-rs" version = "0.3.0" @@ -3569,7 +3571,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -3591,6 +3593,7 @@ dependencies = [ "insta", "md5", "once_cell", + "regex-lite", ] [[package]] @@ -3604,7 +3607,7 @@ dependencies = [ "actix-web", "anyhow", "async-trait", - "brotli", + "brotli 6.0.0", "bstr", "build-info", "byte-unit", @@ -3645,7 +3648,7 @@ dependencies = [ "pin-project-lite", "platform-dirs", "prometheus", - "rand", + "rand 0.8.5", "rayon", "regex", "reqwest", @@ -3659,7 +3662,7 @@ dependencies = [ "serde_urlencoded", "sha-1", "sha2", - "siphasher 1.0.1", + "siphasher", "slice-group-by", "static-files", "sysinfo", @@ -3667,7 +3670,7 @@ dependencies = [ "temp-env", "tempfile", "termcolor", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tokio", "toml", @@ -3682,7 +3685,7 @@ dependencies = [ "uuid", "wiremock", "yaup", - "zip 2.3.0", + "zip 2.4.2", ] [[package]] @@ -3694,12 +3697,12 @@ dependencies = [ "hmac", "maplit", "meilisearch-types", - "rand", + "rand 0.8.5", "roaring", "serde", "serde_json", "sha2", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "uuid", ] @@ -3712,7 +3715,7 @@ dependencies = [ "anyhow", "bumpalo", "bumparaw-collections", - "convert_case 0.6.0", + "convert_case", "csv", "deserr", "either", @@ -3725,13 +3728,13 @@ dependencies = [ "memmap2", "milli", "roaring", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "serde-cs", "serde_json", "tar", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "tokio", "utoipa", @@ -3792,7 +3795,7 @@ dependencies = [ "candle-transformers", "charabia", "concat-arrays", - "convert_case 0.6.0", + "convert_case", "crossbeam-channel", "csv", "deserr", @@ -3805,7 +3808,7 @@ dependencies = [ "fxhash", "geoutils", "grenad", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "heed", "hf-hub", "indexmap", @@ -3824,13 +3827,13 @@ dependencies = [ "obkv", "once_cell", "ordered-float", - "rand", + "rand 0.8.5", "rayon", "rayon-par-bridge", "rhai", "roaring", "rstar", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "serde_json", "slice-group-by", @@ -3838,7 +3841,7 @@ dependencies = [ "smallvec", "smartstring", "tempfile", - "thiserror 2.0.9", + "thiserror 2.0.12", "thread_local", "tiktoken-rs", "time", @@ -3853,9 +3856,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.43" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" +checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" dependencies = [ "libmimalloc-sys", ] @@ -3868,9 +3871,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -3884,50 +3887,30 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "monostate" -version = "0.1.9" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f370ae88093ec6b11a710dec51321a61d420fafd1bad6e30d01bd9c920e8ee" +checksum = "aafe1be9d0c75642e3e50fedc7ecadf1ef1cbce6eb66462153fc44245343fbee" dependencies = [ "monostate-impl", "serde", @@ -3935,13 +3918,13 @@ dependencies = [ [[package]] name = "monostate-impl" -version = "0.1.9" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "371717c0a5543d6a800cac822eac735aa7d2d2fbb41002e9856a4089532dbdce" +checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -4095,23 +4078,23 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -4131,9 +4114,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.31.1" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -4146,17 +4129,23 @@ checksum = "ae4512a8f418ac322335255a72361b9ac927e106f4d7fe6ab4d8ac59cb01f7a9" [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "onig" -version = "6.4.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "libc", "once_cell", "onig_sys", @@ -4164,9 +4153,9 @@ dependencies = [ [[package]] name = "onig_sys" -version = "69.8.1" +version = "69.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" dependencies = [ "cc", "pkg-config", @@ -4174,9 +4163,9 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "option-ext" @@ -4201,9 +4190,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owo-colors" -version = "3.5.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" [[package]] name = "page_size" @@ -4227,22 +4216,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall", "smallvec", - "windows-targets 0.48.1", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "path-matchers" @@ -4271,11 +4260,11 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.3" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "serde", ] @@ -4295,19 +4284,20 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ - "thiserror 1.0.69", + "memchr", + "thiserror 2.0.12", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" dependencies = [ "pest", "pest_generator", @@ -4315,22 +4305,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "pest_meta" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ "once_cell", "pest", @@ -4339,9 +4329,9 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", "phf_shared", @@ -4349,9 +4339,9 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", @@ -4359,54 +4349,54 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher 0.3.11", + "siphasher", ] [[package]] name = "pin-project" -version = "1.1.4" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.4" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -4429,9 +4419,9 @@ checksum = "16f2611cd06a1ac239a0cea4521de9eb068a6ca110324ee00631aa68daa74fc0" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "platform-dirs" @@ -4444,9 +4434,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -4457,24 +4447,33 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "portable-atomic" -version = "1.5.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -4484,47 +4483,27 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "toml_edit 0.21.0", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -4535,10 +4514,10 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "hex", "procfs-core", - "rustix", + "rustix 0.38.44", ] [[package]] @@ -4547,7 +4526,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "hex", ] @@ -4565,7 +4544,7 @@ dependencies = [ "parking_lot", "procfs", "protobuf", - "thiserror 2.0.9", + "thiserror 2.0.12", ] [[package]] @@ -4610,9 +4589,9 @@ dependencies = [ [[package]] name = "pulp" -version = "0.18.9" +version = "0.18.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03457ac216146f43f921500bac4e892d5cd32b0479b929cbfc90f95cd6c599c2" +checksum = "a0a01a0dc67cf4558d279f0c25b0962bd08fc6dec0137699eae304103e882fe6" dependencies = [ "bytemuck", "libm", @@ -4621,61 +4600,89 @@ dependencies = [ ] [[package]] -name = "quinn" -version = "0.11.2" +name = "pulp" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "reborrow", + "version_check", +] + +[[package]] +name = "quinn" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "rustls", - "thiserror 1.0.69", + "socket2", + "thiserror 2.0.12", "tokio", "tracing", + "web-time", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "rand", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.1", "ring", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "rustls", + "rustls-pki-types", "slab", - "thiserror 1.0.69", + "thiserror 2.0.12", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" dependencies = [ + "cfg_aliases", "libc", "once_cell", - "socket2 0.5.5", + "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -4689,8 +4696,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -4700,7 +4717,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -4709,17 +4736,26 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", ] [[package]] name = "rand_distr" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" dependencies = [ "num-traits", - "rand", + "rand 0.9.1", ] [[package]] @@ -4731,6 +4767,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "raw-cpuid" +version = "11.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +dependencies = [ + "bitflags 2.9.1", +] + [[package]] name = "rayon" version = "1.10.0" @@ -4779,30 +4824,21 @@ checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", - "redox_syscall 0.2.16", + "getrandom 0.2.16", + "libredox", "thiserror 1.0.69", ] @@ -4852,16 +4888,16 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.12" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "http-body-util", "hyper", @@ -4892,7 +4928,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", + "webpki-roots 0.26.11", "windows-registry", ] @@ -4901,8 +4937,8 @@ name = "rhai" version = "1.20.0" source = "git+https://github.com/rhaiscript/rhai?rev=ef3df63121d27aacd838f366f2b83fd65f20a1e4#ef3df63121d27aacd838f366f2b83fd65f20a1e4" dependencies = [ - "ahash 0.8.11", - "bitflags 2.9.0", + "ahash 0.8.12", + "bitflags 2.9.1", "instant", "num-traits", "once_cell", @@ -4920,7 +4956,7 @@ source = "git+https://github.com/rhaiscript/rhai?rev=ef3df63121d27aacd838f366f2b dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -4931,7 +4967,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -4939,9 +4975,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -4957,9 +4993,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", @@ -4967,10 +5003,16 @@ dependencies = [ ] [[package]] -name = "roaring" -version = "0.10.10" +name = "rle-decode-fast" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a652edd001c53df0b3f96a36a8dc93fce6866988efc16808235653c6bcac8bf2" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + +[[package]] +name = "roaring" +version = "0.10.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e8d2cfa184d94d0726d650a9f4a1be7f9b76ac9fdb954219878dc00c1c1e7b" dependencies = [ "bytemuck", "byteorder", @@ -4991,15 +5033,15 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" dependencies = [ "arrayvec", "borsh", "bytes", "num-traits", - "rand", + "rand 0.8.5", "rkyv", "serde", "serde_json", @@ -5007,9 +5049,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -5019,37 +5061,41 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustix" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "semver", + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", ] [[package]] name = "rustix" -version = "0.38.41" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.52.0", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "log", "once_cell", @@ -5071,15 +5117,19 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "web-time", + "zeroize", +] [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -5088,21 +5138,21 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "safetensors" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d980e6bfb34436fb0a81e42bc41af43f11805bbbca443e7f68e9faaabe669ed" +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6" dependencies = [ "serde", "serde_json", @@ -5131,32 +5181,32 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "segment" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd0f21b6eb87a45a7cce06075a29ccdb42658a6eb84bf40c8fc179479630609" +checksum = "971369158e31ad10bd73b558625f99de39554a2f00c2ff886a6796d950e69664" dependencies = [ "async-trait", "reqwest", "serde", "serde_json", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", ] [[package]] name = "semver" -version = "1.0.18" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "seq-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" @@ -5184,7 +5234,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5230,6 +5280,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha-1" version = "0.10.1" @@ -5254,9 +5317,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -5280,9 +5343,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -5295,34 +5358,28 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "simdutf8" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "2.2.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_asn1" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", - "thiserror 1.0.69", + "thiserror 2.0.12", "time", ] -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "siphasher" version = "1.0.1" @@ -5331,9 +5388,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -5356,9 +5413,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" dependencies = [ "serde", ] @@ -5377,22 +5434,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5464,31 +5511,31 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -5503,32 +5550,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -5544,13 +5579,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5559,7 +5594,21 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags 2.9.1", "byteorder", "enum-as-inner", "libc", @@ -5589,9 +5638,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.43" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", @@ -5609,16 +5658,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.2.15", + "getrandom 0.3.3", "once_cell", - "rustix", - "windows-sys 0.52.0", + "rustix 1.0.7", + "windows-sys 0.59.0", ] [[package]] @@ -5632,9 +5680,9 @@ dependencies = [ [[package]] name = "thin-vec" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" +checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" dependencies = [ "serde", ] @@ -5650,11 +5698,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.9" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.9", + "thiserror-impl 2.0.12", ] [[package]] @@ -5665,18 +5713,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "thiserror-impl" -version = "2.0.9" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5707,9 +5755,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -5724,15 +5772,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -5749,9 +5797,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -5769,9 +5817,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -5790,7 +5838,7 @@ dependencies = [ "aho-corasick", "derive_builder 0.12.0", "esaxx-rs", - "getrandom 0.2.15", + "getrandom 0.2.16", "itertools 0.12.1", "lazy_static", "log", @@ -5798,7 +5846,7 @@ dependencies = [ "monostate", "onig", "paste", - "rand", + "rand 0.8.5", "rayon", "rayon-cond", "regex", @@ -5814,18 +5862,18 @@ dependencies = [ [[package]] name = "tokio" -version = "1.43.1" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "492a604e2fd7f814268a378409e6c92b5525d747d10db9a229723f55a417958c" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.3", + "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", "windows-sys 0.52.0", ] @@ -5838,25 +5886,24 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -5867,49 +5914,45 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.22", + "toml_write", + "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "tower" version = "0.5.2" @@ -5951,9 +5994,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9f5c1aca50ebebf074ee665b9f99f2e84906dcf6b993a0d0090edb835166d" +checksum = "2340b7722695166c7fc9b3e3cd1166e7c74fedb9075b8f0c74d3822d2e41caf5" dependencies = [ "actix-web", "mutually_exclusive_features", @@ -5970,7 +6013,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -6049,21 +6092,21 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uell" @@ -6076,48 +6119,52 @@ dependencies = [ [[package]] name = "ug" -version = "0.0.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4eef2ebfc18c67a6dbcacd9d8a4d85e0568cc58c82515552382312c2730ea13" +checksum = "03719c61a91b51541f076dfdba45caacf750b230cefaa4b32d6f5411c3f7f437" dependencies = [ - "half 2.4.1", + "gemm 0.18.2", + "half", + "libloading", + "memmap2", "num", + "num-traits", + "num_cpus", + "rayon", + "safetensors", "serde", - "serde_json", "thiserror 1.0.69", + "tracing", + "yoke 0.7.5", ] [[package]] name = "ug-cuda" -version = "0.0.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4dcab280ad0ef3957e153a82dcad608c954d02cf253b695322f502d1f8902e" +checksum = "50758486d7941f8b0a636ba7e29455c07071f41590beac1fd307ec893e8db69a" dependencies = [ "cudarc", - "half 2.4.1", + "half", "serde", - "serde_json", "thiserror 1.0.69", "ug", ] [[package]] name = "unescaper" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" +checksum = "c01d12e3a56a4432a8b436f293c25f4808bdf9e9f9f98f9260bba1f1bc5a1f26" dependencies = [ - "thiserror 1.0.69", + "thiserror 2.0.12", ] [[package]] name = "unicase" -version = "2.6.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-blocks" @@ -6127,9 +6174,9 @@ checksum = "6b12e05d9e06373163a9bb6bb8c263c261b396643a99445fe6b9811fd376581b" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -6151,15 +6198,21 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -6167,6 +6220,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -6189,7 +6248,7 @@ dependencies = [ "serde_json", "socks", "url", - "webpki-roots", + "webpki-roots 0.26.11", ] [[package]] @@ -6210,17 +6269,11 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8_iter" @@ -6230,9 +6283,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utoipa" @@ -6255,7 +6308,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.87", + "syn 2.0.101", "uuid", ] @@ -6273,19 +6326,21 @@ dependencies = [ [[package]] name = "uuid" -version = "1.11.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -6295,9 +6350,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "9.0.2" +version = "9.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f25fc8f8f05df455c7941e87f093ad22522a9ff33d7a027774815acf6f0639" +checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" dependencies = [ "anyhow", "derive_builder 0.20.2", @@ -6307,9 +6362,9 @@ dependencies = [ [[package]] name = "vergen-git2" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e63e069d8749fead1e3bab7a9d79e8fb90516b2ec66fc2243a798ecdc1a31d7" +checksum = "4f6ee511ec45098eabade8a0750e76eec671e7fb2d9360c563911336bea9cac1" dependencies = [ "anyhow", "derive_builder 0.20.2", @@ -6322,9 +6377,9 @@ dependencies = [ [[package]] name = "vergen-lib" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c767e6751c09fc85cde58722cf2f1007e80e4c8d5a4321fc90d83dc54ca147" +checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" dependencies = [ "anyhow", "derive_builder 0.20.2", @@ -6333,9 +6388,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -6375,9 +6430,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -6404,18 +6459,19 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] @@ -6438,7 +6494,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6454,9 +6510,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -6467,9 +6523,19 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -6477,9 +6543,18 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.0", +] + +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" dependencies = [ "rustls-pki-types", ] @@ -6490,7 +6565,7 @@ version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "471d1c1645d361eb782a1650b1786a8fb58dd625e681a04c09f5ff7c8764a7b0" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", "once_cell", ] @@ -6512,11 +6587,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -6555,7 +6630,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -6566,18 +6641,24 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] -name = "windows-registry" -version = "0.2.0" +name = "windows-link" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result 0.2.0", + "windows-result 0.3.4", "windows-strings", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] @@ -6591,30 +6672,20 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.2.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", + "windows-link", ] [[package]] @@ -6623,7 +6694,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -6636,33 +6707,27 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.42.2" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.6", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -6674,7 +6739,7 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", @@ -6682,16 +6747,26 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" +name = "windows-targets" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" @@ -6700,16 +6775,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +name = "windows_aarch64_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" @@ -6718,16 +6793,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "windows_i686_gnu" -version = "0.42.2" +name = "windows_aarch64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" @@ -6735,6 +6810,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" @@ -6742,16 +6823,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "windows_i686_msvc" -version = "0.42.2" +name = "windows_i686_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" @@ -6760,16 +6841,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" +name = "windows_i686_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" @@ -6778,16 +6859,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +name = "windows_x86_64_gnu" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" @@ -6796,16 +6877,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +name = "windows_x86_64_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" @@ -6814,35 +6895,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winnow" -version = "0.5.40" +name = "windows_x86_64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.6.22" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] [[package]] name = "wiremock" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fff469918e7ca034884c7fd8f93fe27bacb7fcb599fd879df6c7b429a29b646" +checksum = "101681b74cd87b5899e87bcf5a64e83334dd313fcd3053ea72e6dba18928e301" dependencies = [ "assert-json-diff", "async-trait", "base64 0.22.1", "deadpool", "futures", - "http 1.2.0", + "http 1.3.1", "http-body-util", "hyper", "hyper-util", @@ -6857,24 +6935,18 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -6887,13 +6959,12 @@ dependencies = [ [[package]] name = "xattr" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "rustix 1.0.7", ] [[package]] @@ -6953,7 +7024,19 @@ checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", - "yoke-derive", + "yoke-derive 0.7.5", + "zerofrom", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.8.0", "zerofrom", ] @@ -6965,48 +7048,60 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "zerofrom" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", "synstructure", ] @@ -7027,29 +7122,40 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke 0.8.0", + "zerofrom", ] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ - "yoke", + "yoke 0.8.0", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -7069,9 +7175,9 @@ dependencies = [ [[package]] name = "zip" -version = "2.3.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e9a772a54b54236b9b744aaaf8d7be01b4d6e99725523cb82cb32d1c81b1d7" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" dependencies = [ "aes", "arbitrary", @@ -7082,14 +7188,14 @@ dependencies = [ "deflate64", "displaydoc", "flate2", - "getrandom 0.3.1", + "getrandom 0.3.3", "hmac", "indexmap", "lzma-rs", "memchr", "pbkdf2", "sha1", - "thiserror 2.0.9", + "thiserror 2.0.12", "time", "xz2", "zeroize", @@ -7099,41 +7205,39 @@ dependencies = [ [[package]] name = "zopfli" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] [[package]] name = "zstd" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.0" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", diff --git a/crates/meili-snap/Cargo.toml b/crates/meili-snap/Cargo.toml index 0c48ff824..b79960fdb 100644 --- a/crates/meili-snap/Cargo.toml +++ b/crates/meili-snap/Cargo.toml @@ -15,3 +15,4 @@ license.workspace = true insta = { version = "=1.39.0", features = ["json", "redactions"] } md5 = "0.7.0" once_cell = "1.20" +regex-lite = "0.1.6" diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index c467aef49..e8e605fec 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -4,9 +4,17 @@ use std::path::{Path, PathBuf}; use std::sync::Mutex; pub use insta; +use insta::internals::{Content, ContentPath}; use once_cell::sync::Lazy; +use regex_lite::{Regex, RegexBuilder}; static SNAPSHOT_NAMES: Lazy>> = Lazy::new(Mutex::default); +/// A regex to match UUIDs in messages, specifically looking for the UUID v4 format +static UUID_IN_MESSAGE_RE: Lazy = Lazy::new(|| { + RegexBuilder::new(r"(?.*)([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})(?.*)") + .case_insensitive(true) + .build().unwrap() +}); /// Return the md5 hash of the given string pub fn hash_snapshot(snap: &str) -> String { @@ -26,6 +34,19 @@ pub fn default_snapshot_settings_for_test<'a>( let filename = path.file_name().unwrap().to_str().unwrap(); settings.set_omit_expression(true); + fn uuid_in_message_redaction(content: Content, _content_path: ContentPath) -> Content { + match &content { + Content::String(s) => { + let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "$before[uuid]$after"); + Content::String(uuid_replaced.to_string()) + } + _ => content, + } + } + + settings.add_dynamic_redaction(".message", uuid_in_message_redaction); + settings.add_dynamic_redaction(".error.message", uuid_in_message_redaction); + let test_name = test_name.strip_suffix("::{{closure}}").unwrap_or(test_name); let test_name = test_name.rsplit("::").next().unwrap().to_owned(); diff --git a/crates/meilisearch/src/error.rs b/crates/meilisearch/src/error.rs index 13800adc1..b13eb8d7c 100644 --- a/crates/meilisearch/src/error.rs +++ b/crates/meilisearch/src/error.rs @@ -64,7 +64,7 @@ pub enum MeilisearchHttpError { #[error(transparent)] IndexScheduler(#[from] index_scheduler::Error), #[error("{}", match .index_name { - Some(name) if !name.is_empty() => format!("Index `{}`: {error}", MeilisearchHttpError::index_name(name)), + Some(name) if !name.is_empty() => format!("Index `{}`: {error}", name), _ => format!("{error}") })] Milli { error: milli::Error, index_name: Option }, @@ -84,14 +84,6 @@ impl MeilisearchHttpError { pub(crate) fn from_milli(error: milli::Error, index_name: Option) -> Self { Self::Milli { error, index_name } } - - fn index_name(index_name: &str) -> &str { - if let Ok(_) = uuid::Uuid::parse_str(index_name) { - "[uuid]" - } else { - index_name - } - } } impl ErrorCode for MeilisearchHttpError { diff --git a/crates/meilisearch/tests/search/errors.rs b/crates/meilisearch/tests/search/errors.rs index bce03f56b..d76a0963d 100644 --- a/crates/meilisearch/tests/search/errors.rs +++ b/crates/meilisearch/tests/search/errors.rs @@ -708,7 +708,7 @@ async fn filter_invalid_attribute_array() { |response, code| { snapshot!(response, @r###" { - "message": "Index `test`: Attribute `many` is not filterable. Available filterable attribute patterns are: `title`.\n1:5 many = Glass", + "message": "Index `[uuid]`: Attribute `many` is not filterable. Available filterable attribute patterns are: `title`.\n1:5 many = Glass", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" From d2948adea33f39485e1692e908378b0dc21772c0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 26 May 2025 14:31:58 +0300 Subject: [PATCH 041/292] Migrate more tests to assert with "[uuid]" instead of real Uuid Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/auth/api_keys.rs | 2 +- crates/meilisearch/tests/search/errors.rs | 16 ++++++++-------- crates/meilisearch/tests/search/filters.rs | 4 ++-- crates/meilisearch/tests/search/mod.rs | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/crates/meilisearch/tests/auth/api_keys.rs b/crates/meilisearch/tests/auth/api_keys.rs index 0aea7d722..7245c73a4 100644 --- a/crates/meilisearch/tests/auth/api_keys.rs +++ b/crates/meilisearch/tests/auth/api_keys.rs @@ -538,7 +538,7 @@ async fn error_add_api_key_parameters_uid_already_exist() { let (response, code) = server.add_api_key(content).await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "`uid` field value `4bc0887a-0e41-4f3b-935d-0c451dcee9c8` is already an existing API key.", + "message": "`uid` field value `[uuid]` is already an existing API key.", "code": "api_key_already_exists", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#api_key_already_exists" diff --git a/crates/meilisearch/tests/search/errors.rs b/crates/meilisearch/tests/search/errors.rs index d76a0963d..5e54bcff1 100644 --- a/crates/meilisearch/tests/search/errors.rs +++ b/crates/meilisearch/tests/search/errors.rs @@ -886,7 +886,7 @@ async fn search_with_pattern_filter_settings_errors() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r#" { - "message": "Index `test`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -912,7 +912,7 @@ async fn search_with_pattern_filter_settings_errors() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r#" { - "message": "Index `test`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -933,7 +933,7 @@ async fn search_with_pattern_filter_settings_errors() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r#" { - "message": "Index `test`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -959,7 +959,7 @@ async fn search_with_pattern_filter_settings_errors() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r#" { - "message": "Index `test`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -985,7 +985,7 @@ async fn search_with_pattern_filter_settings_errors() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r#" { - "message": "Index `test`: Filter operator `TO` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `TO` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -1144,7 +1144,7 @@ async fn search_on_unknown_field() { snapshot!(code, @"400 Bad Request"); snapshot!(response, @r###" { - "message": "Index `test`: Attribute `unknown` is not searchable. Available searchable attributes are: `id, title`.", + "message": "Index `[uuid]`: Attribute `unknown` is not searchable. Available searchable attributes are: `id, title`.", "code": "invalid_search_attributes_to_search_on", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_attributes_to_search_on" @@ -1165,7 +1165,7 @@ async fn search_on_unknown_field_plus_joker() { snapshot!(code, @"400 Bad Request"); snapshot!(response, @r###" { - "message": "Index `test`: Attribute `unknown` is not searchable. Available searchable attributes are: `id, title`.", + "message": "Index `[uuid]`: Attribute `unknown` is not searchable. Available searchable attributes are: `id, title`.", "code": "invalid_search_attributes_to_search_on", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_attributes_to_search_on" @@ -1183,7 +1183,7 @@ async fn search_on_unknown_field_plus_joker() { snapshot!(code, @"400 Bad Request"); snapshot!(response, @r###" { - "message": "Index `test`: Attribute `unknown` is not searchable. Available searchable attributes are: `id, title`.", + "message": "Index `[uuid]`: Attribute `unknown` is not searchable. Available searchable attributes are: `id, title`.", "code": "invalid_search_attributes_to_search_on", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_attributes_to_search_on" diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 4219d2ec1..49409efa6 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -720,7 +720,7 @@ async fn test_filterable_attributes_priority() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Attribute `doggos.age` is not filterable. Available filterable attribute patterns are: `doggos.*`.\n1:11 doggos.age > 2", + "message": "Index `[uuid]`: Attribute `doggos.age` is not filterable. Available filterable attribute patterns are: `doggos.*`.\n1:11 doggos.age > 2", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -746,7 +746,7 @@ async fn test_filterable_attributes_priority() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Attribute `doggos` is not filterable. Available filterable attribute patterns are: `doggos.*`.\n1:7 doggos EXISTS", + "message": "Index `[uuid]`: Attribute `doggos` is not filterable. Available filterable attribute patterns are: `doggos.*`.\n1:7 doggos EXISTS", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index 2cc882c71..bfa23054a 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -1741,7 +1741,7 @@ async fn test_nested_fields() { assert_eq!(code, 400, "{response}"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Attribute `nested` is not filterable. Available filterable attribute patterns are: `nested.machin`, `nested.object`, `title`.\n1:7 nested = array", + "message": "Index `[uuid]`: Attribute `nested` is not filterable. Available filterable attribute patterns are: `nested.machin`, `nested.object`, `title`.\n1:7 nested = array", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -1760,7 +1760,7 @@ async fn test_nested_fields() { assert_eq!(code, 400, "{response}"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Attribute `nested` is not filterable. Available filterable attribute patterns are: `nested.machin`, `nested.object`, `title`.\n1:7 nested = \"I lied\"", + "message": "Index `[uuid]`: Attribute `nested` is not filterable. Available filterable attribute patterns are: `nested.machin`, `nested.object`, `title`.\n1:7 nested = \"I lied\"", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" From 6738a4f6ee4cad6fc341286e1fdd55898134df9e Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 26 May 2025 10:08:07 +0200 Subject: [PATCH 042/292] feat: mettre a jour the insta snapshots --- .../meilisearch/tests/documents/add_documents.rs | 16 ++++++++-------- .../update/new/extract/faceted/extract_facets.rs | 5 +---- .../update/new/extract/faceted/facet_document.rs | 1 - 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 6569bb9a5..39ad57750 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -2039,6 +2039,14 @@ async fn update_documents_with_geo_field() { @r###" { "hits": [ + { + "id": "4", + "_geo": { + "lat": "4", + "lng": "0" + }, + "_geoDistance": 667170 + }, { "id": "3", "_geo": { @@ -2048,14 +2056,6 @@ async fn update_documents_with_geo_field() { "doggo": "kefir", "_geoDistance": 555975 }, - { - "id": "4", - "_geo": { - "lat": "4", - "lng": "0" - }, - "_geoDistance": 667170 - }, { "id": "1" }, diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index de0edc164..3086d25e4 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -135,7 +135,6 @@ impl FacetedDocidsExtractor { extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), new_fields_ids_map.deref_mut(), filterable_attributes, sortable_fields, @@ -177,7 +176,6 @@ impl FacetedDocidsExtractor { extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), new_fields_ids_map.deref_mut(), filterable_attributes, sortable_fields, @@ -200,7 +198,6 @@ impl FacetedDocidsExtractor { extract_document_facets( inner.merged(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), new_fields_ids_map.deref_mut(), filterable_attributes, sortable_fields, @@ -224,7 +221,6 @@ impl FacetedDocidsExtractor { extract_document_facets( inner.inserted(), - inner.external_document_id(), new_fields_ids_map.deref_mut(), filterable_attributes, sortable_fields, @@ -232,6 +228,7 @@ impl FacetedDocidsExtractor { distinct_field, &mut add, )?; + if is_geo_enabled { extract_geo_document( inner.inserted(), diff --git a/crates/milli/src/update/new/extract/faceted/facet_document.rs b/crates/milli/src/update/new/extract/faceted/facet_document.rs index 68bc98b64..359c32e58 100644 --- a/crates/milli/src/update/new/extract/faceted/facet_document.rs +++ b/crates/milli/src/update/new/extract/faceted/facet_document.rs @@ -16,7 +16,6 @@ use crate::filterable_attributes_rules::match_faceted_field; #[allow(clippy::too_many_arguments)] pub fn extract_document_facets<'doc>( document: impl Document<'doc>, - external_document_id: &str, field_id_map: &mut GlobalFieldsIdsMap, filterable_attributes: &[FilterableAttributesRule], sortable_fields: &HashSet, From 18aed75d3b0221222c97bc445101c8f069918ac1 Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 26 May 2025 18:20:55 +0200 Subject: [PATCH 043/292] fix logic --- .../tests/documents/add_documents.rs | 16 +++---- .../new/extract/faceted/extract_facets.rs | 46 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 39ad57750..6569bb9a5 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -2039,14 +2039,6 @@ async fn update_documents_with_geo_field() { @r###" { "hits": [ - { - "id": "4", - "_geo": { - "lat": "4", - "lng": "0" - }, - "_geoDistance": 667170 - }, { "id": "3", "_geo": { @@ -2056,6 +2048,14 @@ async fn update_documents_with_geo_field() { "doggo": "kefir", "_geoDistance": 555975 }, + { + "id": "4", + "_geo": { + "lat": "4", + "lng": "0" + }, + "_geoDistance": 667170 + }, { "id": "1" }, diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index 3086d25e4..861c67bbe 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -170,10 +170,10 @@ impl FacetedDocidsExtractor { let has_changed_for_geo_fields = inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)?; - if has_changed { - // 1. Delete old facet values - let mut del = facet_fn!(del); + // 1. Delete old facet values + let mut del = facet_fn!(del); + if has_changed { extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, new_fields_ids_map.deref_mut(), @@ -183,19 +183,20 @@ impl FacetedDocidsExtractor { distinct_field, &mut del, )?; + } + if is_geo_enabled && has_changed_for_geo_fields { + extract_geo_document( + inner.current(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + &mut del, + )?; + } - if is_geo_enabled && has_changed_for_geo_fields { - extract_geo_document( - inner.current(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), - new_fields_ids_map.deref_mut(), - &mut del, - )?; - } - - // 2. Insert new facet values - let mut add = facet_fn!(add); + // 2. Insert new facet values + let mut add = facet_fn!(add); + if has_changed { extract_document_facets( inner.merged(rtxn, index, context.db_fields_ids_map)?, new_fields_ids_map.deref_mut(), @@ -205,15 +206,14 @@ impl FacetedDocidsExtractor { distinct_field, &mut add, )?; - - if is_geo_enabled && has_changed_for_geo_fields { - extract_geo_document( - inner.merged(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), - new_fields_ids_map.deref_mut(), - &mut add, - )?; - } + } + if is_geo_enabled && has_changed_for_geo_fields { + extract_geo_document( + inner.merged(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + &mut add, + )?; } } DocumentChange::Insertion(inner) => { From c9ec502ed9e37ca970f9a0954780003696452913 Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 26 May 2025 18:32:59 +0200 Subject: [PATCH 044/292] refactor for readability --- .../new/extract/faceted/extract_facets.rs | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index 861c67bbe..2640ac462 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -170,9 +170,7 @@ impl FacetedDocidsExtractor { let has_changed_for_geo_fields = inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)?; - // 1. Delete old facet values - let mut del = facet_fn!(del); - + // 1. Maybe update doc if has_changed { extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, @@ -181,22 +179,9 @@ impl FacetedDocidsExtractor { sortable_fields, asc_desc_fields, distinct_field, - &mut del, + &mut facet_fn!(del), )?; - } - if is_geo_enabled && has_changed_for_geo_fields { - extract_geo_document( - inner.current(rtxn, index, context.db_fields_ids_map)?, - inner.external_document_id(), - new_fields_ids_map.deref_mut(), - &mut del, - )?; - } - // 2. Insert new facet values - let mut add = facet_fn!(add); - - if has_changed { extract_document_facets( inner.merged(rtxn, index, context.db_fields_ids_map)?, new_fields_ids_map.deref_mut(), @@ -204,15 +189,23 @@ impl FacetedDocidsExtractor { sortable_fields, asc_desc_fields, distinct_field, - &mut add, + &mut facet_fn!(add), )?; } + + // 2. Maybe update geo if is_geo_enabled && has_changed_for_geo_fields { + extract_geo_document( + inner.current(rtxn, index, context.db_fields_ids_map)?, + inner.external_document_id(), + new_fields_ids_map.deref_mut(), + &mut facet_fn!(del), + )?; extract_geo_document( inner.merged(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), new_fields_ids_map.deref_mut(), - &mut add, + &mut facet_fn!(add), )?; } } From 9ad43b6841aa4765b7f31645631c69dce565d612 Mon Sep 17 00:00:00 2001 From: nnethercott Date: Mon, 26 May 2025 18:37:20 +0200 Subject: [PATCH 045/292] rename has_changed to has_changed_for_facets --- crates/milli/src/update/new/extract/faceted/extract_facets.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index 2640ac462..a1d9e6553 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -153,7 +153,7 @@ impl FacetedDocidsExtractor { } } DocumentChange::Update(inner) => { - let has_changed = inner.has_changed_for_fields( + let has_changed_for_facets = inner.has_changed_for_fields( &mut |field_name| { match_faceted_field( field_name, @@ -171,7 +171,7 @@ impl FacetedDocidsExtractor { inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)?; // 1. Maybe update doc - if has_changed { + if has_changed_for_facets { extract_document_facets( inner.current(rtxn, index, context.db_fields_ids_map)?, new_fields_ids_map.deref_mut(), From b007ed6be91d05173c081d94029d321330926018 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 27 May 2025 10:04:14 +0200 Subject: [PATCH 046/292] Remove TemplateChecker --- crates/milli/src/prompt/error.rs | 2 + crates/milli/src/prompt/mod.rs | 8 +- crates/milli/src/prompt/template_checker.rs | 301 -------------------- 3 files changed, 4 insertions(+), 307 deletions(-) delete mode 100644 crates/milli/src/prompt/template_checker.rs diff --git a/crates/milli/src/prompt/error.rs b/crates/milli/src/prompt/error.rs index a92e2fdc3..a21031ff1 100644 --- a/crates/milli/src/prompt/error.rs +++ b/crates/milli/src/prompt/error.rs @@ -18,6 +18,7 @@ impl NewPromptError { Self { kind: NewPromptErrorKind::CannotParseTemplate(inner), fault: FaultSource::User } } + #[allow(unused)] pub(crate) fn invalid_fields_in_template(inner: liquid::Error) -> NewPromptError { Self { kind: NewPromptErrorKind::InvalidFieldsInTemplate(inner), fault: FaultSource::User } } @@ -27,6 +28,7 @@ impl NewPromptError { pub enum NewPromptErrorKind { #[error("cannot parse template: {0}")] CannotParseTemplate(liquid::Error), + #[allow(unused)] #[error("template contains invalid fields: {0}. Only `doc.*`, `fields[i].name`, `fields[i].value` are supported")] InvalidFieldsInTemplate(liquid::Error), } diff --git a/crates/milli/src/prompt/mod.rs b/crates/milli/src/prompt/mod.rs index a5cb8de48..c24069c00 100644 --- a/crates/milli/src/prompt/mod.rs +++ b/crates/milli/src/prompt/mod.rs @@ -2,7 +2,6 @@ mod context; mod document; pub(crate) mod error; mod fields; -mod template_checker; use std::cell::RefCell; use std::convert::TryFrom; @@ -105,11 +104,6 @@ impl Prompt { max_bytes, }; - // render template with special object that's OK with `doc.*` and `fields.*` - this.template - .render(&template_checker::TemplateChecker) - .map_err(NewPromptError::invalid_fields_in_template)?; - Ok(this) } @@ -206,6 +200,7 @@ mod test { } #[test] + #[ignore] fn template_missing_doc() { assert!(matches!( Prompt::new("{{title}}: {{overview}}".into(), None), @@ -236,6 +231,7 @@ mod test { } #[test] + #[ignore] fn template_fields_invalid() { assert!(matches!( // intentionally garbled field diff --git a/crates/milli/src/prompt/template_checker.rs b/crates/milli/src/prompt/template_checker.rs deleted file mode 100644 index 4cda4a70d..000000000 --- a/crates/milli/src/prompt/template_checker.rs +++ /dev/null @@ -1,301 +0,0 @@ -use liquid::model::{ - ArrayView, DisplayCow, KStringCow, ObjectRender, ObjectSource, State, Value as LiquidValue, -}; -use liquid::{Object, ObjectView, ValueView}; - -#[derive(Debug)] -pub struct TemplateChecker; - -#[derive(Debug)] -pub struct DummyDoc; - -#[derive(Debug)] -pub struct DummyFields; - -#[derive(Debug)] -pub struct DummyField; - -const DUMMY_VALUE: &LiquidValue = &LiquidValue::Nil; - -impl ObjectView for DummyField { - fn as_value(&self) -> &dyn ValueView { - self - } - - fn size(&self) -> i64 { - 2 - } - - fn keys<'k>(&'k self) -> Box> + 'k> { - Box::new(["name", "value"].iter().map(|s| KStringCow::from_static(s))) - } - - fn values<'k>(&'k self) -> Box + 'k> { - Box::new(vec![DUMMY_VALUE.as_view(), DUMMY_VALUE.as_view()].into_iter()) - } - - fn iter<'k>(&'k self) -> Box, &'k dyn ValueView)> + 'k> { - Box::new(self.keys().zip(self.values())) - } - - fn contains_key(&self, index: &str) -> bool { - index == "name" || index == "value" - } - - fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> { - if self.contains_key(index) { - Some(DUMMY_VALUE.as_view()) - } else { - None - } - } -} - -impl ValueView for DummyField { - fn as_debug(&self) -> &dyn std::fmt::Debug { - self - } - - fn render(&self) -> DisplayCow<'_> { - DUMMY_VALUE.render() - } - - fn source(&self) -> DisplayCow<'_> { - DUMMY_VALUE.source() - } - - fn type_name(&self) -> &'static str { - "object" - } - - fn query_state(&self, state: State) -> bool { - match state { - State::Truthy => true, - State::DefaultValue => false, - State::Empty => false, - State::Blank => false, - } - } - - fn to_kstr(&self) -> KStringCow<'_> { - DUMMY_VALUE.to_kstr() - } - - fn to_value(&self) -> LiquidValue { - let mut this = Object::new(); - this.insert("name".into(), LiquidValue::Nil); - this.insert("value".into(), LiquidValue::Nil); - LiquidValue::Object(this) - } - - fn as_object(&self) -> Option<&dyn ObjectView> { - Some(self) - } -} - -impl ValueView for DummyFields { - fn as_debug(&self) -> &dyn std::fmt::Debug { - self - } - - fn render(&self) -> DisplayCow<'_> { - DUMMY_VALUE.render() - } - - fn source(&self) -> DisplayCow<'_> { - DUMMY_VALUE.source() - } - - fn type_name(&self) -> &'static str { - "array" - } - - fn query_state(&self, state: State) -> bool { - match state { - State::Truthy => true, - State::DefaultValue => false, - State::Empty => false, - State::Blank => false, - } - } - - fn to_kstr(&self) -> KStringCow<'_> { - DUMMY_VALUE.to_kstr() - } - - fn to_value(&self) -> LiquidValue { - LiquidValue::Array(vec![DummyField.to_value()]) - } - - fn as_array(&self) -> Option<&dyn ArrayView> { - Some(self) - } -} - -impl ArrayView for DummyFields { - fn as_value(&self) -> &dyn ValueView { - self - } - - fn size(&self) -> i64 { - u16::MAX as i64 - } - - fn values<'k>(&'k self) -> Box + 'k> { - Box::new(std::iter::once(DummyField.as_value())) - } - - fn contains_key(&self, index: i64) -> bool { - index < self.size() - } - - fn get(&self, _index: i64) -> Option<&dyn ValueView> { - Some(DummyField.as_value()) - } -} - -impl ObjectView for DummyDoc { - fn as_value(&self) -> &dyn ValueView { - self - } - - fn size(&self) -> i64 { - 1000 - } - - fn keys<'k>(&'k self) -> Box> + 'k> { - Box::new(std::iter::empty()) - } - - fn values<'k>(&'k self) -> Box + 'k> { - Box::new(std::iter::empty()) - } - - fn iter<'k>(&'k self) -> Box, &'k dyn ValueView)> + 'k> { - Box::new(std::iter::empty()) - } - - fn contains_key(&self, _index: &str) -> bool { - true - } - - fn get<'s>(&'s self, _index: &str) -> Option<&'s dyn ValueView> { - // Recursively sends itself - Some(self) - } -} - -impl ValueView for DummyDoc { - fn as_debug(&self) -> &dyn std::fmt::Debug { - self - } - - fn render(&self) -> DisplayCow<'_> { - DUMMY_VALUE.render() - } - - fn source(&self) -> DisplayCow<'_> { - DUMMY_VALUE.source() - } - - fn type_name(&self) -> &'static str { - "object" - } - - fn query_state(&self, state: State) -> bool { - match state { - State::Truthy => true, - State::DefaultValue => false, - State::Empty => false, - State::Blank => false, - } - } - - fn to_kstr(&self) -> KStringCow<'_> { - DUMMY_VALUE.to_kstr() - } - - fn to_value(&self) -> LiquidValue { - LiquidValue::Nil - } - - fn as_object(&self) -> Option<&dyn ObjectView> { - Some(self) - } -} - -impl ObjectView for TemplateChecker { - fn as_value(&self) -> &dyn ValueView { - self - } - - fn size(&self) -> i64 { - 2 - } - - fn keys<'k>(&'k self) -> Box> + 'k> { - Box::new(["doc", "fields"].iter().map(|s| KStringCow::from_static(s))) - } - - fn values<'k>(&'k self) -> Box + 'k> { - Box::new( - std::iter::once(DummyDoc.as_value()).chain(std::iter::once(DummyFields.as_value())), - ) - } - - fn iter<'k>(&'k self) -> Box, &'k dyn ValueView)> + 'k> { - Box::new(self.keys().zip(self.values())) - } - - fn contains_key(&self, index: &str) -> bool { - index == "doc" || index == "fields" - } - - fn get<'s>(&'s self, index: &str) -> Option<&'s dyn ValueView> { - match index { - "doc" => Some(DummyDoc.as_value()), - "fields" => Some(DummyFields.as_value()), - _ => None, - } - } -} - -impl ValueView for TemplateChecker { - fn as_debug(&self) -> &dyn std::fmt::Debug { - self - } - - fn render(&self) -> liquid::model::DisplayCow<'_> { - DisplayCow::Owned(Box::new(ObjectRender::new(self))) - } - - fn source(&self) -> liquid::model::DisplayCow<'_> { - DisplayCow::Owned(Box::new(ObjectSource::new(self))) - } - - fn type_name(&self) -> &'static str { - "object" - } - - fn query_state(&self, state: liquid::model::State) -> bool { - match state { - State::Truthy => true, - State::DefaultValue | State::Empty | State::Blank => false, - } - } - - fn to_kstr(&self) -> liquid::model::KStringCow<'_> { - let s = ObjectRender::new(self).to_string(); - KStringCow::from_string(s) - } - - fn to_value(&self) -> LiquidValue { - LiquidValue::Object( - self.iter().map(|(k, x)| (k.to_string().into(), x.to_value())).collect(), - ) - } - - fn as_object(&self) -> Option<&dyn ObjectView> { - Some(self) - } -} From 5810fb239ffdf8cf8b72d12000e3b3ddd246ac23 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 27 May 2025 10:24:04 +0200 Subject: [PATCH 047/292] Reference PR in comments --- crates/milli/src/prompt/error.rs | 4 ++-- crates/milli/src/prompt/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/milli/src/prompt/error.rs b/crates/milli/src/prompt/error.rs index a21031ff1..03f3fb8a8 100644 --- a/crates/milli/src/prompt/error.rs +++ b/crates/milli/src/prompt/error.rs @@ -18,7 +18,7 @@ impl NewPromptError { Self { kind: NewPromptErrorKind::CannotParseTemplate(inner), fault: FaultSource::User } } - #[allow(unused)] + #[allow(unused)] // See for explanation pub(crate) fn invalid_fields_in_template(inner: liquid::Error) -> NewPromptError { Self { kind: NewPromptErrorKind::InvalidFieldsInTemplate(inner), fault: FaultSource::User } } @@ -28,7 +28,7 @@ impl NewPromptError { pub enum NewPromptErrorKind { #[error("cannot parse template: {0}")] CannotParseTemplate(liquid::Error), - #[allow(unused)] + #[allow(unused)] // See for explanation #[error("template contains invalid fields: {0}. Only `doc.*`, `fields[i].name`, `fields[i].value` are supported")] InvalidFieldsInTemplate(liquid::Error), } diff --git a/crates/milli/src/prompt/mod.rs b/crates/milli/src/prompt/mod.rs index c24069c00..d40fcd27f 100644 --- a/crates/milli/src/prompt/mod.rs +++ b/crates/milli/src/prompt/mod.rs @@ -200,7 +200,7 @@ mod test { } #[test] - #[ignore] + #[ignore] // See for explanation fn template_missing_doc() { assert!(matches!( Prompt::new("{{title}}: {{overview}}".into(), None), @@ -231,7 +231,7 @@ mod test { } #[test] - #[ignore] + #[ignore] // See for explanation fn template_fields_invalid() { assert!(matches!( // intentionally garbled field From 46ff78b4ec5e6f5812490c3399b4183545f3cb2d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 27 May 2025 11:47:02 +0300 Subject: [PATCH 048/292] Update the regex to replace all occurrences of uuids in the redaction Signed-off-by: Martin Tzvetanov Grigorov --- Cargo.lock | 1 + crates/meili-snap/Cargo.toml | 3 +++ crates/meili-snap/src/lib.rs | 21 ++++++++++++++++----- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c73af51d9..dc2aa5af4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3594,6 +3594,7 @@ dependencies = [ "md5", "once_cell", "regex-lite", + "uuid", ] [[package]] diff --git a/crates/meili-snap/Cargo.toml b/crates/meili-snap/Cargo.toml index b79960fdb..9dba56256 100644 --- a/crates/meili-snap/Cargo.toml +++ b/crates/meili-snap/Cargo.toml @@ -16,3 +16,6 @@ insta = { version = "=1.39.0", features = ["json", "redactions"] } md5 = "0.7.0" once_cell = "1.20" regex-lite = "0.1.6" + +[dev-dependencies] +uuid = { version = "1.17.0", features = ["v4"] } diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index e8e605fec..975b0d47c 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -6,14 +6,12 @@ use std::sync::Mutex; pub use insta; use insta::internals::{Content, ContentPath}; use once_cell::sync::Lazy; -use regex_lite::{Regex, RegexBuilder}; +use regex_lite::Regex; static SNAPSHOT_NAMES: Lazy>> = Lazy::new(Mutex::default); /// A regex to match UUIDs in messages, specifically looking for the UUID v4 format static UUID_IN_MESSAGE_RE: Lazy = Lazy::new(|| { - RegexBuilder::new(r"(?.*)([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})(?.*)") - .case_insensitive(true) - .build().unwrap() + Regex::new(r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}").unwrap() }); /// Return the md5 hash of the given string @@ -37,7 +35,7 @@ pub fn default_snapshot_settings_for_test<'a>( fn uuid_in_message_redaction(content: Content, _content_path: ContentPath) -> Content { match &content { Content::String(s) => { - let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "$before[uuid]$after"); + let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "[uuid]"); Content::String(uuid_replaced.to_string()) } _ => content, @@ -252,7 +250,10 @@ macro_rules! json_string { #[cfg(test)] mod tests { + use uuid::Uuid; use crate as meili_snap; + use crate::UUID_IN_MESSAGE_RE; + #[test] fn snap() { snapshot_hash!(10, @"d3d9446802a44259755d38e6d163e820"); @@ -300,4 +301,14 @@ mod tests { // snapshot_hash!("", name: "", @"d41d8cd98f00b204e9800998ecf8427e"); } } + + #[test] + fn uuid_in_message_regex() { + let uuid1 = Uuid::new_v4(); + let uuid2 = Uuid::new_v4(); + let uuid3 = Uuid::new_v4(); + let to_replace = format!("1 {uuid1} 2 {uuid2} 3 {uuid3} 4"); + let replaced = UUID_IN_MESSAGE_RE.replace_all(to_replace.as_str(), "[uuid]"); + assert_eq!(replaced, "1 [uuid] 2 [uuid] 3 [uuid] 4"); + } } From 4897ad99d06337791071cc4727be186a7c40b365 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 27 May 2025 14:26:29 +0300 Subject: [PATCH 049/292] Wait for the add_documents task Format the code Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 5 +++-- crates/meilisearch/tests/search/mod.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 975b0d47c..688c87494 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -11,7 +11,8 @@ use regex_lite::Regex; static SNAPSHOT_NAMES: Lazy>> = Lazy::new(Mutex::default); /// A regex to match UUIDs in messages, specifically looking for the UUID v4 format static UUID_IN_MESSAGE_RE: Lazy = Lazy::new(|| { - Regex::new(r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}").unwrap() + Regex::new(r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}") + .unwrap() }); /// Return the md5 hash of the given string @@ -250,9 +251,9 @@ macro_rules! json_string { #[cfg(test)] mod tests { - use uuid::Uuid; use crate as meili_snap; use crate::UUID_IN_MESSAGE_RE; + use uuid::Uuid; #[test] fn snap() { diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index bfa23054a..53e6415c5 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -130,8 +130,8 @@ async fn search_with_stop_word() { snapshot!(code, @"202 Accepted"); let documents = DOCUMENTS.clone(); - index.add_documents(documents, None).await; - index.wait_task(1).await; + let (task, code) = index.add_documents(documents, None).await; + index.wait_task(task.uid()).await.succeeded(); // prefix search index From 48cad4132ad368197ec353e5cbf173ad5981375c Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 27 May 2025 16:44:57 +0300 Subject: [PATCH 050/292] Fix clippy - ignore `code` variable Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index 53e6415c5..be476da35 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -130,7 +130,7 @@ async fn search_with_stop_word() { snapshot!(code, @"202 Accepted"); let documents = DOCUMENTS.clone(); - let (task, code) = index.add_documents(documents, None).await; + let (task, _code) = index.add_documents(documents, None).await; index.wait_task(task.uid()).await.succeeded(); // prefix search From 38b1c57fa80560685ff422e44196d05621c6afcd Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 16 May 2025 16:03:44 +0300 Subject: [PATCH 051/292] Faster IT tests for add_documents.rs Use Shared server where possible Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/documents/add_documents.rs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 6569bb9a5..2c8925833 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -18,8 +18,8 @@ async fn add_documents_test_json_content_types() { } ]); - // this is a what is expected and should work - let server = Server::new().await; + // this is what is expected and should work + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -75,8 +75,8 @@ async fn add_single_document_test_json_content_types() { "content": "Bouvier Bernois", }); - // this is a what is expected and should work - let server = Server::new().await; + // this is what is expected and should work + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -132,8 +132,8 @@ async fn add_single_document_gzip_encoded() { "content": "Bouvier Bernois", }); - // this is a what is expected and should work - let server = Server::new().await; + // this is what is expected and should work + let server = Server::new_shared(); let app = server.init_web_app().await; // post let document = serde_json::to_string(&document).unwrap(); @@ -187,8 +187,8 @@ async fn add_single_document_gzip_encoded() { async fn add_single_document_gzip_encoded_with_incomplete_error() { let document = json!("kefir"); - // this is a what is expected and should work - let server = Server::new().await; + // this is what is expected and should work + let server = Server::new_shared(); let app = server.init_web_app().await; // post let document = serde_json::to_string(&document).unwrap(); @@ -244,8 +244,8 @@ async fn add_single_document_with_every_encoding() { "content": "Bouvier Bernois", }); - // this is a what is expected and should work - let server = Server::new().await; + // this is what is expected and should work + let server = Server::new_shared(); let app = server.init_web_app().await; // post let document = serde_json::to_string(&document).unwrap(); @@ -518,7 +518,7 @@ async fn error_add_documents_test_bad_content_types() { } ]); - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -574,7 +574,7 @@ async fn error_add_documents_test_no_content_type() { } ]); - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -622,7 +622,7 @@ async fn error_add_documents_test_no_content_type() { async fn error_add_malformed_csv_documents() { let document = "id, content\n1234, hello, world\n12, hello world"; - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -672,7 +672,7 @@ async fn error_add_malformed_csv_documents() { async fn error_add_malformed_json_documents() { let document = r#"[{"id": 1}, {id: 2}]"#; - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -768,7 +768,7 @@ async fn error_add_malformed_json_documents() { async fn error_add_malformed_ndjson_documents() { let document = "{\"id\": 1}\n{id: 2}"; - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -818,7 +818,7 @@ async fn error_add_malformed_ndjson_documents() { async fn error_add_missing_payload_csv_documents() { let document = ""; - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -868,7 +868,7 @@ async fn error_add_missing_payload_csv_documents() { async fn error_add_missing_payload_json_documents() { let document = ""; - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post @@ -918,7 +918,7 @@ async fn error_add_missing_payload_json_documents() { async fn error_add_missing_payload_ndjson_documents() { let document = ""; - let server = Server::new().await; + let server = Server::new_shared(); let app = server.init_web_app().await; // post From cf5d26124a9ec856f41e07e4b0c8b80b4db49f49 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 16 May 2025 16:12:02 +0300 Subject: [PATCH 052/292] Call .succeeded() or .failed() on the waited task Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/documents/add_documents.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 2c8925833..57d0864ad 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -1111,7 +1111,7 @@ async fn document_addition_with_huge_int_primary_key() { let (response, code) = index.add_documents(documents, Some("primary")).await; snapshot!(code, @"202 Accepted"); - let response = index.wait_task(response.uid()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(response, @r###" { @@ -1568,7 +1568,7 @@ async fn error_document_field_limit_reached_over_multiple_documents() { let (response, code) = index.update_documents(documents, Some("id")).await; snapshot!(code, @"202 Accepted"); - let response = index.wait_task(response.uid()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(code, @"202 Accepted"); snapshot!(response, @r###" @@ -1603,7 +1603,7 @@ async fn error_document_field_limit_reached_over_multiple_documents() { let (response, code) = index.update_documents(documents, Some("id")).await; snapshot!(code, @"202 Accepted"); - let response = index.wait_task(response.uid()).await; + let response = index.wait_task(response.uid()).await.failed(); snapshot!(code, @"202 Accepted"); snapshot!(response, @r###" @@ -1652,7 +1652,7 @@ async fn error_document_field_limit_reached_in_one_nested_document() { let (response, code) = index.update_documents(documents, Some("id")).await; snapshot!(code, @"202 Accepted"); - let response = index.wait_task(response.uid()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(code, @"202 Accepted"); // Documents without a primary key are not accepted. snapshot!(response, @@ -1697,7 +1697,7 @@ async fn error_document_field_limit_reached_over_multiple_documents_with_nested_ let (response, code) = index.update_documents(documents, Some("id")).await; snapshot!(code, @"202 Accepted"); - let response = index.wait_task(response.uid()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(code, @"202 Accepted"); snapshot!(response, @r###" @@ -1733,7 +1733,7 @@ async fn error_document_field_limit_reached_over_multiple_documents_with_nested_ let (response, code) = index.update_documents(documents, Some("id")).await; snapshot!(code, @"202 Accepted"); - let response = index.wait_task(response.uid()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(code, @"202 Accepted"); snapshot!(response, @r###" @@ -1782,7 +1782,7 @@ async fn add_documents_with_geo_field() { ]); let (task, _status_code) = index.add_documents(documents, None).await; - let response = index.wait_task(task.uid()).await; + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { @@ -1906,7 +1906,7 @@ async fn update_documents_with_geo_field() { ]); let (task, _status_code) = index.add_documents(documents, None).await; - let response = index.wait_task(task.uid()).await; + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { @@ -1975,7 +1975,7 @@ async fn update_documents_with_geo_field() { } ]); let (task, _status_code) = index.update_documents(updated_documents, None).await; - let response = index.wait_task(task.uid()).await; + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { @@ -2913,7 +2913,7 @@ async fn batch_several_documents_addition() { // wait first batch of documents to finish futures::future::join_all(waiter).await; - index.wait_task(4).await; + index.wait_task(4).await.succeeded(); // run a second completely failing batch documents[40] = json!({"title": "error", "desc": "error"}); @@ -2925,7 +2925,7 @@ async fn batch_several_documents_addition() { } // wait second batch of documents to finish futures::future::join_all(waiter).await; - index.wait_task(9).await; + index.wait_task(9).await.failed(); let (response, _code) = index.filtered_tasks(&[], &["failed"], &[]).await; From fc88b003b47301006348e2cd6ddd0f189f9d7c7d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 26 May 2025 11:28:23 +0300 Subject: [PATCH 053/292] Use shared server and unique indices for add_documents IT tests Signed-off-by: Martin Tzvetanov Grigorov --- Cargo.lock | 102 +++--- crates/index-scheduler/src/error.rs | 14 +- crates/meili-snap/src/lib.rs | 10 + crates/meilisearch/Cargo.toml | 2 +- .../tests/documents/add_documents.rs | 328 +++++++++--------- 5 files changed, 243 insertions(+), 213 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc2aa5af4..a36c568b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1067,9 +1067,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -1077,9 +1077,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -2715,17 +2715,21 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2", "tokio", @@ -2988,6 +2992,16 @@ dependencies = [ "serde", ] +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.16" @@ -3067,9 +3081,9 @@ dependencies = [ [[package]] name = "jieba-rs" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1bcad6332969e4d48ee568d430e14ee6dea70740c2549d005d87677ebefb0c" +checksum = "b06096b4b61fb4bfdbf16c6a968ea2d6be1ac9617cf3db741c3b641e6c290a35" dependencies = [ "cedarwood", "fxhash", @@ -3207,9 +3221,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", "windows-targets 0.53.0", @@ -4889,9 +4903,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "2bf597b113be201cb2269b4c39b39a804d01b99ee95a4278f0ed04e45cff1c71" dependencies = [ "base64 0.22.1", "bytes", @@ -4913,7 +4927,6 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", @@ -4923,14 +4936,14 @@ dependencies = [ "tokio-rustls", "tokio-util", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.11", - "windows-registry", + "webpki-roots 1.0.0", ] [[package]] @@ -5435,9 +5448,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5969,6 +5982,24 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http 1.3.1", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -6619,7 +6650,7 @@ checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ "windows-implement", "windows-interface", - "windows-result 0.1.2", + "windows-result", "windows-targets 0.52.6", ] @@ -6645,23 +6676,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result 0.3.4", - "windows-strings", - "windows-targets 0.53.0", -] - [[package]] name = "windows-result" version = "0.1.2" @@ -6671,24 +6685,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.48.0" diff --git a/crates/index-scheduler/src/error.rs b/crates/index-scheduler/src/error.rs index cb798b385..a0945d8a3 100644 --- a/crates/index-scheduler/src/error.rs +++ b/crates/index-scheduler/src/error.rs @@ -126,7 +126,7 @@ pub enum Error { #[error(transparent)] Heed(#[from] heed::Error), #[error("{}", match .index_uid { - Some(uid) if !uid.is_empty() => format!("Index `{}`: {error}", uid), + Some(uid) if !uid.is_empty() => format!("Index `{}`: {error}", Error::index_name(uid)), _ => format!("{error}") })] Milli { error: milli::Error, index_uid: Option }, @@ -177,6 +177,18 @@ pub enum Error { PlannedFailure, } +impl Error { + + #[inline] + fn index_name(index_name: &str) -> &str { + if let Ok(_) = uuid::Uuid::parse_str(index_name) { + "[uuid]" + } else { + index_name + } + } +} + #[derive(Debug, thiserror::Error)] #[error( "{disabled_action} requires enabling the `{feature}` experimental feature. See {issue_link}" diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 688c87494..17a57c082 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -33,6 +33,7 @@ pub fn default_snapshot_settings_for_test<'a>( let filename = path.file_name().unwrap().to_str().unwrap(); settings.set_omit_expression(true); +<<<<<<< HEAD fn uuid_in_message_redaction(content: Content, _content_path: ContentPath) -> Content { match &content { Content::String(s) => { @@ -45,6 +46,15 @@ pub fn default_snapshot_settings_for_test<'a>( settings.add_dynamic_redaction(".message", uuid_in_message_redaction); settings.add_dynamic_redaction(".error.message", uuid_in_message_redaction); + settings.add_dynamic_redaction(".indexUid", |content, _content_path| { + match &content { + Content::String(s) => match uuid::Uuid::parse_str(s) { + Ok(_) => Content::String("[uuid]".to_owned()), + Err(_) => content, + }, + _ => content, + } + }); let test_name = test_name.strip_suffix("::{{closure}}").unwrap_or(test_name); let test_name = test_name.rsplit("::").next().unwrap().to_owned(); diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index 40c0d98b5..dffa60326 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -116,7 +116,7 @@ utoipa-scalar = { version = "0.3.0", optional = true, features = ["actix-web"] } actix-rt = "2.10.0" brotli = "6.0.0" # fixed version due to format breakages in v1.40 -insta = "=1.39.0" +insta = { version = "=1.39.0", features = ["redactions"] } manifest-dir-macros = "0.1.18" maplit = "1.0.2" meili-snap = { path = "../meili-snap" } diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 57d0864ad..e8ef43b40 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -3,7 +3,7 @@ use meili_snap::{json_string, snapshot}; use meilisearch::Opt; use time::format_description::well_known::Rfc3339; use time::OffsetDateTime; - +use uuid::Uuid; use crate::common::encoder::Encoder; use crate::common::{default_settings, GetAllDocumentsOptions, Server, Value}; use crate::json; @@ -21,10 +21,11 @@ async fn add_documents_test_json_content_types() { // this is what is expected and should work let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -37,7 +38,7 @@ async fn add_documents_test_json_content_types() { @r###" { "taskUid": 0, - "indexUid": "dog", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -46,7 +47,7 @@ async fn add_documents_test_json_content_types() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -59,7 +60,7 @@ async fn add_documents_test_json_content_types() { @r###" { "taskUid": 1, - "indexUid": "dog", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -78,10 +79,11 @@ async fn add_single_document_test_json_content_types() { // this is what is expected and should work let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -94,7 +96,7 @@ async fn add_single_document_test_json_content_types() { @r###" { "taskUid": 0, - "indexUid": "dog", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -103,7 +105,7 @@ async fn add_single_document_test_json_content_types() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -116,7 +118,7 @@ async fn add_single_document_test_json_content_types() { @r###" { "taskUid": 1, - "indexUid": "dog", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -135,11 +137,12 @@ async fn add_single_document_gzip_encoded() { // this is what is expected and should work let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let document = serde_json::to_string(&document).unwrap(); let encoder = Encoder::Gzip; let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(encoder.encode(document.clone())) .insert_header(("content-type", "application/json")) .insert_header(encoder.header().unwrap()) @@ -153,7 +156,7 @@ async fn add_single_document_gzip_encoded() { @r###" { "taskUid": 0, - "indexUid": "dog", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -162,7 +165,7 @@ async fn add_single_document_gzip_encoded() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(encoder.encode(document)) .insert_header(("content-type", "application/json")) .insert_header(encoder.header().unwrap()) @@ -176,7 +179,7 @@ async fn add_single_document_gzip_encoded() { @r###" { "taskUid": 1, - "indexUid": "dog", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -190,10 +193,11 @@ async fn add_single_document_gzip_encoded_with_incomplete_error() { // this is what is expected and should work let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let document = serde_json::to_string(&document).unwrap(); let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .insert_header(("content-encoding", "gzip")) @@ -215,7 +219,7 @@ async fn add_single_document_gzip_encoded_with_incomplete_error() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .insert_header(("content-encoding", "gzip")) @@ -247,12 +251,13 @@ async fn add_single_document_with_every_encoding() { // this is what is expected and should work let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let document = serde_json::to_string(&document).unwrap(); for (task_uid, encoder) in Encoder::iterator().enumerate() { let mut req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(encoder.encode(document.clone())) .insert_header(("content-type", "application/json")); req = match encoder.header() { @@ -271,8 +276,8 @@ async fn add_single_document_with_every_encoding() { #[actix_rt::test] async fn add_csv_document() { - let server = Server::new().await; - let index = server.index("pets"); + let server = Server::new_shared(); + let index = server.unique_index(); let document = "#id,name,race 0,jean,bernese mountain @@ -283,18 +288,18 @@ async fn add_csv_document() { snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" { "taskUid": 0, - "indexUid": "pets", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } "###); - let response = index.wait_task(response["taskUid"].as_u64().unwrap()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { "uid": 0, "batchUid": 0, - "indexUid": "pets", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -335,8 +340,8 @@ async fn add_csv_document() { #[actix_rt::test] async fn add_csv_document_with_types() { - let server = Server::new().await; - let index = server.index("pets"); + let server = Server::new_shared(); + let index = server.unique_index(); let document = "#id:number,name:string,race:string,age:number,cute:boolean 0,jean,bernese mountain,2.5,true @@ -348,18 +353,18 @@ async fn add_csv_document_with_types() { snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" { "taskUid": 0, - "indexUid": "pets", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } "###); - let response = index.wait_task(response["taskUid"].as_u64().unwrap()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { "uid": 0, "batchUid": 0, - "indexUid": "pets", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -411,8 +416,8 @@ async fn add_csv_document_with_types() { #[actix_rt::test] async fn add_csv_document_with_custom_delimiter() { - let server = Server::new().await; - let index = server.index("pets"); + let server = Server::new_shared(); + let index = server.unique_index(); let document = "#id|name|race 0|jean|bernese mountain @@ -424,18 +429,18 @@ async fn add_csv_document_with_custom_delimiter() { snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" { "taskUid": 0, - "indexUid": "pets", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } "###); - let response = index.wait_task(response["taskUid"].as_u64().unwrap()).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { "uid": 0, "batchUid": 0, - "indexUid": "pets", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -476,8 +481,8 @@ async fn add_csv_document_with_custom_delimiter() { #[actix_rt::test] async fn add_csv_document_with_types_error() { - let server = Server::new().await; - let index = server.index("pets"); + let server = Server::new_shared(); + let index = server.unique_index(); let document = "#id:number,a:boolean,b:number 0,doggo,1"; @@ -520,10 +525,11 @@ async fn error_add_documents_test_bad_content_types() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "text/plain")) .to_request(); @@ -544,7 +550,7 @@ async fn error_add_documents_test_bad_content_types() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "text/plain")) .to_request(); @@ -576,10 +582,11 @@ async fn error_add_documents_test_no_content_type() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .to_request(); let res = test::call_service(&app, req).await; @@ -599,7 +606,7 @@ async fn error_add_documents_test_no_content_type() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .to_request(); let res = test::call_service(&app, req).await; @@ -624,10 +631,11 @@ async fn error_add_malformed_csv_documents() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "text/csv")) .to_request(); @@ -648,7 +656,7 @@ async fn error_add_malformed_csv_documents() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "text/csv")) .to_request(); @@ -674,10 +682,11 @@ async fn error_add_malformed_json_documents() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -698,7 +707,7 @@ async fn error_add_malformed_json_documents() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -724,7 +733,7 @@ async fn error_add_malformed_json_documents() { let document = format!("\"{}\"", long); let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document) .insert_header(("content-type", "application/json")) .to_request(); @@ -745,7 +754,7 @@ async fn error_add_malformed_json_documents() { // add one more char to the long string to test if the truncating works. let document = format!("\"{}m\"", long); let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document) .insert_header(("content-type", "application/json")) .to_request(); @@ -770,10 +779,11 @@ async fn error_add_malformed_ndjson_documents() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/x-ndjson")) .to_request(); @@ -794,7 +804,7 @@ async fn error_add_malformed_ndjson_documents() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/x-ndjson")) .to_request(); @@ -820,10 +830,11 @@ async fn error_add_missing_payload_csv_documents() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "text/csv")) .to_request(); @@ -844,7 +855,7 @@ async fn error_add_missing_payload_csv_documents() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "text/csv")) .to_request(); @@ -870,10 +881,11 @@ async fn error_add_missing_payload_json_documents() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -894,7 +906,7 @@ async fn error_add_missing_payload_json_documents() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/json")) .to_request(); @@ -920,10 +932,11 @@ async fn error_add_missing_payload_ndjson_documents() { let server = Server::new_shared(); let app = server.init_web_app().await; + let index_name = Uuid::new_v4().to_string(); // post let req = test::TestRequest::post() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/x-ndjson")) .to_request(); @@ -944,7 +957,7 @@ async fn error_add_missing_payload_ndjson_documents() { // put let req = test::TestRequest::put() - .uri("/indexes/dog/documents") + .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(document.to_string()) .insert_header(("content-type", "application/x-ndjson")) .to_request(); @@ -966,8 +979,8 @@ async fn error_add_missing_payload_ndjson_documents() { #[actix_rt::test] async fn add_documents_no_index_creation() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -989,7 +1002,7 @@ async fn add_documents_no_index_creation() { { "uid": 0, "batchUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1037,8 +1050,8 @@ async fn error_document_add_create_index_bad_uid() { #[actix_rt::test] async fn document_addition_with_primary_key() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -1052,7 +1065,7 @@ async fn document_addition_with_primary_key() { @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -1068,7 +1081,7 @@ async fn document_addition_with_primary_key() { { "uid": 0, "batchUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1086,10 +1099,10 @@ async fn document_addition_with_primary_key() { let (response, code) = index.get().await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".createdAt" => "[date]", ".updatedAt" => "[date]" }), + snapshot!(json_string!(response, { ".createdAt" => "[date]", ".updatedAt" => "[date]", ".uid" => "[uuid]" }), @r###" { - "uid": "test", + "uid": "[uuid]", "createdAt": "[date]", "updatedAt": "[date]", "primaryKey": "primary" @@ -1099,8 +1112,8 @@ async fn document_addition_with_primary_key() { #[actix_rt::test] async fn document_addition_with_huge_int_primary_key() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -1117,7 +1130,7 @@ async fn document_addition_with_huge_int_primary_key() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1146,8 +1159,8 @@ async fn document_addition_with_huge_int_primary_key() { #[actix_rt::test] async fn replace_document() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -1162,7 +1175,7 @@ async fn replace_document() { @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" @@ -1190,7 +1203,7 @@ async fn replace_document() { { "uid": 1, "batchUid": 1, - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1219,17 +1232,17 @@ async fn replace_document() { #[actix_rt::test] async fn add_no_documents() { - let server = Server::new().await; - let index = server.index("kefir"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, code) = index.add_documents(json!([]), None).await; snapshot!(code, @"202 Accepted"); - let task = server.wait_task(task.uid()).await; + let task = server.wait_task(task.uid()).await.succeeded(); let task = task.succeeded(); snapshot!(task, @r#" { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "kefir", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1246,13 +1259,13 @@ async fn add_no_documents() { "#); let (task, _code) = index.add_documents(json!([]), Some("kefkef")).await; - let task = server.wait_task(task.uid()).await; + let task = server.wait_task(task.uid()).await.succeeded(); let task = task.succeeded(); snapshot!(task, @r#" { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "kefir", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1269,13 +1282,13 @@ async fn add_no_documents() { "#); let (task, _code) = index.add_documents(json!([{ "kefkef": 1 }]), None).await; - let task = server.wait_task(task.uid()).await; + let task = server.wait_task(task.uid()).await.succeeded(); let task = task.succeeded(); snapshot!(task, @r#" { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "kefir", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1307,8 +1320,8 @@ async fn add_no_documents() { #[actix_rt::test] async fn add_larger_dataset() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let update_id = index.load_test_set().await; let (response, code) = index.get_task(update_id).await; assert_eq!(code, 200); @@ -1319,12 +1332,11 @@ async fn add_larger_dataset() { let (response, code) = index .get_all_documents(GetAllDocumentsOptions { limit: Some(1000), ..Default::default() }) .await; - assert_eq!(code, 200, "failed with `{}`", response); + assert_eq!(code, 200, "failed with `{response}`"); assert_eq!(response["results"].as_array().unwrap().len(), 77); // x-ndjson add large test - let server = Server::new().await; - let index = server.index("test"); + let index = server.unique_index(); let update_id = index.load_test_set_ndjson().await; let (response, code) = index.get_task(update_id).await; assert_eq!(code, 200); @@ -1341,8 +1353,8 @@ async fn add_larger_dataset() { #[actix_rt::test] async fn error_add_documents_bad_document_id() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("docid")).await; // unsupported characters @@ -1362,7 +1374,7 @@ async fn error_add_documents_bad_document_id() { { "uid": 1, "batchUid": 1, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1399,7 +1411,7 @@ async fn error_add_documents_bad_document_id() { { "uid": 2, "batchUid": 2, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1436,7 +1448,7 @@ async fn error_add_documents_bad_document_id() { { "uid": 3, "batchUid": 3, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1460,8 +1472,8 @@ async fn error_add_documents_bad_document_id() { #[actix_rt::test] async fn error_add_documents_missing_document_id() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("docid")).await; let documents = json!([ { @@ -1478,7 +1490,7 @@ async fn error_add_documents_missing_document_id() { { "uid": 1, "batchUid": 1, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1502,8 +1514,8 @@ async fn error_add_documents_missing_document_id() { #[actix_rt::test] async fn error_document_field_limit_reached_in_one_document() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("id")).await; @@ -1527,7 +1539,7 @@ async fn error_document_field_limit_reached_in_one_document() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1551,8 +1563,8 @@ async fn error_document_field_limit_reached_in_one_document() { #[actix_rt::test] async fn error_document_field_limit_reached_over_multiple_documents() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("id")).await; @@ -1575,7 +1587,7 @@ async fn error_document_field_limit_reached_over_multiple_documents() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1610,7 +1622,7 @@ async fn error_document_field_limit_reached_over_multiple_documents() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1634,8 +1646,8 @@ async fn error_document_field_limit_reached_over_multiple_documents() { #[actix_rt::test] async fn error_document_field_limit_reached_in_one_nested_document() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("id")).await; @@ -1660,7 +1672,7 @@ async fn error_document_field_limit_reached_in_one_nested_document() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1679,8 +1691,8 @@ async fn error_document_field_limit_reached_in_one_nested_document() { #[actix_rt::test] async fn error_document_field_limit_reached_over_multiple_documents_with_nested_fields() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("id")).await; @@ -1704,7 +1716,7 @@ async fn error_document_field_limit_reached_over_multiple_documents_with_nested_ { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1740,7 +1752,7 @@ async fn error_document_field_limit_reached_over_multiple_documents_with_nested_ { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1759,8 +1771,8 @@ async fn error_document_field_limit_reached_over_multiple_documents_with_nested_ #[actix_rt::test] async fn add_documents_with_geo_field() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); index.update_settings(json!({"sortableAttributes": ["_geo"]})).await; let documents = json!([ @@ -1788,7 +1800,7 @@ async fn add_documents_with_geo_field() { { "uid": 1, "batchUid": 1, - "indexUid": "doggo", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1883,8 +1895,8 @@ async fn add_documents_with_geo_field() { #[actix_rt::test] async fn update_documents_with_geo_field() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); index.update_settings(json!({"sortableAttributes": ["_geo"]})).await; let documents = json!([ @@ -1912,7 +1924,7 @@ async fn update_documents_with_geo_field() { { "uid": 1, "batchUid": 1, - "indexUid": "doggo", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -1981,7 +1993,7 @@ async fn update_documents_with_geo_field() { { "uid": 2, "batchUid": 2, - "indexUid": "doggo", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2075,8 +2087,8 @@ async fn update_documents_with_geo_field() { #[actix_rt::test] async fn add_documents_invalid_geo_field() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("id")).await; index.update_settings(json!({"sortableAttributes": ["_geo"]})).await; @@ -2092,12 +2104,12 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".indexUid" => "[uuid]" }), @r###" { "uid": 2, "batchUid": 2, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2106,7 +2118,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: The `_geo` field in the document with the id: `\"11\"` is not an object. Was expecting an object with the `_geo.lat` and `_geo.lng` fields but instead got `\"foobar\"`.", + "message": "Index `[uuid]`: The `_geo` field in the document with the id: `\"11\"` is not an object. Was expecting an object with the `_geo.lat` and `_geo.lng` fields but instead got `\"foobar\"`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2135,7 +2147,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 3, "batchUid": 3, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2144,7 +2156,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find latitude nor longitude in the document with the id: `\"11\"`. Was expecting `_geo.lat` and `_geo.lng` fields.", + "message": "Index `[uuid]`: Could not find latitude nor longitude in the document with the id: `\"11\"`. Was expecting `_geo.lat` and `_geo.lng` fields.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2173,7 +2185,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 4, "batchUid": 4, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2182,7 +2194,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find latitude nor longitude in the document with the id: `\"11\"`. Was expecting `_geo.lat` and `_geo.lng` fields.", + "message": "Index `[uuid]`: Could not find latitude nor longitude in the document with the id: `\"11\"`. Was expecting `_geo.lat` and `_geo.lng` fields.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2211,7 +2223,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 5, "batchUid": 5, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2220,7 +2232,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find longitude in the document with the id: `\"11\"`. Was expecting a `_geo.lng` field.", + "message": "Index `[uuid]`: Could not find longitude in the document with the id: `\"11\"`. Was expecting a `_geo.lng` field.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2249,7 +2261,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 6, "batchUid": 6, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2258,7 +2270,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find latitude in the document with the id: `\"11\"`. Was expecting a `_geo.lat` field.", + "message": "Index `[uuid]`: Could not find latitude in the document with the id: `\"11\"`. Was expecting a `_geo.lat` field.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2287,7 +2299,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 7, "batchUid": 7, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2296,7 +2308,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find longitude in the document with the id: `\"11\"`. Was expecting a `_geo.lng` field.", + "message": "Index `[uuid]`: Could not find longitude in the document with the id: `\"11\"`. Was expecting a `_geo.lng` field.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2325,7 +2337,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 8, "batchUid": 8, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2334,7 +2346,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find latitude in the document with the id: `\"11\"`. Was expecting a `_geo.lat` field.", + "message": "Index `[uuid]`: Could not find latitude in the document with the id: `\"11\"`. Was expecting a `_geo.lat` field.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2363,7 +2375,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 9, "batchUid": 9, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2372,7 +2384,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not parse latitude nor longitude in the document with the id: `\"11\"`. Was expecting finite numbers but instead got `false` and `true`.", + "message": "Index `[uuid]`: Could not parse latitude nor longitude in the document with the id: `\"11\"`. Was expecting finite numbers but instead got `false` and `true`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2401,7 +2413,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 10, "batchUid": 10, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2410,7 +2422,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find longitude in the document with the id: `\"11\"`. Was expecting a `_geo.lng` field.", + "message": "Index `[uuid]`: Could not find longitude in the document with the id: `\"11\"`. Was expecting a `_geo.lng` field.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2439,7 +2451,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 11, "batchUid": 11, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2448,7 +2460,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not find latitude in the document with the id: `\"11\"`. Was expecting a `_geo.lat` field.", + "message": "Index `[uuid]`: Could not find latitude in the document with the id: `\"11\"`. Was expecting a `_geo.lat` field.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2477,7 +2489,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 12, "batchUid": 12, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2486,7 +2498,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not parse latitude nor longitude in the document with the id: `\"11\"`. Was expecting finite numbers but instead got `\"doggo\"` and `\"doggo\"`.", + "message": "Index `[uuid]`: Could not parse latitude nor longitude in the document with the id: `\"11\"`. Was expecting finite numbers but instead got `\"doggo\"` and `\"doggo\"`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2515,7 +2527,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 13, "batchUid": 13, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2524,7 +2536,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: The `_geo` field in the document with the id: `\"11\"` contains the following unexpected fields: `{\"doggo\":\"are the best\"}`.", + "message": "Index `[uuid]`: The `_geo` field in the document with the id: `\"11\"` contains the following unexpected fields: `{\"doggo\":\"are the best\"}`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2554,7 +2566,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 14, "batchUid": 14, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2563,7 +2575,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not parse longitude in the document with the id: `\"12\"`. Was expecting a finite number but instead got `null`.", + "message": "Index `[uuid]`: Could not parse longitude in the document with the id: `\"12\"`. Was expecting a finite number but instead got `null`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2591,7 +2603,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 15, "batchUid": 15, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2600,7 +2612,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not parse latitude in the document with the id: `\"12\"`. Was expecting a finite number but instead got `null`.", + "message": "Index `[uuid]`: Could not parse latitude in the document with the id: `\"12\"`. Was expecting a finite number but instead got `null`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2628,7 +2640,7 @@ async fn add_documents_invalid_geo_field() { { "uid": 16, "batchUid": 16, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2637,7 +2649,7 @@ async fn add_documents_invalid_geo_field() { "indexedDocuments": 0 }, "error": { - "message": "Index `test`: Could not parse latitude nor longitude in the document with the id: `\"13\"`. Was expecting finite numbers but instead got `null` and `null`.", + "message": "Index `[uuid]`: Could not parse latitude nor longitude in the document with the id: `\"13\"`. Was expecting finite numbers but instead got `null` and `null`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2653,8 +2665,8 @@ async fn add_documents_invalid_geo_field() { // Related to #4333 #[actix_rt::test] async fn add_invalid_geo_and_then_settings() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("id")).await; // _geo is not a correct object @@ -2671,7 +2683,7 @@ async fn add_invalid_geo_and_then_settings() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2694,7 +2706,7 @@ async fn add_invalid_geo_and_then_settings() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "settingsUpdate", "canceledBy": null, @@ -2704,7 +2716,7 @@ async fn add_invalid_geo_and_then_settings() { ] }, "error": { - "message": "Index `test`: Could not parse latitude in the document with the id: `\"11\"`. Was expecting a finite number but instead got `null`.", + "message": "Index `[uuid]`: Could not parse latitude in the document with the id: `\"11\"`. Was expecting a finite number but instead got `null`.", "code": "invalid_document_geo_field", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_geo_field" @@ -2719,8 +2731,8 @@ async fn add_invalid_geo_and_then_settings() { #[actix_rt::test] async fn error_add_documents_payload_size() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(Some("id")).await; let document = json!( { @@ -2746,8 +2758,8 @@ async fn error_add_documents_payload_size() { #[actix_rt::test] async fn error_primary_key_inference() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -2766,7 +2778,7 @@ async fn error_primary_key_inference() { { "uid": 0, "batchUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2807,7 +2819,7 @@ async fn error_primary_key_inference() { { "uid": 1, "batchUid": 1, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2846,7 +2858,7 @@ async fn error_primary_key_inference() { { "uid": 2, "batchUid": 2, - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -2865,8 +2877,8 @@ async fn error_primary_key_inference() { #[actix_rt::test] async fn add_documents_with_primary_key_twice() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -2888,8 +2900,8 @@ async fn add_documents_with_primary_key_twice() { #[actix_rt::test] async fn batch_several_documents_addition() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let mut documents: Vec<_> = (0..150usize) .map(|id| { From ce9c930d1070dc60f172db146e074bb9099125b8 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 26 May 2025 11:33:59 +0300 Subject: [PATCH 054/292] Fix clippy and fmt Signed-off-by: Martin Tzvetanov Grigorov --- crates/index-scheduler/src/error.rs | 3 +-- crates/meili-snap/src/lib.rs | 1 - crates/meilisearch/tests/documents/add_documents.rs | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/index-scheduler/src/error.rs b/crates/index-scheduler/src/error.rs index a0945d8a3..cbedf827d 100644 --- a/crates/index-scheduler/src/error.rs +++ b/crates/index-scheduler/src/error.rs @@ -178,10 +178,9 @@ pub enum Error { } impl Error { - #[inline] fn index_name(index_name: &str) -> &str { - if let Ok(_) = uuid::Uuid::parse_str(index_name) { + if uuid::Uuid::parse_str(index_name).is_ok() { "[uuid]" } else { index_name diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 17a57c082..30769c7c1 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -33,7 +33,6 @@ pub fn default_snapshot_settings_for_test<'a>( let filename = path.file_name().unwrap().to_str().unwrap(); settings.set_omit_expression(true); -<<<<<<< HEAD fn uuid_in_message_redaction(content: Content, _content_path: ContentPath) -> Content { match &content { Content::String(s) => { diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index e8ef43b40..efe1bfbf0 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -1,12 +1,12 @@ +use crate::common::encoder::Encoder; +use crate::common::{default_settings, GetAllDocumentsOptions, Server, Value}; +use crate::json; use actix_web::test; use meili_snap::{json_string, snapshot}; use meilisearch::Opt; use time::format_description::well_known::Rfc3339; use time::OffsetDateTime; use uuid::Uuid; -use crate::common::encoder::Encoder; -use crate::common::{default_settings, GetAllDocumentsOptions, Server, Value}; -use crate::json; /// This is the basic usage of our API and every other tests uses the content-type application/json #[actix_rt::test] From f3d691667d47985347766f134b294a2a8354bbe2 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 26 May 2025 13:39:15 +0300 Subject: [PATCH 055/292] Use a Regex in insta dynamic redaction to replace Uuids with [uuid] Signed-off-by: Martin Tzvetanov Grigorov --- crates/index-scheduler/src/error.rs | 13 +------------ crates/meili-snap/src/lib.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/crates/index-scheduler/src/error.rs b/crates/index-scheduler/src/error.rs index cbedf827d..cb798b385 100644 --- a/crates/index-scheduler/src/error.rs +++ b/crates/index-scheduler/src/error.rs @@ -126,7 +126,7 @@ pub enum Error { #[error(transparent)] Heed(#[from] heed::Error), #[error("{}", match .index_uid { - Some(uid) if !uid.is_empty() => format!("Index `{}`: {error}", Error::index_name(uid)), + Some(uid) if !uid.is_empty() => format!("Index `{}`: {error}", uid), _ => format!("{error}") })] Milli { error: milli::Error, index_uid: Option }, @@ -177,17 +177,6 @@ pub enum Error { PlannedFailure, } -impl Error { - #[inline] - fn index_name(index_name: &str) -> &str { - if uuid::Uuid::parse_str(index_name).is_ok() { - "[uuid]" - } else { - index_name - } - } -} - #[derive(Debug, thiserror::Error)] #[error( "{disabled_action} requires enabling the `{feature}` experimental feature. See {issue_link}" diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 30769c7c1..0f709b3de 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -55,6 +55,14 @@ pub fn default_snapshot_settings_for_test<'a>( } }); + settings.add_dynamic_redaction(".error.message", |content, _content_path| match &content { + Content::String(s) => { + let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "$before[uuid]$after"); + Content::String(uuid_replaced.to_string()) + } + _ => content, + }); + let test_name = test_name.strip_suffix("::{{closure}}").unwrap_or(test_name); let test_name = test_name.rsplit("::").next().unwrap().to_owned(); From 3e0de6cb83a219a38428a4c68b5b6217c4b8fb91 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 27 May 2025 14:39:45 +0300 Subject: [PATCH 056/292] Wait for the batched tasks bu their real uid. Some of them succeed, others fail. Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/documents/add_documents.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index efe1bfbf0..35f3d793a 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -2924,8 +2924,10 @@ async fn batch_several_documents_addition() { } // wait first batch of documents to finish - futures::future::join_all(waiter).await; - index.wait_task(4).await.succeeded(); + let finished_tasks = futures::future::join_all(waiter).await; + for (task, _code) in finished_tasks { + index.wait_task(task.uid()).await; + } // run a second completely failing batch documents[40] = json!({"title": "error", "desc": "error"}); @@ -2936,8 +2938,10 @@ async fn batch_several_documents_addition() { waiter.push(index.add_documents(json!(chunk), Some("id"))); } // wait second batch of documents to finish - futures::future::join_all(waiter).await; - index.wait_task(9).await.failed(); + let finished_tasks = futures::future::join_all(waiter).await; + for (task, _code) in finished_tasks { + index.wait_task(task.uid()).await; + } let (response, _code) = index.filtered_tasks(&[], &["failed"], &[]).await; From ce65ad213bf85fcc8ec1fb1d7534f30688160eb1 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 27 May 2025 16:27:08 +0300 Subject: [PATCH 057/292] Add dynamic redactions for `uid`, `batchUid` and `taskUid` Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/documents/add_documents.rs | 286 +++++++++--------- 1 file changed, 142 insertions(+), 144 deletions(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 35f3d793a..99aa566d7 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -34,16 +34,16 @@ async fn add_documents_test_json_content_types() { let body = test::read_body(res).await; let response: Value = serde_json::from_slice(&body).unwrap_or_default(); snapshot!(status_code, @"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); // put let req = test::TestRequest::put() @@ -56,10 +56,10 @@ async fn add_documents_test_json_content_types() { let body = test::read_body(res).await; let response: Value = serde_json::from_slice(&body).unwrap_or_default(); snapshot!(status_code, @"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "taskUid": 1, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", @@ -92,16 +92,16 @@ async fn add_single_document_test_json_content_types() { let body = test::read_body(res).await; let response: Value = serde_json::from_slice(&body).unwrap_or_default(); snapshot!(status_code, @"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); // put let req = test::TestRequest::put() @@ -114,10 +114,10 @@ async fn add_single_document_test_json_content_types() { let body = test::read_body(res).await; let response: Value = serde_json::from_slice(&body).unwrap_or_default(); snapshot!(status_code, @"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "taskUid": 1, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", @@ -152,16 +152,16 @@ async fn add_single_document_gzip_encoded() { let body = test::read_body(res).await; let response: Value = serde_json::from_slice(&body).unwrap_or_default(); snapshot!(status_code, @"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); // put let req = test::TestRequest::put() @@ -175,10 +175,10 @@ async fn add_single_document_gzip_encoded() { let body = test::read_body(res).await; let response: Value = serde_json::from_slice(&body).unwrap_or_default(); snapshot!(status_code, @"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "taskUid": 1, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", @@ -255,7 +255,7 @@ async fn add_single_document_with_every_encoding() { // post let document = serde_json::to_string(&document).unwrap(); - for (task_uid, encoder) in Encoder::iterator().enumerate() { + for encoder in Encoder::iterator() { let mut req = test::TestRequest::post() .uri(format!("/indexes/{index_name}/documents").as_str()) .set_payload(encoder.encode(document.clone())) @@ -268,9 +268,8 @@ async fn add_single_document_with_every_encoding() { let res = test::call_service(&app, req).await; let status_code = res.status(); let body = test::read_body(res).await; - let response: Value = serde_json::from_slice(&body).unwrap_or_default(); + let _response: Value = serde_json::from_slice(&body).unwrap_or_default(); assert_eq!(status_code, 202); - assert_eq!(response["taskUid"], task_uid); } } @@ -285,20 +284,20 @@ async fn add_csv_document() { let (response, code) = index.raw_update_documents(document, Some("text/csv"), "").await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); let response = index.wait_task(response.uid()).await.succeeded(); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -350,20 +349,20 @@ async fn add_csv_document_with_types() { let (response, code) = index.raw_update_documents(document, Some("text/csv"), "").await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); let response = index.wait_task(response.uid()).await.succeeded(); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -426,20 +425,20 @@ async fn add_csv_document_with_custom_delimiter() { let (response, code) = index.raw_update_documents(document, Some("text/csv"), "?csvDelimiter=|").await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); let response = index.wait_task(response.uid()).await.succeeded(); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -991,17 +990,16 @@ async fn add_documents_no_index_creation() { let (response, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - assert_eq!(response["taskUid"], 0); index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.get_task(0).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1061,26 +1059,26 @@ async fn document_addition_with_primary_key() { ]); let (response, code) = index.add_documents(documents, Some("primary")).await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.get_task(response.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1171,16 +1169,16 @@ async fn replace_document() { let (response, code) = index.add_documents(documents, None).await; snapshot!(code,@"202 Accepted"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "documentAdditionOrUpdate", "enqueuedAt": "[date]" } - "###); + "#); index.wait_task(response.uid()).await.succeeded(); @@ -1198,11 +1196,11 @@ async fn replace_document() { let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1369,11 +1367,11 @@ async fn error_add_documents_bad_document_id() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -1393,7 +1391,7 @@ async fn error_add_documents_bad_document_id() { "startedAt": "[date]", "finishedAt": "[date]" } - "###); + "#); // More than 512 bytes let documents = json!([ @@ -1406,11 +1404,11 @@ async fn error_add_documents_bad_document_id() { index.wait_task(value.uid()).await.failed(); let (response, code) = index.get_task(value.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 2, - "batchUid": 2, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -1443,11 +1441,11 @@ async fn error_add_documents_bad_document_id() { index.wait_task(value.uid()).await.failed(); let (response, code) = index.get_task(value.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 3, - "batchUid": 3, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -1485,11 +1483,11 @@ async fn error_add_documents_missing_document_id() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -1509,7 +1507,7 @@ async fn error_add_documents_missing_document_id() { "startedAt": "[date]", "finishedAt": "[date]" } - "###); + "#); } #[actix_rt::test] @@ -1795,11 +1793,11 @@ async fn add_documents_with_geo_field() { let (task, _status_code) = index.add_documents(documents, None).await; let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1814,7 +1812,7 @@ async fn add_documents_with_geo_field() { "startedAt": "[date]", "finishedAt": "[date]" } - "###); + "#); let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; @@ -1919,11 +1917,11 @@ async fn update_documents_with_geo_field() { let (task, _status_code) = index.add_documents(documents, None).await; let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1938,7 +1936,7 @@ async fn update_documents_with_geo_field() { "startedAt": "[date]", "finishedAt": "[date]" } - "###); + "#); let (response, code) = index.search_post(json!({"sort": ["_geoPoint(10,0):asc"]})).await; snapshot!(code, @"200 OK"); @@ -1988,11 +1986,11 @@ async fn update_documents_with_geo_field() { ]); let (task, _status_code) = index.update_documents(updated_documents, None).await; let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 2, - "batchUid": 2, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -2104,11 +2102,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".indexUid" => "[uuid]" }), - @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".indexUid" => "[uuid]" }), + @r#" { - "uid": 2, - "batchUid": 2, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2128,7 +2126,7 @@ async fn add_documents_invalid_geo_field() { "startedAt": "[date]", "finishedAt": "[date]" } - "###); + "#); // _geo is an object but is missing both the lat and lng let documents = json!([ @@ -2142,11 +2140,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 3, - "batchUid": 3, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2180,11 +2178,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 4, - "batchUid": 4, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2218,11 +2216,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 5, - "batchUid": 5, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2256,11 +2254,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 6, - "batchUid": 6, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2294,11 +2292,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 7, - "batchUid": 7, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2332,11 +2330,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 8, - "batchUid": 8, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2370,11 +2368,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 9, - "batchUid": 9, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2408,11 +2406,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 10, - "batchUid": 10, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2446,11 +2444,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 11, - "batchUid": 11, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2484,11 +2482,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 12, - "batchUid": 12, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2522,11 +2520,11 @@ async fn add_documents_invalid_geo_field() { index.wait_task(task.uid()).await.failed(); let (response, code) = index.get_task(task.uid()).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 13, - "batchUid": 13, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2561,11 +2559,11 @@ async fn add_documents_invalid_geo_field() { let (response, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); let response = index.wait_task(response.uid()).await.failed(); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 14, - "batchUid": 14, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2598,11 +2596,11 @@ async fn add_documents_invalid_geo_field() { let (response, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); let response = index.wait_task(response.uid()).await.failed(); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 15, - "batchUid": 15, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2635,11 +2633,11 @@ async fn add_documents_invalid_geo_field() { let (response, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); let response = index.wait_task(response.uid()).await.failed(); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 16, - "batchUid": 16, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2773,11 +2771,11 @@ async fn error_primary_key_inference() { let (response, code) = index.get_task(task.uid()).await; assert_eq!(code, 200); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), - @r###" + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + @r#" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2797,7 +2795,7 @@ async fn error_primary_key_inference() { "startedAt": "[date]", "finishedAt": "[date]" } - "###); + "#); let documents = json!([ { @@ -2814,11 +2812,11 @@ async fn error_primary_key_inference() { let (response, code) = index.get_task(task.uid()).await; assert_eq!(code, 200); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentAdditionOrUpdate", @@ -2853,11 +2851,11 @@ async fn error_primary_key_inference() { let (response, code) = index.get_task(task.uid()).await; assert_eq!(code, 200); - snapshot!(json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 2, - "batchUid": 2, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", From 36f0a1492ce7f4185381c99b286d03f919d8a0e9 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Wed, 28 May 2025 14:17:54 +0300 Subject: [PATCH 058/292] Apply suggestions from code review Co-authored-by: Tamo --- crates/meilisearch/tests/documents/add_documents.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 99aa566d7..522fc530b 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -991,11 +991,9 @@ async fn add_documents_no_index_creation() { let (response, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - index.wait_task(response.uid()).await.succeeded(); - - let (response, code) = index.get_task(0).await; + let response = index.wait_task(response.uid()).await.succeeded(); snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(response, @r###" { "uid": "[uid]", From c13efde04241d496b2eada49c8da39c0f24cbb0b Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 28 May 2025 14:35:50 +0300 Subject: [PATCH 059/292] uuid is a production dependency of meili-snap Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/meili-snap/Cargo.toml b/crates/meili-snap/Cargo.toml index 9dba56256..be96769ab 100644 --- a/crates/meili-snap/Cargo.toml +++ b/crates/meili-snap/Cargo.toml @@ -16,6 +16,4 @@ insta = { version = "=1.39.0", features = ["json", "redactions"] } md5 = "0.7.0" once_cell = "1.20" regex-lite = "0.1.6" - -[dev-dependencies] uuid = { version = "1.17.0", features = ["v4"] } From 02929e241b8af615f149ea44e0738ab99d33c37d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 28 May 2025 14:36:13 +0300 Subject: [PATCH 060/292] Update the status code Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/documents/add_documents.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/documents/add_documents.rs b/crates/meilisearch/tests/documents/add_documents.rs index 522fc530b..1cf492fc0 100644 --- a/crates/meilisearch/tests/documents/add_documents.rs +++ b/crates/meilisearch/tests/documents/add_documents.rs @@ -992,7 +992,7 @@ async fn add_documents_no_index_creation() { snapshot!(code, @"202 Accepted"); let response = index.wait_task(response.uid()).await.succeeded(); - snapshot!(code, @"200 OK"); + snapshot!(code, @"202 Accepted"); snapshot!(response, @r###" { From 43ec97fe457be2e01fde6a502044037e9bdf4c02 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 28 May 2025 15:01:04 +0300 Subject: [PATCH 061/292] format the code Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 0f709b3de..1641a6335 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -45,14 +45,12 @@ pub fn default_snapshot_settings_for_test<'a>( settings.add_dynamic_redaction(".message", uuid_in_message_redaction); settings.add_dynamic_redaction(".error.message", uuid_in_message_redaction); - settings.add_dynamic_redaction(".indexUid", |content, _content_path| { - match &content { - Content::String(s) => match uuid::Uuid::parse_str(s) { - Ok(_) => Content::String("[uuid]".to_owned()), - Err(_) => content, - }, - _ => content, - } + settings.add_dynamic_redaction(".indexUid", |content, _content_path| match &content { + Content::String(s) => match uuid::Uuid::parse_str(s) { + Ok(_) => Content::String("[uuid]".to_owned()), + Err(_) => content, + }, + _ => content, }); settings.add_dynamic_redaction(".error.message", |content, _content_path| match &content { From 7e9909ee45177f14eb39d77fab76f36858b11c99 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 19 May 2025 16:10:17 +0300 Subject: [PATCH 062/292] perf: Faster index::update_index IT tests Use a shared server where possible. Assert succeeded/failed task waits. Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/index.rs | 4 ++ .../meilisearch/tests/index/update_index.rs | 55 ++++++++++--------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/crates/meilisearch/tests/common/index.rs b/crates/meilisearch/tests/common/index.rs index 09a7d623c..24db6776b 100644 --- a/crates/meilisearch/tests/common/index.rs +++ b/crates/meilisearch/tests/common/index.rs @@ -29,6 +29,10 @@ impl<'a> Index<'a, Owned> { } } + pub fn with_encoder(&self, encoder: Encoder) -> Index<'a, Owned> { + Index { uid: self.uid.clone(), service: self.service, encoder, marker: PhantomData } + } + pub async fn load_test_set(&self) -> u64 { let url = format!("/indexes/{}/documents", urlencode(self.uid.as_ref())); let (response, code) = self diff --git a/crates/meilisearch/tests/index/update_index.rs b/crates/meilisearch/tests/index/update_index.rs index a9b02e7d4..8880314d4 100644 --- a/crates/meilisearch/tests/index/update_index.rs +++ b/crates/meilisearch/tests/index/update_index.rs @@ -7,15 +7,16 @@ use crate::json; #[actix_rt::test] async fn update_primary_key() { - let server = Server::new().await; - let index = server.index("test"); - let (_, code) = index.create(None).await; + let server = Server::new_shared(); + let index = server.unique_index(); + let (task, code) = index.create(None).await; assert_eq!(code, 202); + index.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = index.update(Some("primary")).await; - let response = index.wait_task(task.uid()).await; + let response = index.wait_task(task.uid()).await.succeeded(); assert_eq!(response["status"], "succeeded"); @@ -23,7 +24,7 @@ async fn update_primary_key() { assert_eq!(code, 200); - assert_eq!(response["uid"], "test"); + assert_eq!(response["uid"], index.uid); assert!(response.get("createdAt").is_some()); assert!(response.get("updatedAt").is_some()); @@ -39,24 +40,25 @@ async fn update_primary_key() { #[actix_rt::test] async fn create_and_update_with_different_encoding() { - let server = Server::new().await; - let index = server.index_with_encoder("test", Encoder::Gzip); - let (_, code) = index.create(None).await; + let server = Server::new_shared(); + let index = server.unique_index_with_encoder(Encoder::Gzip); + let (create_task, code) = index.create(None).await; assert_eq!(code, 202); + index.wait_task(create_task.uid()).await.succeeded(); - let index = server.index_with_encoder("test", Encoder::Brotli); + let index = index.with_encoder(Encoder::Brotli); let (task, _status_code) = index.update(Some("primary")).await; - let response = index.wait_task(task.uid()).await; + let response = index.wait_task(task.uid()).await.succeeded(); assert_eq!(response["status"], "succeeded"); } #[actix_rt::test] async fn update_nothing() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task1, code) = index.create(None).await; assert_eq!(code, 202); @@ -67,18 +69,19 @@ async fn update_nothing() { assert_eq!(code, 202); - let response = index.wait_task(task2.uid()).await; + let response = index.wait_task(task2.uid()).await.succeeded(); assert_eq!(response["status"], "succeeded"); } #[actix_rt::test] async fn error_update_existing_primary_key() { - let server = Server::new().await; - let index = server.index("test"); - let (_response, code) = index.create(Some("id")).await; + let server = Server::new_shared(); + let index = server.unique_index(); + let (create_task, code) = index.create(Some("id")).await; assert_eq!(code, 202); + index.wait_task(create_task.uid()).await.succeeded(); let documents = json!([ { @@ -86,16 +89,17 @@ async fn error_update_existing_primary_key() { "content": "foobar" } ]); - index.add_documents(documents, None).await; + let (add_docs_task, add_docs_status_code) = index.add_documents(documents, None).await; + assert_eq!(add_docs_status_code, 202); + index.wait_task(add_docs_task.uid()).await.succeeded(); - let (task, code) = index.update(Some("primary")).await; + let (update_task, code) = index.update(Some("primary")).await; assert_eq!(code, 202); - - let response = index.wait_task(task.uid()).await; + let response = index.wait_task(update_task.uid()).await.failed(); let expected_response = json!({ - "message": "Index `test`: Index already has a primary key: `id`.", + "message": format!("Index `{}`: Index already has a primary key: `id`.", index.uid), "code": "index_primary_key_already_exists", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_primary_key_already_exists" @@ -106,15 +110,16 @@ async fn error_update_existing_primary_key() { #[actix_rt::test] async fn error_update_unexisting_index() { - let server = Server::new().await; - let (task, code) = server.index("test").update(None).await; + let server = Server::new_shared(); + let index = server.unique_index(); + let (task, code) = index.update(None).await; assert_eq!(code, 202); - let response = server.index("test").wait_task(task.uid()).await; + let response = index.wait_task(task.uid()).await.failed(); let expected_response = json!({ - "message": "Index `test` not found.", + "message": format!("Index `{}` not found.", index.uid), "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" From f77abc9dc833a669eb110a3d5fa38f5d6c437fc5 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Tue, 20 May 2025 11:49:27 +0300 Subject: [PATCH 063/292] Update crates/meilisearch/tests/index/update_index.rs Co-authored-by: Tamo --- crates/meilisearch/tests/index/update_index.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/meilisearch/tests/index/update_index.rs b/crates/meilisearch/tests/index/update_index.rs index 8880314d4..bc432fbd9 100644 --- a/crates/meilisearch/tests/index/update_index.rs +++ b/crates/meilisearch/tests/index/update_index.rs @@ -17,9 +17,6 @@ async fn update_primary_key() { let (task, _status_code) = index.update(Some("primary")).await; let response = index.wait_task(task.uid()).await.succeeded(); - - assert_eq!(response["status"], "succeeded"); - let (response, code) = index.get().await; assert_eq!(code, 200); From 025df397c037c0e02bbd2e76f5eddac6c1f7576b Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Tue, 20 May 2025 11:49:38 +0300 Subject: [PATCH 064/292] Update crates/meilisearch/tests/index/update_index.rs Co-authored-by: Tamo --- crates/meilisearch/tests/index/update_index.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/meilisearch/tests/index/update_index.rs b/crates/meilisearch/tests/index/update_index.rs index bc432fbd9..7f8325020 100644 --- a/crates/meilisearch/tests/index/update_index.rs +++ b/crates/meilisearch/tests/index/update_index.rs @@ -47,9 +47,7 @@ async fn create_and_update_with_different_encoding() { let index = index.with_encoder(Encoder::Brotli); let (task, _status_code) = index.update(Some("primary")).await; - let response = index.wait_task(task.uid()).await.succeeded(); - - assert_eq!(response["status"], "succeeded"); + index.wait_task(task.uid()).await.succeeded(); } #[actix_rt::test] From 65354b414a6af43e06f53cb67677c21d4163cabe Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Tue, 20 May 2025 11:49:45 +0300 Subject: [PATCH 065/292] Update crates/meilisearch/tests/index/update_index.rs Co-authored-by: Tamo --- crates/meilisearch/tests/index/update_index.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/meilisearch/tests/index/update_index.rs b/crates/meilisearch/tests/index/update_index.rs index 7f8325020..dd7ab9df7 100644 --- a/crates/meilisearch/tests/index/update_index.rs +++ b/crates/meilisearch/tests/index/update_index.rs @@ -64,9 +64,7 @@ async fn update_nothing() { assert_eq!(code, 202); - let response = index.wait_task(task2.uid()).await.succeeded(); - - assert_eq!(response["status"], "succeeded"); + index.wait_task(task2.uid()).await.succeeded(); } #[actix_rt::test] From f87e46cc16fa17f0d9d09150c31e8578b840917c Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 20 May 2025 13:43:48 +0300 Subject: [PATCH 066/292] Ignore the result from #wait_task() Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/index/update_index.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/index/update_index.rs b/crates/meilisearch/tests/index/update_index.rs index dd7ab9df7..c32828c9e 100644 --- a/crates/meilisearch/tests/index/update_index.rs +++ b/crates/meilisearch/tests/index/update_index.rs @@ -15,8 +15,8 @@ async fn update_primary_key() { index.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = index.update(Some("primary")).await; - - let response = index.wait_task(task.uid()).await.succeeded(); + index.wait_task(task.uid()).await.succeeded(); + let (response, code) = index.get().await; assert_eq!(code, 200); From b658e38acdbc3c2b52b4eebcffc278b0af605c6e Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 20 May 2025 13:53:51 +0300 Subject: [PATCH 067/292] Fix formatting Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/index/update_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/index/update_index.rs b/crates/meilisearch/tests/index/update_index.rs index c32828c9e..a17e7c63f 100644 --- a/crates/meilisearch/tests/index/update_index.rs +++ b/crates/meilisearch/tests/index/update_index.rs @@ -16,7 +16,7 @@ async fn update_primary_key() { let (task, _status_code) = index.update(Some("primary")).await; index.wait_task(task.uid()).await.succeeded(); - + let (response, code) = index.get().await; assert_eq!(code, 200); From b4ca0a8c985b07161550a36fe012f834f961aa00 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 23 May 2025 23:44:07 +0300 Subject: [PATCH 068/292] Update the tests related to updating indices Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/index.rs | 22 ++++++++++++++++ .../meilisearch/tests/index/update_index.rs | 26 ++++--------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/crates/meilisearch/tests/common/index.rs b/crates/meilisearch/tests/common/index.rs index 24db6776b..e324d2ff5 100644 --- a/crates/meilisearch/tests/common/index.rs +++ b/crates/meilisearch/tests/common/index.rs @@ -294,6 +294,20 @@ impl Index<'_, Shared> { } (task, code) } + + pub async fn update_index_fail(&self, primary_key: Option<&str>) -> (Value, StatusCode) { + let (mut task, code) = self._update(primary_key).await; + if code.is_success() { + task = self.wait_task(task.uid()).await; + if task.is_success() { + panic!( + "`update_index_fail` succeeded: {}", + serde_json::to_string_pretty(&task).unwrap() + ); + } + } + (task, code) + } } #[allow(dead_code)] @@ -337,6 +351,14 @@ impl Index<'_, State> { self.service.post_encoded("/indexes", body, self.encoder).await } + pub(super) async fn _update(&self, primary_key: Option<&str>) -> (Value, StatusCode) { + let body = json!({ + "primaryKey": primary_key, + }); + let url = format!("/indexes/{}", urlencode(self.uid.as_ref())); + self.service.patch_encoded(url, body, self.encoder).await + } + pub(super) async fn _delete(&self) -> (Value, StatusCode) { let url = format!("/indexes/{}", urlencode(self.uid.as_ref())); self.service.delete(url).await diff --git a/crates/meilisearch/tests/index/update_index.rs b/crates/meilisearch/tests/index/update_index.rs index a17e7c63f..291700728 100644 --- a/crates/meilisearch/tests/index/update_index.rs +++ b/crates/meilisearch/tests/index/update_index.rs @@ -2,7 +2,7 @@ use time::format_description::well_known::Rfc3339; use time::OffsetDateTime; use crate::common::encoder::Encoder; -use crate::common::Server; +use crate::common::{shared_does_not_exists_index, shared_index_with_documents, Server}; use crate::json; #[actix_rt::test] @@ -69,24 +69,9 @@ async fn update_nothing() { #[actix_rt::test] async fn error_update_existing_primary_key() { - let server = Server::new_shared(); - let index = server.unique_index(); - let (create_task, code) = index.create(Some("id")).await; + let index = shared_index_with_documents().await; - assert_eq!(code, 202); - index.wait_task(create_task.uid()).await.succeeded(); - - let documents = json!([ - { - "id": "11", - "content": "foobar" - } - ]); - let (add_docs_task, add_docs_status_code) = index.add_documents(documents, None).await; - assert_eq!(add_docs_status_code, 202); - index.wait_task(add_docs_task.uid()).await.succeeded(); - - let (update_task, code) = index.update(Some("primary")).await; + let (update_task, code) = index.update_index_fail(Some("primary")).await; assert_eq!(code, 202); let response = index.wait_task(update_task.uid()).await.failed(); @@ -103,9 +88,8 @@ async fn error_update_existing_primary_key() { #[actix_rt::test] async fn error_update_unexisting_index() { - let server = Server::new_shared(); - let index = server.unique_index(); - let (task, code) = index.update(None).await; + let index = shared_does_not_exists_index().await; + let (task, code) = index.update_index_fail(Some("my-primary-key")).await; assert_eq!(code, 202); From 44f812c36d958a3fd2477a943b649064e6fe8512 Mon Sep 17 00:00:00 2001 From: Nate Nethercott <53127799+nnethercott@users.noreply.github.com> Date: Wed, 28 May 2025 15:38:12 +0200 Subject: [PATCH 069/292] Update crates/milli/src/update/new/extract/faceted/extract_facets.rs Co-authored-by: Many the fish --- crates/milli/src/update/new/extract/faceted/extract_facets.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index a1d9e6553..9e5120bba 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -194,7 +194,7 @@ impl FacetedDocidsExtractor { } // 2. Maybe update geo - if is_geo_enabled && has_changed_for_geo_fields { + if is_geo_enabled && inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)? { extract_geo_document( inner.current(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), From b06cc1e0a2bba4f89fab8e80fd6e7e08a5670651 Mon Sep 17 00:00:00 2001 From: Nate Nethercott <53127799+nnethercott@users.noreply.github.com> Date: Wed, 28 May 2025 15:38:23 +0200 Subject: [PATCH 070/292] Update crates/milli/src/update/new/extract/faceted/extract_facets.rs Co-authored-by: Many the fish --- crates/milli/src/update/new/extract/faceted/extract_facets.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index 9e5120bba..2160c16eb 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -91,7 +91,8 @@ impl FacetedDocidsExtractor { let mut del_add_facet_value = DelAddFacetValue::new(&context.doc_alloc); let docid = document_change.docid(); - // Macro expanding to an insertion/deletion facet fn + // Macro expanding to an insertion/deletion facet fn, + // using a macro avoid to borrow the parameters as mutable in both closures at the same time by postponing their creation macro_rules! facet_fn { (del) => { |fid: FieldId, meta: Metadata, depth: perm_json_p::Depth, value: &Value| { From 1811168b965fbfe695bbd5bfec4904d6bc96aab6 Mon Sep 17 00:00:00 2001 From: nnethercott Date: Wed, 28 May 2025 15:45:13 +0200 Subject: [PATCH 071/292] remove duplicated check on geo field changes --- .../src/update/new/extract/faceted/extract_facets.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/milli/src/update/new/extract/faceted/extract_facets.rs b/crates/milli/src/update/new/extract/faceted/extract_facets.rs index 2160c16eb..517ef3f2d 100644 --- a/crates/milli/src/update/new/extract/faceted/extract_facets.rs +++ b/crates/milli/src/update/new/extract/faceted/extract_facets.rs @@ -91,8 +91,8 @@ impl FacetedDocidsExtractor { let mut del_add_facet_value = DelAddFacetValue::new(&context.doc_alloc); let docid = document_change.docid(); - // Macro expanding to an insertion/deletion facet fn, - // using a macro avoid to borrow the parameters as mutable in both closures at the same time by postponing their creation + // Using a macro avoid borrowing the parameters as mutable in both closures at + // the same time by postponing their creation macro_rules! facet_fn { (del) => { |fid: FieldId, meta: Metadata, depth: perm_json_p::Depth, value: &Value| { @@ -168,8 +168,6 @@ impl FacetedDocidsExtractor { index, context.db_fields_ids_map, )?; - let has_changed_for_geo_fields = - inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)?; // 1. Maybe update doc if has_changed_for_facets { @@ -195,7 +193,9 @@ impl FacetedDocidsExtractor { } // 2. Maybe update geo - if is_geo_enabled && inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)? { + if is_geo_enabled + && inner.has_changed_for_geo_fields(rtxn, index, context.db_fields_ids_map)? + { extract_geo_document( inner.current(rtxn, index, context.db_fields_ids_map)?, inner.external_document_id(), From 3c13feebf7a193a99bf87ce6cc16fbf1c686cf2b Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 28 May 2025 17:44:38 +0200 Subject: [PATCH 072/292] Test that distinct is applied for hybrid search --- crates/meilisearch/tests/search/hybrid.rs | 86 +++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/crates/meilisearch/tests/search/hybrid.rs b/crates/meilisearch/tests/search/hybrid.rs index 3282a357a..3a8fb2b4c 100644 --- a/crates/meilisearch/tests/search/hybrid.rs +++ b/crates/meilisearch/tests/search/hybrid.rs @@ -76,6 +76,48 @@ static SINGLE_DOCUMENT_VEC: Lazy = Lazy::new(|| { }]) }); +static TEST_DISTINCT_DOCUMENTS: Lazy = Lazy::new(|| { + // for query "Captain Marvel" and vector [1.0, 1.0] + json!([ + { + "id": 0, + "search": "Captain Planet", + "desc": "#2 for keyword search, #3 for hybrid search", + "_vectors": { + "default": [-1.0, 0.0], + }, + "distinct": 0 + }, + { + "id": 1, + "search": "Captain Marvel", + "desc": "#1 for keyword search, #4 for hybrid search", + "_vectors": { + "default": [-1.0, -1.0], + }, + "distinct": 1 + }, + { + "id": 2, + "search": "Some Captain at least", + "desc": "#3 for keyword search, #1 for hybrid search", + "_vectors": { + "default": [1.0, 1.0], + }, + "distinct": 0 + }, + { + "id": 3, + "search": "Irrelevant Capitaine", + "desc": "#4 for keyword search, #2 for hybrid search", + "_vectors": { + "default": [1.0, 0.0], + }, + "distinct": 1 + }, + ]) +}); + static SIMPLE_SEARCH_DOCUMENTS: Lazy = Lazy::new(|| { json!([ { @@ -493,6 +535,50 @@ async fn query_combination() { snapshot!(response["semanticHitCount"], @"0"); } +// see +#[actix_rt::test] +async fn distinct_is_applied() { + let server = Server::new().await; + let index = index_with_documents_user_provided(&server, &TEST_DISTINCT_DOCUMENTS).await; + + let (response, code) = index.update_settings(json!({ "distinctAttribute": "distinct" } )).await; + assert_eq!(202, code, "{:?}", response); + index.wait_task(response.uid()).await.succeeded(); + + // pure keyword + let (response, code) = index + .search_post( + json!({"q": "Captain Marvel", "vector": [1.0, 1.0], "hybrid": {"semanticRatio": 0.0, "embedder": "default"}}), + ) + .await; + snapshot!(code, @"200 OK"); + snapshot!(response["hits"], @r###"[{"id":1,"search":"Captain Marvel","desc":"#1 for keyword search, #4 for hybrid search","distinct":1},{"id":0,"search":"Captain Planet","desc":"#2 for keyword search, #3 for hybrid search","distinct":0}]"###); + snapshot!(response["semanticHitCount"], @"null"); + snapshot!(response["estimatedTotalHits"], @"2"); + + // pure semantic + let (response, code) = index + .search_post( + json!({"q": "Captain Marvel", "vector": [1.0, 1.0], "hybrid": {"semanticRatio": 1.0, "embedder": "default"}}), + ) + .await; + snapshot!(code, @"200 OK"); + snapshot!(response["hits"], @r###"[{"id":2,"search":"Some Captain at least","desc":"#3 for keyword search, #1 for hybrid search","distinct":0},{"id":3,"search":"Irrelevant Capitaine","desc":"#4 for keyword search, #2 for hybrid search","distinct":1}]"###); + snapshot!(response["semanticHitCount"], @"2"); + snapshot!(response["estimatedTotalHits"], @"2"); + + // hybrid + let (response, code) = index + .search_post( + json!({"q": "Captain Marvel", "vector": [1.0, 1.0], "hybrid": {"semanticRatio": 0.5, "embedder": "default"}}), + ) + .await; + snapshot!(code, @"200 OK"); + snapshot!(response["hits"], @r###"[{"id":2,"search":"Some Captain at least","desc":"#3 for keyword search, #1 for hybrid search","distinct":0},{"id":1,"search":"Captain Marvel","desc":"#1 for keyword search, #4 for hybrid search","distinct":1}]"###); + snapshot!(response["semanticHitCount"], @"1"); + snapshot!(response["estimatedTotalHits"], @"2"); +} + #[actix_rt::test] async fn retrieve_vectors() { let server = Server::new().await; From fd4b192a39372320916f11fd9f5610b3647a6760 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 28 May 2025 17:57:31 +0200 Subject: [PATCH 073/292] Add distinct_fid function and expose distinct_single_docid --- crates/milli/src/search/new/bucket_sort.rs | 15 ++++----------- crates/milli/src/search/new/distinct.rs | 17 ++++++++++++++++- crates/milli/src/search/new/mod.rs | 4 ++-- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/crates/milli/src/search/new/bucket_sort.rs b/crates/milli/src/search/new/bucket_sort.rs index ca7a4a986..3c26cad5c 100644 --- a/crates/milli/src/search/new/bucket_sort.rs +++ b/crates/milli/src/search/new/bucket_sort.rs @@ -4,7 +4,9 @@ use super::logger::SearchLogger; use super::ranking_rules::{BoxRankingRule, RankingRuleQueryTrait}; use super::SearchContext; use crate::score_details::{ScoreDetails, ScoringStrategy}; -use crate::search::new::distinct::{apply_distinct_rule, distinct_single_docid, DistinctOutput}; +use crate::search::new::distinct::{ + apply_distinct_rule, distinct_fid, distinct_single_docid, DistinctOutput, +}; use crate::{Result, TimeBudget}; pub struct BucketSortOutput { @@ -35,16 +37,7 @@ pub fn bucket_sort<'ctx, Q: RankingRuleQueryTrait>( logger.ranking_rules(&ranking_rules); logger.initial_universe(universe); - let distinct_field = match distinct { - Some(distinct) => Some(distinct), - None => ctx.index.distinct_field(ctx.txn)?, - }; - - let distinct_fid = if let Some(field) = distinct_field { - ctx.index.fields_ids_map(ctx.txn)?.id(field) - } else { - None - }; + let distinct_fid = distinct_fid(distinct, ctx.index, ctx.txn)?; if universe.len() < from as u64 { return Ok(BucketSortOutput { diff --git a/crates/milli/src/search/new/distinct.rs b/crates/milli/src/search/new/distinct.rs index 17859b6f8..36172302a 100644 --- a/crates/milli/src/search/new/distinct.rs +++ b/crates/milli/src/search/new/distinct.rs @@ -9,7 +9,7 @@ use crate::heed_codec::facet::{ FacetGroupKey, FacetGroupKeyCodec, FacetGroupValueCodec, FieldDocIdFacetCodec, }; use crate::heed_codec::BytesRefCodec; -use crate::{Index, Result, SearchContext}; +use crate::{FieldId, Index, Result, SearchContext}; pub struct DistinctOutput { pub remaining: RoaringBitmap, @@ -121,3 +121,18 @@ pub fn facet_string_values<'a>( fn facet_values_prefix_key(distinct: u16, id: u32) -> [u8; FID_SIZE + DOCID_SIZE] { concat_arrays::concat_arrays!(distinct.to_be_bytes(), id.to_be_bytes()) } + +pub fn distinct_fid( + query_distinct_field: Option<&str>, + index: &Index, + rtxn: &RoTxn<'_>, +) -> Result> { + let distinct_field = match query_distinct_field { + Some(distinct) => Some(distinct), + None => index.distinct_field(rtxn)?, + }; + + let distinct_fid = + if let Some(field) = distinct_field { index.fields_ids_map(rtxn)?.id(field) } else { None }; + Ok(distinct_fid) +} diff --git a/crates/milli/src/search/new/mod.rs b/crates/milli/src/search/new/mod.rs index 0a3bc1b04..a65b4076b 100644 --- a/crates/milli/src/search/new/mod.rs +++ b/crates/milli/src/search/new/mod.rs @@ -28,6 +28,7 @@ use std::time::Duration; use bucket_sort::{bucket_sort, BucketSortOutput}; use charabia::{Language, TokenizerBuilder}; use db_cache::DatabaseCache; +pub use distinct::{distinct_fid, distinct_single_docid}; use exact_attribute::ExactAttribute; use graph_based_ranking_rule::{Exactness, Fid, Position, Proximity, Typo}; use heed::RoTxn; @@ -47,8 +48,7 @@ use sort::Sort; use self::distinct::facet_string_values; use self::geo_sort::GeoSort; -pub use self::geo_sort::Parameter as GeoSortParameter; -pub use self::geo_sort::Strategy as GeoSortStrategy; +pub use self::geo_sort::{Parameter as GeoSortParameter, Strategy as GeoSortStrategy}; use self::graph_based_ranking_rule::Words; use self::interner::Interned; use self::vector_sort::VectorSort; From 54f5e74744205f467ddbaa229adc8844c5767f44 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 28 May 2025 17:58:02 +0200 Subject: [PATCH 074/292] Support distinct in hybrid search --- crates/milli/src/search/hybrid.rs | 69 ++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/crates/milli/src/search/hybrid.rs b/crates/milli/src/search/hybrid.rs index e07f886c9..b63f6288f 100644 --- a/crates/milli/src/search/hybrid.rs +++ b/crates/milli/src/search/hybrid.rs @@ -1,11 +1,13 @@ use std::cmp::Ordering; +use heed::RoTxn; use itertools::Itertools; use roaring::RoaringBitmap; use crate::score_details::{ScoreDetails, ScoreValue, ScoringStrategy}; +use crate::search::new::{distinct_fid, distinct_single_docid}; use crate::search::SemanticSearch; -use crate::{MatchingWords, Result, Search, SearchResult}; +use crate::{Index, MatchingWords, Result, Search, SearchResult}; struct ScoreWithRatioResult { matching_words: MatchingWords, @@ -91,7 +93,10 @@ impl ScoreWithRatioResult { keyword_results: Self, from: usize, length: usize, - ) -> (SearchResult, u32) { + distinct: Option<&str>, + index: &Index, + rtxn: &RoTxn<'_>, + ) -> Result<(SearchResult, u32)> { #[derive(Clone, Copy)] enum ResultSource { Semantic, @@ -106,8 +111,9 @@ impl ScoreWithRatioResult { vector_results.document_scores.len() + keyword_results.document_scores.len(), ); - let mut documents_seen = RoaringBitmap::new(); - for ((docid, (main_score, _sub_score)), source) in vector_results + let distinct_fid = distinct_fid(distinct, index, rtxn)?; + let mut excluded_documents = RoaringBitmap::new(); + for res in vector_results .document_scores .into_iter() .zip(std::iter::repeat(ResultSource::Semantic)) @@ -121,13 +127,33 @@ impl ScoreWithRatioResult { compare_scores(left, right).is_ge() }, ) - // remove documents we already saw - .filter(|((docid, _), _)| documents_seen.insert(*docid)) + // remove documents we already saw and apply distinct rule + .filter_map(|item @ ((docid, _), _)| { + if !excluded_documents.insert(docid) { + // the document was already added, or is indistinct from an already-added document. + return None; + } + + if let Some(distinct_fid) = distinct_fid { + if let Err(error) = distinct_single_docid( + index, + rtxn, + distinct_fid, + docid, + &mut excluded_documents, + ) { + return Some(Err(error)); + } + } + + Some(Ok(item)) + }) // start skipping **after** the filter .skip(from) // take **after** skipping .take(length) { + let ((docid, (main_score, _sub_score)), source) = res?; if let ResultSource::Semantic = source { semantic_hit_count += 1; } @@ -136,10 +162,24 @@ impl ScoreWithRatioResult { document_scores.push(main_score); } - ( + // compute the set of candidates from both sets + let candidates = vector_results.candidates | keyword_results.candidates; + let must_remove_redundant_candidates = distinct_fid.is_some(); + let candidates = if must_remove_redundant_candidates { + // patch-up the candidates to remove the indistinct documents, then add back the actual hits + let mut candidates = candidates - excluded_documents; + for docid in &documents_ids { + candidates.insert(*docid); + } + candidates + } else { + candidates + }; + + Ok(( SearchResult { matching_words: keyword_results.matching_words, - candidates: vector_results.candidates | keyword_results.candidates, + candidates, documents_ids, document_scores, degraded: vector_results.degraded | keyword_results.degraded, @@ -147,7 +187,7 @@ impl ScoreWithRatioResult { | keyword_results.used_negative_operator, }, semantic_hit_count, - ) + )) } } @@ -226,8 +266,15 @@ impl Search<'_> { let keyword_results = ScoreWithRatioResult::new(keyword_results, 1.0 - semantic_ratio); let vector_results = ScoreWithRatioResult::new(vector_results, semantic_ratio); - let (merge_results, semantic_hit_count) = - ScoreWithRatioResult::merge(vector_results, keyword_results, self.offset, self.limit); + let (merge_results, semantic_hit_count) = ScoreWithRatioResult::merge( + vector_results, + keyword_results, + self.offset, + self.limit, + search.distinct.as_deref(), + search.index, + search.rtxn, + )?; assert!(merge_results.documents_ids.len() <= self.limit); Ok((merge_results, Some(semantic_hit_count))) } From d329e8625064e12c548250b498a9aa720de4470a Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 08:42:10 +0300 Subject: [PATCH 075/292] tests: Use shared server + unique server where possible Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/errors.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/meilisearch/tests/search/errors.rs b/crates/meilisearch/tests/search/errors.rs index 5e54bcff1..ba7853d11 100644 --- a/crates/meilisearch/tests/search/errors.rs +++ b/crates/meilisearch/tests/search/errors.rs @@ -1196,10 +1196,8 @@ async fn search_on_unknown_field_plus_joker() { #[actix_rt::test] async fn distinct_at_search_time() { - let server = Server::new().await; - let index = server.index("test"); - let (task, _) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, _code) = index.add_documents(json!([{"id": 1, "color": "Doggo", "machin": "Action"}]), None).await; index.wait_task(response.uid()).await.succeeded(); @@ -1209,7 +1207,7 @@ async fn distinct_at_search_time() { snapshot!(code, @"400 Bad Request"); snapshot!(response, @r###" { - "message": "Index `test`: Attribute `doggo.truc` is not filterable and thus, cannot be used as distinct attribute. This index does not have configured filterable attributes.", + "message": "Index `[uuid]`: Attribute `doggo.truc` is not filterable and thus, cannot be used as distinct attribute. This index does not have configured filterable attributes.", "code": "invalid_search_distinct", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_distinct" @@ -1224,7 +1222,7 @@ async fn distinct_at_search_time() { snapshot!(code, @"400 Bad Request"); snapshot!(response, @r###" { - "message": "Index `test`: Attribute `doggo.truc` is not filterable and thus, cannot be used as distinct attribute. Available filterable attributes patterns are: `color, machin`.", + "message": "Index `[uuid]`: Attribute `doggo.truc` is not filterable and thus, cannot be used as distinct attribute. Available filterable attributes patterns are: `color, machin`.", "code": "invalid_search_distinct", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_distinct" @@ -1239,7 +1237,7 @@ async fn distinct_at_search_time() { snapshot!(code, @"400 Bad Request"); snapshot!(response, @r###" { - "message": "Index `test`: Attribute `doggo.truc` is not filterable and thus, cannot be used as distinct attribute. Available filterable attributes patterns are: `color, <..hidden-attributes>`.", + "message": "Index `[uuid]`: Attribute `doggo.truc` is not filterable and thus, cannot be used as distinct attribute. Available filterable attributes patterns are: `color, <..hidden-attributes>`.", "code": "invalid_search_distinct", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_distinct" From 8b8b0d802c31016e6d02645ed1bdccd584dd906d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 08:53:10 +0300 Subject: [PATCH 076/292] tests: Faster search::facet_search IT tests Use shared server + unique indices where possible. Assert .succeeded() for the waited tasks. Drop usage of dbg!() in the assertions. It caused noise in the logs Signed-off-by: Martin Tzvetanov Grigorov --- .../meilisearch/tests/search/facet_search.rs | 168 +++++++++--------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/crates/meilisearch/tests/search/facet_search.rs b/crates/meilisearch/tests/search/facet_search.rs index 65e204702..87af125f0 100644 --- a/crates/meilisearch/tests/search/facet_search.rs +++ b/crates/meilisearch/tests/search/facet_search.rs @@ -50,13 +50,13 @@ async fn test_settings_documents_indexing_swapping_and_facet_search( let (task, code) = index.add_documents(documents.clone(), None).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + let response = index.wait_task(task.uid()).await.succeeded(); + assert!(response.is_success(), "{response:?}"); let (task, code) = index.update_settings(settings.clone()).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + let response = index.wait_task(task.uid()).await.succeeded(); + assert!(response.is_success(), "{response:?}"); let (response, code) = index.facet_search(query.clone()).await; insta::allow_duplicates! { @@ -65,21 +65,21 @@ async fn test_settings_documents_indexing_swapping_and_facet_search( let (task, code) = server.delete_index("test").await; assert_eq!(code, 202, "{}", task); - let response = server.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + let response = server.wait_task(task.uid()).await.succeeded(); + assert!(response.is_success(), "{response:?}"); eprintln!("Settings -> Documents -> test"); let index = server.index("test"); let (task, code) = index.update_settings(settings.clone()).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + let response = index.wait_task(task.uid()).await.succeeded(); + assert!(response.is_success(), "{response:?}"); let (task, code) = index.add_documents(documents.clone(), None).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + let response = index.wait_task(task.uid()).await.succeeded(); + assert!(response.is_success(), "{response:?}"); let (response, code) = index.facet_search(query.clone()).await; insta::allow_duplicates! { @@ -88,14 +88,14 @@ async fn test_settings_documents_indexing_swapping_and_facet_search( let (task, code) = server.delete_index("test").await; assert_eq!(code, 202, "{}", task); - let response = server.wait_task(task.uid()).await; - assert!(response.is_success(), "{:?}", response); + let response = server.wait_task(task.uid()).await.succeeded(); + assert!(response.is_success(), "{response:?}"); } #[actix_rt::test] async fn simple_facet_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_filterable_attributes(json!(["genres"])).await; @@ -105,20 +105,20 @@ async fn simple_facet_search() { let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 200, "{}", response); - assert_eq!(dbg!(response)["facetHits"].as_array().unwrap().len(), 2); + assert_eq!(code, 200, "{response}"); + assert_eq!(response["facetHits"].as_array().unwrap().len(), 2); let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "adventure"})).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["facetHits"].as_array().unwrap().len(), 1); } #[actix_rt::test] async fn simple_facet_search_on_movies() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -212,23 +212,23 @@ async fn simple_facet_search_on_movies() { ]); let (response, code) = index.update_settings_filterable_attributes(json!(["genres", "color"])).await; - assert_eq!(202, code, "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!(202, code, "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let (response, _code) = index.add_documents(documents, None).await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.facet_search(json!({"facetQuery": "", "facetName": "genres", "q": "" })).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(response["facetHits"], @r###"[{"value":"Action","count":2},{"value":"Adventure","count":3},{"value":"Drama","count":3},{"value":"Fantasy","count":1},{"value":"Romance","count":1},{"value":"Science Fiction","count":1}]"###); } #[actix_rt::test] async fn advanced_facet_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_filterable_attributes(json!(["genres"])).await; @@ -251,8 +251,8 @@ async fn advanced_facet_search() { #[actix_rt::test] async fn more_advanced_facet_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_filterable_attributes(json!(["genres"])).await; @@ -275,8 +275,8 @@ async fn more_advanced_facet_search() { #[actix_rt::test] async fn simple_facet_search_with_max_values() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_faceting(json!({ "maxValuesPerFacet": 1 })).await; @@ -287,14 +287,14 @@ async fn simple_facet_search_with_max_values() { let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 200, "{}", response); - assert_eq!(dbg!(response)["facetHits"].as_array().unwrap().len(), 1); + assert_eq!(code, 200, "{response}"); + assert_eq!(response["facetHits"].as_array().unwrap().len(), 1); } #[actix_rt::test] async fn simple_facet_search_by_count_with_max_values() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index @@ -309,14 +309,14 @@ async fn simple_facet_search_by_count_with_max_values() { let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 200, "{}", response); - assert_eq!(dbg!(response)["facetHits"].as_array().unwrap().len(), 1); + assert_eq!(code, 200, "{response}"); + assert_eq!(response["facetHits"].as_array().unwrap().len(), 1); } #[actix_rt::test] async fn non_filterable_facet_search_error() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); let (task, _status_code) = index.add_documents(documents, None).await; @@ -324,17 +324,17 @@ async fn non_filterable_facet_search_error() { let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 400, "{}", response); + assert_eq!(code, 400, "{response}"); let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "adv"})).await; - assert_eq!(code, 400, "{}", response); + assert_eq!(code, 400, "{response}"); } #[actix_rt::test] async fn facet_search_dont_support_words() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_filterable_attributes(json!(["genres"])).await; @@ -344,14 +344,14 @@ async fn facet_search_dont_support_words() { let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "words"})).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["facetHits"].as_array().unwrap().len(), 0); } #[actix_rt::test] async fn simple_facet_search_with_sort_by_count() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_faceting(json!({ "sortFacetValuesBy": { "*": "count" } })).await; @@ -362,7 +362,7 @@ async fn simple_facet_search_with_sort_by_count() { let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); let hits = response["facetHits"].as_array().unwrap(); assert_eq!(hits.len(), 2); assert_eq!(hits[0], json!({ "value": "Action", "count": 3 })); @@ -371,25 +371,25 @@ async fn simple_facet_search_with_sort_by_count() { #[actix_rt::test] async fn add_documents_and_deactivate_facet_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); let (response, _code) = index.add_documents(documents, None).await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index .update_settings(json!({ "facetSearch": false, "filterableAttributes": ["genres"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 400, "{}", response); + assert_eq!(code, 400, "{response}"); snapshot!(response, @r###" { "message": "The facet search is disabled for this index", @@ -402,8 +402,8 @@ async fn add_documents_and_deactivate_facet_search() { #[actix_rt::test] async fn deactivate_facet_search_and_add_documents() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -411,16 +411,16 @@ async fn deactivate_facet_search_and_add_documents() { "filterableAttributes": ["genres"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (response, _code) = index.add_documents(documents, None).await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 400, "{}", response); + assert_eq!(code, 400, "{response}"); snapshot!(response, @r###" { "message": "The facet search is disabled for this index", @@ -433,8 +433,8 @@ async fn deactivate_facet_search_and_add_documents() { #[actix_rt::test] async fn deactivate_facet_search_add_documents_and_activate_facet_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -442,31 +442,31 @@ async fn deactivate_facet_search_add_documents_and_activate_facet_search() { "filterableAttributes": ["genres"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (response, _code) = index.add_documents(documents, None).await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index .update_settings(json!({ "facetSearch": true, })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 200, "{}", response); - assert_eq!(dbg!(response)["facetHits"].as_array().unwrap().len(), 2); + assert_eq!(code, 200, "{response}"); + assert_eq!(response["facetHits"].as_array().unwrap().len(), 2); } #[actix_rt::test] async fn deactivate_facet_search_add_documents_and_reset_facet_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -474,25 +474,25 @@ async fn deactivate_facet_search_add_documents_and_reset_facet_search() { "filterableAttributes": ["genres"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (response, _code) = index.add_documents(documents, None).await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index .update_settings(json!({ "facetSearch": serde_json::Value::Null, })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.facet_search(json!({"facetName": "genres", "facetQuery": "a"})).await; - assert_eq!(code, 200, "{}", response); - assert_eq!(dbg!(response)["facetHits"].as_array().unwrap().len(), 2); + assert_eq!(code, 200, "{response}"); + assert_eq!(response["facetHits"].as_array().unwrap().len(), 2); } #[actix_rt::test] @@ -618,8 +618,8 @@ async fn facet_search_with_filterable_attributes_rules_errors() { #[actix_rt::test] async fn distinct_facet_search_on_movies() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -925,26 +925,26 @@ async fn distinct_facet_search_on_movies() { ]); let (response, code) = index.update_settings_filterable_attributes(json!(["genres", "color"])).await; - assert_eq!(202, code, "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!(202, code, "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.update_settings_distinct_attribute(json!("color")).await; - assert_eq!(202, code, "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!(202, code, "{response:?}"); + index.wait_task(response.uid()).await.succeeded(); let (response, _code) = index.add_documents(documents, None).await; - index.wait_task(response.uid()).await; + index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.facet_search(json!({"facetQuery": "blob", "facetName": "genres", "q": "" })).await; // non-exhaustive facet count is counting 27 documents with the facet query "blob" but there are only 23 documents with a distinct color. - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(response["facetHits"], @r###"[{"value":"Blob","count":27}]"###); let (response, code) = index.facet_search(json!({"facetQuery": "blob", "facetName": "genres", "q": "", "exhaustiveFacetCount": true })).await; // exhaustive facet count is counting 23 documents with the facet query "blob" which is the number of distinct colors. - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(response["facetHits"], @r###"[{"value":"Blob","count":23}]"###); } From bd95503eba5aa79a0b32c2fb035c4cc136dd1855 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 09:03:23 +0300 Subject: [PATCH 077/292] tests: Faster search::locales IT tests Use a shared server + unique indices where possible Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/locales.rs | 82 +++++++++++----------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/crates/meilisearch/tests/search/locales.rs b/crates/meilisearch/tests/search/locales.rs index 282589d6a..aaa65b7ea 100644 --- a/crates/meilisearch/tests/search/locales.rs +++ b/crates/meilisearch/tests/search/locales.rs @@ -89,9 +89,9 @@ static DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn simple_search() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); index .update_settings( @@ -196,9 +196,9 @@ async fn simple_search() { #[actix_rt::test] async fn force_locales() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); let (response, _) = index .update_settings( @@ -214,7 +214,7 @@ async fn force_locales() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -274,9 +274,9 @@ async fn force_locales() { #[actix_rt::test] async fn force_locales_with_pattern() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); let (response, _) = index .update_settings( @@ -292,7 +292,7 @@ async fn force_locales_with_pattern() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -352,9 +352,9 @@ async fn force_locales_with_pattern() { #[actix_rt::test] async fn force_locales_with_pattern_nested() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = NESTED_DOCUMENTS.clone(); let (response, _) = index .update_settings(json!({ @@ -368,7 +368,7 @@ async fn force_locales_with_pattern_nested() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -423,9 +423,9 @@ async fn force_locales_with_pattern_nested() { } #[actix_rt::test] async fn force_different_locales_with_pattern() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); let (response, _) = index .update_settings( @@ -443,7 +443,7 @@ async fn force_different_locales_with_pattern() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -499,9 +499,9 @@ async fn force_different_locales_with_pattern() { #[actix_rt::test] async fn auto_infer_locales_at_search_with_attributes_to_search_on() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); let (response, _) = index .update_settings( @@ -521,7 +521,7 @@ async fn auto_infer_locales_at_search_with_attributes_to_search_on() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -577,9 +577,9 @@ async fn auto_infer_locales_at_search_with_attributes_to_search_on() { #[actix_rt::test] async fn auto_infer_locales_at_search() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); let (response, _) = index .update_settings( @@ -595,7 +595,7 @@ async fn auto_infer_locales_at_search() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -676,9 +676,9 @@ async fn auto_infer_locales_at_search() { #[actix_rt::test] async fn force_different_locales_with_pattern_nested() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = NESTED_DOCUMENTS.clone(); let (response, _) = index .update_settings(json!({ @@ -694,7 +694,7 @@ async fn force_different_locales_with_pattern_nested() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -774,9 +774,9 @@ async fn force_different_locales_with_pattern_nested() { #[actix_rt::test] async fn settings_change() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = NESTED_DOCUMENTS.clone(); let (task, _status_code) = index.add_documents(documents, None).await; index.wait_task(task.uid()).await.succeeded(); @@ -792,7 +792,7 @@ async fn settings_change() { snapshot!(response, @r###" { "taskUid": 1, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -855,7 +855,7 @@ async fn settings_change() { snapshot!(response, @r###" { "taskUid": 2, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -906,9 +906,9 @@ async fn settings_change() { #[actix_rt::test] async fn invalid_locales() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); index .update_settings( @@ -945,9 +945,9 @@ async fn invalid_locales() { #[actix_rt::test] async fn invalid_localized_attributes_rules() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let (response, _) = index .update_settings(json!({ "localizedAttributes": [ @@ -1015,9 +1015,9 @@ async fn invalid_localized_attributes_rules() { #[actix_rt::test] async fn simple_facet_search() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); let (response, _) = index .update_settings(json!({ @@ -1027,7 +1027,7 @@ async fn simple_facet_search() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -1073,9 +1073,9 @@ async fn simple_facet_search() { #[actix_rt::test] async fn facet_search_with_localized_attributes() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = DOCUMENTS.clone(); let (response, _) = index .update_settings(json!({ @@ -1089,7 +1089,7 @@ async fn facet_search_with_localized_attributes() { snapshot!(response, @r###" { "taskUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -1146,9 +1146,9 @@ async fn facet_search_with_localized_attributes() { #[actix_rt::test] async fn swedish_search() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = json!([ {"id": "tra1-1", "product": "trä"}, {"id": "tra2-1", "product": "traktor"}, @@ -1269,9 +1269,9 @@ async fn swedish_search() { #[actix_rt::test] async fn german_search() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = server.unique_index(); - let index = server.index("test"); let documents = json!([ {"id": 1, "product": "Interkulturalität"}, {"id": 2, "product": "Wissensorganisation"}, From 17207b54057adae3afc4908ed164e12529616495 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 09:09:02 +0300 Subject: [PATCH 078/292] tests: Faster search::matching_strategy IT tests Use shared server + unique indices for all tests Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- .../meilisearch/tests/search/matching_strategy.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/meilisearch/tests/search/matching_strategy.rs b/crates/meilisearch/tests/search/matching_strategy.rs index 3b4325c10..7131ab9cc 100644 --- a/crates/meilisearch/tests/search/matching_strategy.rs +++ b/crates/meilisearch/tests/search/matching_strategy.rs @@ -2,11 +2,11 @@ use meili_snap::snapshot; use once_cell::sync::Lazy; use crate::common::index::Index; -use crate::common::{Server, Value}; +use crate::common::{Server, Shared, Value}; use crate::json; -async fn index_with_documents<'a>(server: &'a Server, documents: &Value) -> Index<'a> { - let index = server.index("test"); +async fn index_with_documents<'a>(server: &'a Server, documents: &Value) -> Index<'a> { + let index = server.unique_index(); let (task, _status_code) = index.add_documents(documents.clone(), None).await; index.wait_task(task.uid()).await.succeeded(); @@ -48,8 +48,8 @@ static SIMPLE_SEARCH_DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn simple_search() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; index .search(json!({"q": "Captain Marvel", "matchingStrategy": "last", "attributesToRetrieve": ["id"]}), |response, code| { @@ -75,7 +75,7 @@ async fn simple_search() { #[actix_rt::test] async fn search_with_typo() { - let server = Server::new().await; + let server = Server::new_shared(); let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; index @@ -102,7 +102,7 @@ async fn search_with_typo() { #[actix_rt::test] async fn search_with_unknown_word() { - let server = Server::new().await; + let server = Server::new_shared(); let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; index From fb8b8321922e40b2cc647bfe71e813cc0c8a40f6 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 10:54:31 +0300 Subject: [PATCH 079/292] Trigger build Signed-off-by: Martin Tzvetanov Grigorov From 58207da9346f2cf965927d5b67c495fada9e3aa8 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 10:56:33 +0300 Subject: [PATCH 080/292] Trigger build Signed-off-by: Martin Tzvetanov Grigorov From 27e7c00622860149698dc43ba514df959608e85b Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 11:33:10 +0300 Subject: [PATCH 081/292] Add dynamic redactions for taskUid and enqueuedAt properties Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/locales.rs | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/crates/meilisearch/tests/search/locales.rs b/crates/meilisearch/tests/search/locales.rs index aaa65b7ea..b1c9b2bc2 100644 --- a/crates/meilisearch/tests/search/locales.rs +++ b/crates/meilisearch/tests/search/locales.rs @@ -211,9 +211,9 @@ async fn force_locales() { }), ) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -289,9 +289,9 @@ async fn force_locales_with_pattern() { }), ) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -365,9 +365,9 @@ async fn force_locales_with_pattern_nested() { ] })) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -440,9 +440,9 @@ async fn force_different_locales_with_pattern() { }), ) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -518,9 +518,9 @@ async fn auto_infer_locales_at_search_with_attributes_to_search_on() { }), ) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -592,9 +592,9 @@ async fn auto_infer_locales_at_search() { }), ) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -691,9 +691,9 @@ async fn force_different_locales_with_pattern_nested() { ] })) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -789,9 +789,9 @@ async fn settings_change() { ] })) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 1, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -852,9 +852,9 @@ async fn settings_change() { ] })) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 2, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -1024,9 +1024,9 @@ async fn simple_facet_search() { "filterableAttributes": ["name_en", "name_ja", "name_zh"], })) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", @@ -1086,9 +1086,9 @@ async fn facet_search_with_localized_attributes() { ] })) .await; - snapshot!(response, @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 0, + "taskUid": "[task_uid]", "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", From 308fd7128e60907b7ce30364993fb6165ad622c0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 11:36:56 +0300 Subject: [PATCH 082/292] Fix clippy errors Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/matching_strategy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/search/matching_strategy.rs b/crates/meilisearch/tests/search/matching_strategy.rs index 7131ab9cc..ece320b2a 100644 --- a/crates/meilisearch/tests/search/matching_strategy.rs +++ b/crates/meilisearch/tests/search/matching_strategy.rs @@ -76,7 +76,7 @@ async fn simple_search() { #[actix_rt::test] async fn search_with_typo() { let server = Server::new_shared(); - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; index .search(json!({"q": "Capitain Marvel", "matchingStrategy": "last", "attributesToRetrieve": ["id"]}), |response, code| { @@ -103,7 +103,7 @@ async fn search_with_typo() { #[actix_rt::test] async fn search_with_unknown_word() { let server = Server::new_shared(); - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; index .search(json!({"q": "Captain Supercopter Marvel", "matchingStrategy": "last", "attributesToRetrieve": ["id"]}), |response, code| { From ae9899f179cc2a75794457f729647aa69089f499 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 30 May 2025 15:26:55 +0300 Subject: [PATCH 083/292] tests: search::pagination IT tests Minor cleanup. Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/pagination.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/tests/search/pagination.rs b/crates/meilisearch/tests/search/pagination.rs index ff601bd5b..f8b698a95 100644 --- a/crates/meilisearch/tests/search/pagination.rs +++ b/crates/meilisearch/tests/search/pagination.rs @@ -7,7 +7,7 @@ async fn default_search_should_return_estimated_total_hit() { let index = shared_index_with_documents().await; index .search(json!({}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert!(response.get("estimatedTotalHits").is_some()); assert!(response.get("limit").is_some()); assert!(response.get("offset").is_some()); @@ -25,7 +25,7 @@ async fn simple_search() { let index = shared_index_with_documents().await; index .search(json!({"page": 1}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 5); assert!(response.get("totalHits").is_some()); assert_eq!(response["page"], 1); @@ -44,7 +44,7 @@ async fn page_zero_should_not_return_any_result() { let index = shared_index_with_documents().await; index .search(json!({"page": 0}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 0); assert!(response.get("totalHits").is_some()); assert_eq!(response["page"], 0); @@ -58,7 +58,7 @@ async fn hits_per_page_1() { let index = shared_index_with_documents().await; index .search(json!({"hitsPerPage": 1}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); assert_eq!(response["totalHits"], 5); assert_eq!(response["page"], 1); @@ -72,7 +72,7 @@ async fn hits_per_page_0_should_not_return_any_result() { let index = shared_index_with_documents().await; index .search(json!({"hitsPerPage": 0}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 0); assert_eq!(response["totalHits"], 5); assert_eq!(response["page"], 1); @@ -126,7 +126,7 @@ async fn ensure_placeholder_search_hit_count_valid() { for page in 0..=4 { index .search(json!({"page": page, "hitsPerPage": 1}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["totalHits"], 4); assert_eq!(response["totalPages"], 4); }) From d9b0463a0b23e7a7a44bdddf065ad6a65675a542 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 30 May 2025 15:37:27 +0300 Subject: [PATCH 084/292] tests: Faster search::restricted_searchable IT tests Use shared server + unique indices Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/search/restrict_searchable.rs | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/crates/meilisearch/tests/search/restrict_searchable.rs b/crates/meilisearch/tests/search/restrict_searchable.rs index 8ef5db26d..e5408a210 100644 --- a/crates/meilisearch/tests/search/restrict_searchable.rs +++ b/crates/meilisearch/tests/search/restrict_searchable.rs @@ -2,11 +2,11 @@ use meili_snap::{json_string, snapshot}; use once_cell::sync::Lazy; use crate::common::index::Index; -use crate::common::{Server, Value}; +use crate::common::{Server, Shared, Value}; use crate::json; -async fn index_with_documents<'a>(server: &'a Server, documents: &Value) -> Index<'a> { - let index = server.index("test"); +async fn index_with_documents<'a>(server: &'a Server, documents: &Value) -> Index<'a> { + let index = server.unique_index(); let (task, _code) = index.add_documents(documents.clone(), None).await; index.wait_task(task.uid()).await.succeeded(); @@ -34,8 +34,8 @@ static SIMPLE_SEARCH_DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn simple_search_on_title() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; // simple search should return 2 documents (ids: 2 and 3). index @@ -51,8 +51,8 @@ async fn simple_search_on_title() { #[actix_rt::test] async fn search_no_searchable_attribute_set() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; index .search( @@ -93,8 +93,8 @@ async fn search_no_searchable_attribute_set() { #[actix_rt::test] async fn search_on_all_attributes() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; index .search(json!({"q": "Captain Marvel", "attributesToSearchOn": ["*"]}), |response, code| { @@ -106,8 +106,8 @@ async fn search_on_all_attributes() { #[actix_rt::test] async fn search_on_all_attributes_restricted_set() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; let (task, _status_code) = index.update_settings_searchable_attributes(json!(["title"])).await; index.wait_task(task.uid()).await.succeeded(); @@ -121,8 +121,8 @@ async fn search_on_all_attributes_restricted_set() { #[actix_rt::test] async fn simple_prefix_search_on_title() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; // simple search should return 2 documents (ids: 2 and 3). index @@ -135,8 +135,8 @@ async fn simple_prefix_search_on_title() { #[actix_rt::test] async fn simple_search_on_title_matching_strategy_all() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; // simple search matching strategy all should only return 1 document (ids: 2). index .search(json!({"q": "Captain Marvel", "attributesToSearchOn": ["title"], "matchingStrategy": "all"}), |response, code| { @@ -148,8 +148,8 @@ async fn simple_search_on_title_matching_strategy_all() { #[actix_rt::test] async fn simple_search_on_no_field() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; // simple search on no field shouldn't return any document. index .search(json!({"q": "Captain Marvel", "attributesToSearchOn": []}), |response, code| { @@ -161,8 +161,8 @@ async fn simple_search_on_no_field() { #[actix_rt::test] async fn word_ranking_rule_order() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; // Document 3 should appear before document 2. index @@ -189,8 +189,8 @@ async fn word_ranking_rule_order() { #[actix_rt::test] async fn word_ranking_rule_order_exact_words() { - let server = Server::new().await; - let index = index_with_documents(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &SIMPLE_SEARCH_DOCUMENTS).await; let (task, _status_code) = index .update_settings_typo_tolerance(json!({"disableOnWords": ["Captain", "Marvel"]})) .await; @@ -221,9 +221,9 @@ async fn word_ranking_rule_order_exact_words() { #[actix_rt::test] async fn typo_ranking_rule_order() { - let server = Server::new().await; + let server = Server::new_shared(); let index = index_with_documents( - &server, + server, &json!([ { "title": "Capitain Marivel", @@ -260,9 +260,9 @@ async fn typo_ranking_rule_order() { #[actix_rt::test] async fn attributes_ranking_rule_order() { - let server = Server::new().await; + let server = Server::new_shared(); let index = index_with_documents( - &server, + server, &json!([ { "title": "Captain Marvel", @@ -301,9 +301,9 @@ async fn attributes_ranking_rule_order() { #[actix_rt::test] async fn exactness_ranking_rule_order() { - let server = Server::new().await; + let server = Server::new_shared(); let index = index_with_documents( - &server, + server, &json!([ { "title": "Captain Marvel", @@ -340,9 +340,9 @@ async fn exactness_ranking_rule_order() { #[actix_rt::test] async fn search_on_exact_field() { - let server = Server::new().await; + let server = Server::new_shared(); let index = index_with_documents( - &server, + server, &json!([ { "title": "Captain Marvel", @@ -359,7 +359,7 @@ async fn search_on_exact_field() { let (response, code) = index.update_settings_typo_tolerance(json!({ "disableOnAttributes": ["exact"] })).await; - assert_eq!(202, code, "{:?}", response); + assert_eq!(202, code, "{response:?}"); index.wait_task(response.uid()).await.succeeded(); // Searching on an exact attribute should only return the document matching without typo. index @@ -372,7 +372,7 @@ async fn search_on_exact_field() { #[actix_rt::test] async fn phrase_search_on_title() { - let server = Server::new().await; + let server = Server::new_shared(); let documents = json!([ { "id": 8, "desc": "Document Review", "title": "Document Review Specialist II" }, { "id": 5, "desc": "Document Review", "title": "Document Review Attorney" }, @@ -383,7 +383,7 @@ async fn phrase_search_on_title() { { "id": 7, "desc": "Document Review", "title": "Document Review Specialist II" }, { "id": 6, "desc": "Document Review", "title": "Document Review (Entry Level)" } ]); - let index = index_with_documents(&server, &documents).await; + let index = index_with_documents(server, &documents).await; index .search( @@ -460,8 +460,8 @@ static NESTED_SEARCH_DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn nested_search_on_title_with_prefix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; // Wildcard should match to 'details.' attribute index @@ -486,8 +486,8 @@ async fn nested_search_on_title_with_prefix_wildcard() { #[actix_rt::test] async fn nested_search_with_suffix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; // Wildcard should match to any attribute inside 'details.' // It's worth noting the difference between 'details.*' and '*.title' @@ -553,8 +553,8 @@ async fn nested_search_with_suffix_wildcard() { #[actix_rt::test] async fn nested_search_on_title_restricted_set_with_suffix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; let (task, _status_code) = index.update_settings_searchable_attributes(json!(["details.title"])).await; index.wait_task(task.uid()).await.succeeded(); @@ -581,8 +581,8 @@ async fn nested_search_on_title_restricted_set_with_suffix_wildcard() { #[actix_rt::test] async fn nested_search_no_searchable_attribute_set_with_any_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; index .search( @@ -632,8 +632,8 @@ async fn nested_search_no_searchable_attribute_set_with_any_wildcard() { #[actix_rt::test] async fn nested_prefix_search_on_title_with_prefix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; // Nested prefix search with prefix wildcard should return 2 documents (ids: 2 and 3). index @@ -658,8 +658,8 @@ async fn nested_prefix_search_on_title_with_prefix_wildcard() { #[actix_rt::test] async fn nested_prefix_search_on_details_with_suffix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; index .search( @@ -686,8 +686,8 @@ async fn nested_prefix_search_on_details_with_suffix_wildcard() { #[actix_rt::test] async fn nested_prefix_search_on_weaknesses_with_suffix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; // Wildcard search on nested weaknesses should return 2 documents (ids: 1 and 3) index @@ -712,8 +712,8 @@ async fn nested_prefix_search_on_weaknesses_with_suffix_wildcard() { #[actix_rt::test] async fn nested_search_on_title_matching_strategy_all() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; // Nested search matching strategy all should only return 1 document (ids: 3) index @@ -735,8 +735,8 @@ async fn nested_search_on_title_matching_strategy_all() { #[actix_rt::test] async fn nested_attributes_ranking_rule_order_with_prefix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; // Document 3 should appear before documents 1 and 2 index @@ -766,8 +766,8 @@ async fn nested_attributes_ranking_rule_order_with_prefix_wildcard() { #[actix_rt::test] async fn nested_attributes_ranking_rule_order_with_suffix_wildcard() { - let server = Server::new().await; - let index = index_with_documents(&server, &NESTED_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents(server, &NESTED_SEARCH_DOCUMENTS).await; // Document 3 should appear before documents 1 and 2 index From 1158d6689f0a787b4b171105bbaf3809fd771e9d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 30 May 2025 15:41:31 +0300 Subject: [PATCH 085/292] tests: Faster settings::distinct IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/settings/distinct.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/meilisearch/tests/settings/distinct.rs b/crates/meilisearch/tests/settings/distinct.rs index 2c5b7517f..a3b1b5276 100644 --- a/crates/meilisearch/tests/settings/distinct.rs +++ b/crates/meilisearch/tests/settings/distinct.rs @@ -3,8 +3,8 @@ use crate::json; #[actix_rt::test] async fn set_and_reset_distinct_attribute() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task1, _code) = index.update_settings(json!({ "distinctAttribute": "test"})).await; index.wait_task(task1.uid()).await.succeeded(); @@ -24,8 +24,8 @@ async fn set_and_reset_distinct_attribute() { #[actix_rt::test] async fn set_and_reset_distinct_attribute_with_dedicated_route() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (update_task1, _code) = index.update_distinct_attribute(json!("test")).await; index.wait_task(update_task1.uid()).await.succeeded(); From 3ea167bade0103b837c713dd41f11b6301a6696a Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 30 May 2025 16:33:27 +0300 Subject: [PATCH 086/292] tests: Faster settings::get_settings IT tests Use shared server + unique indices Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/settings/get_settings.rs | 169 +++++++++--------- 1 file changed, 84 insertions(+), 85 deletions(-) diff --git a/crates/meilisearch/tests/settings/get_settings.rs b/crates/meilisearch/tests/settings/get_settings.rs index 5c0f89ed3..a52d4fa90 100644 --- a/crates/meilisearch/tests/settings/get_settings.rs +++ b/crates/meilisearch/tests/settings/get_settings.rs @@ -11,59 +11,62 @@ macro_rules! test_setting_routes { #[actix_rt::test] async fn get_unexisting_index() { - let server = Server::new().await; - let url = format!("/indexes/test/settings/{}", - stringify!($setting) - .chars() - .map(|c| if c == '_' { '-' } else { c }) - .collect::()); - let (_response, code) = server.service.get(url).await; - assert_eq!(code, 404); - } - - #[actix_rt::test] - async fn update_unexisting_index() { - let server = Server::new().await; - let url = format!("/indexes/test/settings/{}", - stringify!($setting) - .chars() - .map(|c| if c == '_' { '-' } else { c }) - .collect::()); - let (response, code) = server.service.$update_verb(url, serde_json::Value::Null.into()).await; - assert_eq!(code, 202, "{}", response); - server.index("").wait_task(0).await; - let (response, code) = server.index("test").get().await; - assert_eq!(code, 200, "{}", response); - } - - #[actix_rt::test] - async fn delete_unexisting_index() { - let server = Server::new().await; - let url = format!("/indexes/test/settings/{}", - stringify!($setting) - .chars() - .map(|c| if c == '_' { '-' } else { c }) - .collect::()); - let (_, code) = server.service.delete(url).await; - assert_eq!(code, 202); - let response = server.index("").wait_task(0).await; - assert_eq!(response["status"], "failed"); - } - - #[actix_rt::test] - async fn get_default() { - let server = Server::new().await; - let index = server.index("test"); - let (response, code) = index.create(None).await; - assert_eq!(code, 202, "{}", response); - index.wait_task(0).await; - let url = format!("/indexes/test/settings/{}", + let server = Server::new_shared(); + let index_name = uuid::Uuid::new_v4().to_string(); + let url = format!("/indexes/{index_name}/settings/{}", stringify!($setting) .chars() .map(|c| if c == '_' { '-' } else { c }) .collect::()); let (response, code) = server.service.get(url).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 404, "{response}"); + } + + #[actix_rt::test] + async fn update_unexisting_index() { + let server = Server::new_shared(); + let index_name = uuid::Uuid::new_v4().to_string(); + let url = format!("/indexes/{index_name}/settings/{}", + stringify!($setting) + .chars() + .map(|c| if c == '_' { '-' } else { c }) + .collect::()); + let (response, code) = server.service.$update_verb(url, serde_json::Value::Null.into()).await; + assert_eq!(code, 202, "{response}"); + let (response, code) = server.service.get(format!("/indixes/{index_name}")).await; + assert_eq!(code, 404, "{response}"); + } + + #[actix_rt::test] + async fn delete_unexisting_index() { + let server = Server::new_shared(); + let index_name = uuid::Uuid::new_v4().to_string(); + let url = format!("/indexes/{index_name}/settings/{}", + stringify!($setting) + .chars() + .map(|c| if c == '_' { '-' } else { c }) + .collect::()); + let (response, code) = server.service.delete(url).await; + assert_eq!(code, 202, "{response}"); + let (response, code) = server.service.get(format!("/indixes/{index_name}")).await; + assert_eq!(code, 404, "{response}"); + } + + #[actix_rt::test] + async fn get_default() { + let server = Server::new_shared(); + let index = server.unique_index(); + let (response, code) = index.create(None).await; + assert_eq!(code, 202, "{response}"); + index.wait_task(response.uid()).await.succeeded(); + let url = format!("/indexes/{}/settings/{}", + index.uid, + stringify!($setting) + .chars() + .map(|c| if c == '_' { '-' } else { c }) + .collect::()); + let (response, code) = server.service.get(url).await; + assert_eq!(code, 200, "{response}"); let expected = crate::json!($default_value); assert_eq!(expected, response); } @@ -185,15 +188,16 @@ test_setting_routes!( #[actix_rt::test] async fn get_settings_unexisting_index() { - let server = Server::new().await; - let (response, code) = server.index("test").settings().await; - assert_eq!(code, 404, "{}", response) + let server = Server::new_shared(); + let index = server.unique_index(); + let (response, code) = index.settings().await; + assert_eq!(code, 404, "{response}") } #[actix_rt::test] async fn get_settings() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, _code) = index.create(None).await; index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.settings().await; @@ -237,9 +241,8 @@ async fn get_settings() { #[actix_rt::test] async fn secrets_are_hidden_in_settings() { - let server = Server::new().await; - - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, _code) = index.create(None).await; index.wait_task(response.uid()).await.succeeded(); @@ -259,11 +262,11 @@ async fn secrets_are_hidden_in_settings() { .await; meili_snap::snapshot!(code, @"202 Accepted"); - meili_snap::snapshot!(meili_snap::json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + meili_snap::snapshot!(meili_snap::json_string!(response, { ".taskUid" => "[task_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "taskUid": 1, - "indexUid": "test", + "taskUid": "[task_uid]", + "indexUid": "[uuid]", "status": "enqueued", "type": "settingsUpdate", "enqueuedAt": "[date]" @@ -272,7 +275,7 @@ async fn secrets_are_hidden_in_settings() { let settings_update_uid = response.uid(); - index.wait_task(settings_update_uid).await; + index.wait_task(settings_update_uid).await.succeeded(); let (response, code) = index.settings().await; meili_snap::snapshot!(code, @"200 OK"); @@ -360,16 +363,16 @@ async fn secrets_are_hidden_in_settings() { #[actix_rt::test] async fn error_update_settings_unknown_field() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (_response, code) = index.update_settings(json!({"foo": 12})).await; assert_eq!(code, 400); } #[actix_rt::test] async fn test_partial_update() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _code) = index.update_settings(json!({"displayedAttributes": ["foo"]})).await; index.wait_task(task.uid()).await.succeeded(); let (response, code) = index.settings().await; @@ -388,20 +391,18 @@ async fn test_partial_update() { #[actix_rt::test] async fn error_delete_settings_unexisting_index() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, code) = index.delete_settings().await; assert_eq!(code, 202); - let response = index.wait_task(task.uid()).await; - - assert_eq!(response["status"], "failed"); + index.wait_task(task.uid()).await.failed(); } #[actix_rt::test] async fn reset_all_settings() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = json!([ { @@ -413,7 +414,7 @@ async fn reset_all_settings() { let (response, code) = index.add_documents(documents, None).await; assert_eq!(code, 202); - assert_eq!(response["taskUid"], 0); + assert!(response["taskUid"].as_i64().unwrap() >= 0); index.wait_task(response.uid()).await.succeeded(); let (update_task,_status_code) = index @@ -446,17 +447,15 @@ async fn reset_all_settings() { #[actix_rt::test] async fn update_setting_unexisting_index() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, code) = index.update_settings(json!({})).await; assert_eq!(code, 202); - let response = index.wait_task(task.uid()).await; - assert_eq!(response["status"], "succeeded"); + index.wait_task(task.uid()).await.succeeded(); let (_response, code) = index.get().await; assert_eq!(code, 200); let (task, _status_code) = index.delete_settings().await; - let response = index.wait_task(task.uid()).await; - assert_eq!(response["status"], "succeeded"); + index.wait_task(task.uid()).await.succeeded(); } #[actix_rt::test] @@ -477,8 +476,8 @@ async fn error_update_setting_unexisting_index_invalid_uid() { #[actix_rt::test] async fn error_set_invalid_ranking_rules() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(None).await; let (response, code) = index.update_settings(json!({ "rankingRules": [ "manyTheFish"]})).await; @@ -495,8 +494,8 @@ async fn error_set_invalid_ranking_rules() { #[actix_rt::test] async fn set_and_reset_distinct_attribute_with_dedicated_route() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _code) = index.update_distinct_attribute(json!("test")).await; index.wait_task(task.uid()).await.succeeded(); @@ -516,8 +515,8 @@ async fn set_and_reset_distinct_attribute_with_dedicated_route() { #[actix_rt::test] async fn granular_filterable_attributes() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(None).await; let (response, code) = @@ -535,7 +534,7 @@ async fn granular_filterable_attributes() { index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.settings().await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response["filterableAttributes"]), @r###" [ { From b54ece690b5d57d07f86917e5f181ecd3dcf4967 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 08:20:05 +0300 Subject: [PATCH 087/292] tests: Faster settings::proximity_settings IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/settings/proximity_settings.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/meilisearch/tests/settings/proximity_settings.rs b/crates/meilisearch/tests/settings/proximity_settings.rs index c5897bc51..6de1ffe0e 100644 --- a/crates/meilisearch/tests/settings/proximity_settings.rs +++ b/crates/meilisearch/tests/settings/proximity_settings.rs @@ -26,8 +26,8 @@ static DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn attribute_scale_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.add_documents(DOCUMENTS.clone(), None).await; index.wait_task(task.uid()).await.succeeded(); @@ -38,7 +38,7 @@ async fn attribute_scale_search() { "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); + assert_eq!("202", code.as_str(), "{response:?}"); index.wait_task(response.uid()).await.succeeded(); // the expected order is [1, 3, 2] instead of [3, 1, 2] @@ -99,8 +99,8 @@ async fn attribute_scale_search() { #[actix_rt::test] async fn attribute_scale_phrase_search() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.add_documents(DOCUMENTS.clone(), None).await; index.wait_task(task.uid()).await.succeeded(); @@ -167,8 +167,8 @@ async fn attribute_scale_phrase_search() { #[actix_rt::test] async fn word_scale_set_and_reset() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.add_documents(DOCUMENTS.clone(), None).await; index.wait_task(task.uid()).await.succeeded(); @@ -282,8 +282,8 @@ async fn word_scale_set_and_reset() { #[actix_rt::test] async fn attribute_scale_default_ranking_rules() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.add_documents(DOCUMENTS.clone(), None).await; index.wait_task(task.uid()).await.succeeded(); @@ -293,7 +293,7 @@ async fn attribute_scale_default_ranking_rules() { "proximityPrecision": "byAttribute" })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); + assert_eq!("202", code.as_str(), "{response:?}"); index.wait_task(response.uid()).await.succeeded(); // the expected order is [3, 1, 2] From 6b1a345dce44d4aa4b8975cb754eea2710f61aab Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 08:23:09 +0300 Subject: [PATCH 088/292] tests: Faster settings::tokenizer_customization IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/settings/tokenizer_customization.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/tests/settings/tokenizer_customization.rs b/crates/meilisearch/tests/settings/tokenizer_customization.rs index 190918b34..7c58368f7 100644 --- a/crates/meilisearch/tests/settings/tokenizer_customization.rs +++ b/crates/meilisearch/tests/settings/tokenizer_customization.rs @@ -5,8 +5,8 @@ use crate::json; #[actix_rt::test] async fn set_and_reset() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _code) = index .update_settings(json!({ @@ -70,8 +70,8 @@ async fn set_and_search() { }, ]); - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (add_task, _status_code) = index.add_documents(documents, None).await; index.wait_task(add_task.uid()).await.succeeded(); @@ -224,8 +224,8 @@ async fn advanced_synergies() { }, ]); - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (add_task, _status_code) = index.add_documents(documents, None).await; index.wait_task(add_task.uid()).await.succeeded(); From 790621dc29f95b1332fd6e8f00b63fbab021bae6 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Mon, 2 Jun 2025 10:55:28 +0300 Subject: [PATCH 089/292] Remove useless assert Co-authored-by: Many the fish --- crates/meilisearch/tests/settings/get_settings.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/meilisearch/tests/settings/get_settings.rs b/crates/meilisearch/tests/settings/get_settings.rs index a52d4fa90..2dc2b175f 100644 --- a/crates/meilisearch/tests/settings/get_settings.rs +++ b/crates/meilisearch/tests/settings/get_settings.rs @@ -414,7 +414,6 @@ async fn reset_all_settings() { let (response, code) = index.add_documents(documents, None).await; assert_eq!(code, 202); - assert!(response["taskUid"].as_i64().unwrap() >= 0); index.wait_task(response.uid()).await.succeeded(); let (update_task,_status_code) = index From 5a7cfc57fd304c25332ba438f8fa7a52728568a4 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 10:56:43 +0300 Subject: [PATCH 090/292] tests: Faster tasks::mode IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/tasks/mod.rs | 359 +++++++++++++------------- 1 file changed, 180 insertions(+), 179 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index f432ef7db..fcaf5f576 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -1,8 +1,8 @@ mod errors; mod webhook; -use meili_snap::insta::assert_json_snapshot; -use meili_snap::snapshot; +use insta::assert_json_snapshot; +use meili_snap::{json_string, snapshot}; use time::format_description::well_known::Rfc3339; use time::OffsetDateTime; @@ -11,11 +11,11 @@ use crate::json; #[actix_rt::test] async fn error_get_unexisting_task_status() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); - let (response, code) = index.get_task(1).await; + let (response, code) = index.get_task(u32::MAX as u64).await; let expected_response = json!({ "message": "Task `1` not found.", @@ -30,8 +30,8 @@ async fn error_get_unexisting_task_status() { #[actix_rt::test] async fn get_task_status() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (create_task, _status_code) = index.create(None).await; let (add_task, _status_code) = index .add_documents( @@ -50,8 +50,8 @@ async fn get_task_status() { #[actix_rt::test] async fn list_tasks() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index @@ -64,14 +64,14 @@ async fn list_tasks() { #[actix_rt::test] async fn list_tasks_pagination_and_reverse() { - let server = Server::new().await; + let server = Server::new_shared(); // First of all we want to create a lot of tasks very quickly. The fastest way is to delete a lot of unexisting indexes let mut last_task = None; - for i in 0..10 { - let index = server.index(format!("test-{i}")); + for _ in 0..10 { + let index = server.unique_index(); last_task = Some(index.create(None).await.0.uid()); } - server.wait_task(last_task.unwrap()).await; + server.wait_task(last_task.unwrap()).await.succeeded(); let (response, code) = server.tasks_filter("limit=3").await; assert_eq!(code, 200); @@ -102,14 +102,14 @@ async fn list_tasks_pagination_and_reverse() { #[actix_rt::test] async fn list_tasks_with_star_filters() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; - let (response, code) = index.service.get("/tasks?indexUids=test").await; + let (response, code) = index.service.get(format!("/tasks?indexUids={}", index.uid)).await; assert_eq!(code, 200); assert_eq!(response["results"].as_array().unwrap().len(), 2); @@ -127,50 +127,50 @@ async fn list_tasks_with_star_filters() { let (response, code) = index.service.get("/tasks?types=*,documentAdditionOrUpdate&statuses=*").await; - assert_eq!(code, 200, "{:?}", response); + assert_eq!(code, 200, "{response:?}"); assert_eq!(response["results"].as_array().unwrap().len(), 2); let (response, code) = index .service - .get("/tasks?types=*,documentAdditionOrUpdate&statuses=*,failed&indexUids=test") + .get(format!("/tasks?types=*,documentAdditionOrUpdate&statuses=*,failed&indexUids={}", index.uid)) .await; - assert_eq!(code, 200, "{:?}", response); + assert_eq!(code, 200, "{response:?}"); assert_eq!(response["results"].as_array().unwrap().len(), 2); let (response, code) = index .service .get("/tasks?types=*,documentAdditionOrUpdate&statuses=*,failed&indexUids=test,*") .await; - assert_eq!(code, 200, "{:?}", response); + assert_eq!(code, 200, "{response:?}"); assert_eq!(response["results"].as_array().unwrap().len(), 2); } #[actix_rt::test] async fn list_tasks_status_filtered() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.failed(); let (response, code) = index.filtered_tasks(&[], &["succeeded"], &[]).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 1); let (response, code) = index.filtered_tasks(&[], &["succeeded"], &[]).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 1); let (response, code) = index.filtered_tasks(&[], &["succeeded", "failed"], &[]).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 2); } #[actix_rt::test] async fn list_tasks_type_filtered() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index @@ -178,19 +178,19 @@ async fn list_tasks_type_filtered() { .await; let (response, code) = index.filtered_tasks(&["indexCreation"], &[], &[]).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 1); let (response, code) = index.filtered_tasks(&["indexCreation", "documentAdditionOrUpdate"], &[], &[]).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 2); } #[actix_rt::test] async fn list_tasks_invalid_canceled_by_filter() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index @@ -198,14 +198,14 @@ async fn list_tasks_invalid_canceled_by_filter() { .await; let (response, code) = index.filtered_tasks(&[], &[], &["0"]).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 0); } #[actix_rt::test] async fn list_tasks_status_and_type_filtered() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index @@ -213,7 +213,7 @@ async fn list_tasks_status_and_type_filtered() { .await; let (response, code) = index.filtered_tasks(&["indexCreation"], &["failed"], &[]).await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 0); let (response, code) = index @@ -223,12 +223,12 @@ async fn list_tasks_status_and_type_filtered() { &[], ) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 2); } macro_rules! assert_valid_summarized_task { - ($response:expr, $task_type:literal, $index:literal) => {{ + ($response:expr, $task_type:literal, $index:tt) => {{ assert_eq!($response.as_object().unwrap().len(), 5); assert!($response["taskUid"].as_u64().is_some()); assert_eq!($response["indexUid"], $index); @@ -242,49 +242,49 @@ macro_rules! assert_valid_summarized_task { #[actix_web::test] async fn test_summarized_task_view() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); + let index_uid = index.uid.clone(); let (response, _) = index.create(None).await; - assert_valid_summarized_task!(response, "indexCreation", "test"); + assert_valid_summarized_task!(response, "indexCreation", index_uid); let (response, _) = index.update(None).await; - assert_valid_summarized_task!(response, "indexUpdate", "test"); + assert_valid_summarized_task!(response, "indexUpdate", index_uid); let (response, _) = index.update_settings(json!({})).await; - assert_valid_summarized_task!(response, "settingsUpdate", "test"); + assert_valid_summarized_task!(response, "settingsUpdate", index_uid); let (response, _) = index.update_documents(json!([{"id": 1}]), None).await; - assert_valid_summarized_task!(response, "documentAdditionOrUpdate", "test"); + assert_valid_summarized_task!(response, "documentAdditionOrUpdate", index_uid); let (response, _) = index.add_documents(json!([{"id": 1}]), None).await; - assert_valid_summarized_task!(response, "documentAdditionOrUpdate", "test"); + assert_valid_summarized_task!(response, "documentAdditionOrUpdate", index_uid); let (response, _) = index.delete_document(1).await; - assert_valid_summarized_task!(response, "documentDeletion", "test"); + assert_valid_summarized_task!(response, "documentDeletion", index_uid); let (response, _) = index.clear_all_documents().await; - assert_valid_summarized_task!(response, "documentDeletion", "test"); + assert_valid_summarized_task!(response, "documentDeletion", index_uid); let (response, _) = index.delete().await; - assert_valid_summarized_task!(response, "indexDeletion", "test"); + assert_valid_summarized_task!(response, "indexDeletion", index_uid); } #[actix_web::test] async fn test_summarized_document_addition_or_update() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), None).await; index.wait_task(task.uid()).await.succeeded(); - let (task, _) = index.get_task(0).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -329,18 +329,17 @@ async fn test_summarized_document_addition_or_update() { #[actix_web::test] async fn test_summarized_delete_documents_by_batch() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.delete_batch(vec![1, 2, 3]).await; index.wait_task(task.uid()).await.failed(); - let (task, _) = index.get_task(0).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { "uid": 0, "batchUid": 0, - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "documentDeletion", "canceledBy": null, @@ -366,13 +365,13 @@ async fn test_summarized_delete_documents_by_batch() { let (del_task, _status_code) = index.delete_batch(vec![42]).await; index.wait_task(del_task.uid()).await.succeeded(); let (task, _) = index.get_task(del_task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { "uid": 2, "batchUid": 2, - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", "canceledBy": null, @@ -392,20 +391,20 @@ async fn test_summarized_delete_documents_by_batch() { #[actix_web::test] async fn test_summarized_delete_documents_by_filter() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "failed", "type": "documentDeletion", "canceledBy": null, @@ -415,7 +414,7 @@ async fn test_summarized_delete_documents_by_filter() { "originalFilter": "\"doggo = bernese\"" }, "error": { - "message": "Index `test` not found.", + "message": "Index `[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -432,13 +431,13 @@ async fn test_summarized_delete_documents_by_filter() { index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 2, - "batchUid": 2, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "failed", "type": "documentDeletion", "canceledBy": null, @@ -448,7 +447,7 @@ async fn test_summarized_delete_documents_by_filter() { "originalFilter": "\"doggo = bernese\"" }, "error": { - "message": "Index `test`: Attribute `doggo` is not filterable. This index does not have configured filterable attributes.\n1:6 doggo = bernese", + "message": "Index `[uuid]`: Attribute `doggo` is not filterable. This index does not have configured filterable attributes.\n1:6 doggo = bernese", "code": "invalid_document_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_document_filter" @@ -465,13 +464,13 @@ async fn test_summarized_delete_documents_by_filter() { index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 4, - "batchUid": 4, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", "canceledBy": null, @@ -491,18 +490,18 @@ async fn test_summarized_delete_documents_by_filter() { #[actix_web::test] async fn test_summarized_delete_document_by_id() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.delete_document(1).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "failed", "type": "documentDeletion", "canceledBy": null, @@ -512,7 +511,7 @@ async fn test_summarized_delete_document_by_id() { "originalFilter": null }, "error": { - "message": "Index `test` not found.", + "message": "Index `[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -528,13 +527,13 @@ async fn test_summarized_delete_document_by_id() { let (task, _status_code) = index.delete_document(42).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 2, - "batchUid": 2, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", "canceledBy": null, @@ -554,12 +553,12 @@ async fn test_summarized_delete_document_by_id() { #[actix_web::test] async fn test_summarized_settings_update() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); // here we should find my payload even in the failed task. let (response, code) = index.update_settings(json!({ "rankingRules": ["custom"] })).await; - meili_snap::snapshot!(code, @"400 Bad Request"); - meili_snap::snapshot!(meili_snap::json_string!(response), @r###" + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" { "message": "Invalid value at `.rankingRules[0]`: `custom` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules.", "code": "invalid_settings_ranking_rules", @@ -571,13 +570,13 @@ async fn test_summarized_settings_update() { let (task,_status_code) = index.update_settings(json!({ "displayedAttributes": ["doggos", "name"], "filterableAttributes": ["age", "nb_paw_pads"], "sortableAttributes": ["iq"] })).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, @@ -605,18 +604,18 @@ async fn test_summarized_settings_update() { #[actix_web::test] async fn test_summarized_index_creation() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "indexCreation", "canceledBy": null, @@ -634,13 +633,13 @@ async fn test_summarized_index_creation() { let (task, _status_code) = index.create(Some("doggos")).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 1, - "batchUid": 1, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "failed", "type": "indexCreation", "canceledBy": null, @@ -648,7 +647,7 @@ async fn test_summarized_index_creation() { "primaryKey": "doggos" }, "error": { - "message": "Index `test` already exists.", + "message": "Index `[uuid]` already exists.", "code": "index_already_exists", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_already_exists" @@ -663,8 +662,8 @@ async fn test_summarized_index_creation() { #[actix_web::test] async fn test_summarized_index_deletion() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (ret, _code) = index.delete().await; let task = index.wait_task(ret.uid()).await; snapshot!(task, @@ -672,7 +671,7 @@ async fn test_summarized_index_deletion() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "indexDeletion", "canceledBy": null, @@ -680,7 +679,7 @@ async fn test_summarized_index_deletion() { "deletedDocuments": 0 }, "error": { - "message": "Index `test` not found.", + "message": "Index `[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -703,7 +702,7 @@ async fn test_summarized_index_deletion() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -726,7 +725,7 @@ async fn test_summarized_index_deletion() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "succeeded", "type": "indexDeletion", "canceledBy": null, @@ -749,7 +748,7 @@ async fn test_summarized_index_deletion() { { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "test", + "indexUid": "[uuid]", "status": "failed", "type": "indexDeletion", "canceledBy": null, @@ -757,7 +756,7 @@ async fn test_summarized_index_deletion() { "deletedDocuments": 0 }, "error": { - "message": "Index `test` not found.", + "message": "Index `[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -772,19 +771,19 @@ async fn test_summarized_index_deletion() { #[actix_web::test] async fn test_summarized_index_update() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); // If the index doesn't exist yet, we should get errors with or without the primary key. let (task, _status_code) = index.update(None).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "failed", "type": "indexUpdate", "canceledBy": null, @@ -792,7 +791,7 @@ async fn test_summarized_index_update() { "primaryKey": null }, "error": { - "message": "Index `test` not found.", + "message": "Index `[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -807,13 +806,13 @@ async fn test_summarized_index_update() { let (task, _status_code) = index.update(Some("bones")).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 1, - "batchUid": 1, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "failed", "type": "indexUpdate", "canceledBy": null, @@ -821,7 +820,7 @@ async fn test_summarized_index_update() { "primaryKey": "bones" }, "error": { - "message": "Index `test` not found.", + "message": "Index `[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -839,13 +838,13 @@ async fn test_summarized_index_update() { let (task, _status_code) = index.update(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 3, - "batchUid": 3, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "indexUpdate", "canceledBy": null, @@ -863,13 +862,13 @@ async fn test_summarized_index_update() { let (task, _status_code) = index.update(Some("bones")).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 4, - "batchUid": 4, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "indexUpdate", "canceledBy": null, @@ -887,7 +886,7 @@ async fn test_summarized_index_update() { #[actix_web::test] async fn test_summarized_index_swap() { - let server = Server::new().await; + let server = Server::new_shared(); let (task, _status_code) = server .index_swap(json!([ { "indexes": ["doggos", "cattos"] } @@ -895,12 +894,12 @@ async fn test_summarized_index_swap() { .await; server.wait_task(task.uid()).await.failed(); let (task, _) = server.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": null, "status": "failed", "type": "indexSwap", @@ -928,23 +927,25 @@ async fn test_summarized_index_swap() { } "###); - let (task, _code) = server.index("doggos").create(None).await; + let doggos_index = server.unique_index(); + let (task, _code) = doggos_index.create(None).await; server.wait_task(task.uid()).await.succeeded(); - let (task, _code) = server.index("cattos").create(None).await; + let cattos_index = server.unique_index(); + let (task, _code) = cattos_index.create(None).await; server.wait_task(task.uid()).await.succeeded(); let (task, _code) = server .index_swap(json!([ - { "indexes": ["doggos", "cattos"] } + { "indexes": [doggos_index.uid, cattos_index.uid] } ])) .await; server.wait_task(task.uid()).await.succeeded(); let (task, _) = server.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".**.indexes[0]" => "doggos", ".**.indexes[1]" => "cattos", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 3, - "batchUid": 3, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": null, "status": "succeeded", "type": "indexSwap", @@ -970,20 +971,20 @@ async fn test_summarized_index_swap() { #[actix_web::test] async fn test_summarized_task_cancelation() { - let server = Server::new().await; - let index = server.index("doggos"); + let server = Server::new_shared(); + let index = server.unique_index(); // to avoid being flaky we're only going to cancel an already finished task :( let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = server.cancel_tasks("uids=0").await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": null, "status": "succeeded", "type": "taskCancelation", @@ -1004,20 +1005,20 @@ async fn test_summarized_task_cancelation() { #[actix_web::test] async fn test_summarized_task_deletion() { - let server = Server::new().await; - let index = server.index("doggos"); + let server = Server::new_shared(); + let index = server.unique_index(); // to avoid being flaky we're only going to delete an already finished task :( let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = server.delete_tasks("uids=0").await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 1, - "batchUid": 1, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": null, "status": "succeeded", "type": "taskDeletion", @@ -1038,16 +1039,16 @@ async fn test_summarized_task_deletion() { #[actix_web::test] async fn test_summarized_dump_creation() { - let server = Server::new().await; + let server = Server::new_shared(); let (task, _status_code) = server.create_dump().await; server.wait_task(task.uid()).await; let (task, _) = server.get_task(task.uid()).await; - assert_json_snapshot!(task, - { ".details.dumpUid" => "[dumpUid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".details.dumpUid" => "[dumpUid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": null, "status": "succeeded", "type": "dumpCreation", From db28d13cb11e788aeded1c38e4460e679b7fb73b Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 10:59:46 +0300 Subject: [PATCH 091/292] Remove useless assertion. .succeeded() does the same Signed-off-by: Martin Tzvetanov Grigorov --- .../meilisearch/tests/search/facet_search.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/crates/meilisearch/tests/search/facet_search.rs b/crates/meilisearch/tests/search/facet_search.rs index 87af125f0..57d2cfcd2 100644 --- a/crates/meilisearch/tests/search/facet_search.rs +++ b/crates/meilisearch/tests/search/facet_search.rs @@ -50,13 +50,11 @@ async fn test_settings_documents_indexing_swapping_and_facet_search( let (task, code) = index.add_documents(documents.clone(), None).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await.succeeded(); - assert!(response.is_success(), "{response:?}"); + index.wait_task(task.uid()).await.succeeded(); let (task, code) = index.update_settings(settings.clone()).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await.succeeded(); - assert!(response.is_success(), "{response:?}"); + index.wait_task(task.uid()).await.succeeded(); let (response, code) = index.facet_search(query.clone()).await; insta::allow_duplicates! { @@ -65,21 +63,18 @@ async fn test_settings_documents_indexing_swapping_and_facet_search( let (task, code) = server.delete_index("test").await; assert_eq!(code, 202, "{}", task); - let response = server.wait_task(task.uid()).await.succeeded(); - assert!(response.is_success(), "{response:?}"); + server.wait_task(task.uid()).await.succeeded(); eprintln!("Settings -> Documents -> test"); let index = server.index("test"); let (task, code) = index.update_settings(settings.clone()).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await.succeeded(); - assert!(response.is_success(), "{response:?}"); + index.wait_task(task.uid()).await.succeeded(); let (task, code) = index.add_documents(documents.clone(), None).await; assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await.succeeded(); - assert!(response.is_success(), "{response:?}"); + index.wait_task(task.uid()).await.succeeded(); let (response, code) = index.facet_search(query.clone()).await; insta::allow_duplicates! { @@ -88,8 +83,7 @@ async fn test_settings_documents_indexing_swapping_and_facet_search( let (task, code) = server.delete_index("test").await; assert_eq!(code, 202, "{}", task); - let response = server.wait_task(task.uid()).await.succeeded(); - assert!(response.is_success(), "{response:?}"); + server.wait_task(task.uid()).await.succeeded(); } #[actix_rt::test] From 8d8fcb9846640f383573387503dd764de55dd1bb Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 11:44:21 +0300 Subject: [PATCH 092/292] Revert to unique server + named index for some tests Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/tasks/mod.rs | 64 ++++++++++++++++----------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index fcaf5f576..57cb87364 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -1,7 +1,6 @@ mod errors; mod webhook; -use insta::assert_json_snapshot; use meili_snap::{json_string, snapshot}; use time::format_description::well_known::Rfc3339; use time::OffsetDateTime; @@ -18,7 +17,7 @@ async fn error_get_unexisting_task_status() { let (response, code) = index.get_task(u32::MAX as u64).await; let expected_response = json!({ - "message": "Task `1` not found.", + "message": "Task `4294967295` not found.", "code": "task_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#task_not_found" @@ -64,11 +63,12 @@ async fn list_tasks() { #[actix_rt::test] async fn list_tasks_pagination_and_reverse() { - let server = Server::new_shared(); + // do not use a shared server here, as we want to assert tasks ids and we need them to be stable + let server = Server::new().await; // First of all we want to create a lot of tasks very quickly. The fastest way is to delete a lot of unexisting indexes let mut last_task = None; - for _ in 0..10 { - let index = server.unique_index(); + for i in 0..10 { + let index = server.index(format!("test-{i}")); last_task = Some(index.create(None).await.0.uid()); } server.wait_task(last_task.unwrap()).await.succeeded(); @@ -102,8 +102,9 @@ async fn list_tasks_pagination_and_reverse() { #[actix_rt::test] async fn list_tasks_with_star_filters() { - let server = Server::new_shared(); - let index = server.unique_index(); + let server = Server::new().await; + // Do not use a unique index here, as we want to test the `indexUids=*` filter. + let index = server.index("test"); let (task, _code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index @@ -132,7 +133,10 @@ async fn list_tasks_with_star_filters() { let (response, code) = index .service - .get(format!("/tasks?types=*,documentAdditionOrUpdate&statuses=*,failed&indexUids={}", index.uid)) + .get(format!( + "/tasks?types=*,documentAdditionOrUpdate&statuses=*,failed&indexUids={}", + index.uid + )) .await; assert_eq!(code, 200, "{response:?}"); assert_eq!(response["results"].as_array().unwrap().len(), 2); @@ -278,6 +282,7 @@ async fn test_summarized_document_addition_or_update() { let (task, _status_code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), None).await; index.wait_task(task.uid()).await.succeeded(); + let (task, _) = index.get_task(task.uid()).await; snapshot!(json_string!(task, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" @@ -303,14 +308,14 @@ async fn test_summarized_document_addition_or_update() { let (task, _status_code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; index.wait_task(task.uid()).await.succeeded(); - let (task, _) = index.get_task(1).await; - assert_json_snapshot!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + let (task, _) = index.get_task(task.uid()).await; + snapshot!(json_string!(task, + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 1, - "batchUid": 1, - "indexUid": "test", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, @@ -331,14 +336,20 @@ async fn test_summarized_document_addition_or_update() { async fn test_summarized_delete_documents_by_batch() { let server = Server::new_shared(); let index = server.unique_index(); - let (task, _status_code) = index.delete_batch(vec![1, 2, 3]).await; + let non_existing_task_id1 = u32::MAX as u64; + let non_existing_task_id2 = non_existing_task_id1 - 1; + let non_existing_task_id3 = non_existing_task_id1 - 2; + let (task, _status_code) = index + .delete_batch(vec![non_existing_task_id1, non_existing_task_id2, non_existing_task_id3]) + .await; index.wait_task(task.uid()).await.failed(); + let (task, _) = index.get_task(task.uid()).await; snapshot!(json_string!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 0, - "batchUid": 0, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "failed", "type": "documentDeletion", @@ -349,7 +360,7 @@ async fn test_summarized_delete_documents_by_batch() { "originalFilter": null }, "error": { - "message": "Index `test` not found.", + "message": "Index `[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -366,11 +377,11 @@ async fn test_summarized_delete_documents_by_batch() { index.wait_task(del_task.uid()).await.succeeded(); let (task, _) = index.get_task(del_task.uid()).await; snapshot!(json_string!(task, - { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { - "uid": 2, - "batchUid": 2, + "uid": "[uid]", + "batchUid": "[batch_uid]", "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", @@ -975,12 +986,13 @@ async fn test_summarized_task_cancelation() { let index = server.unique_index(); // to avoid being flaky we're only going to cancel an already finished task :( let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); - let (task, _status_code) = server.cancel_tasks("uids=0").await; + let task_uid = task.uid(); + index.wait_task(task_uid).await.succeeded(); + let (task, _status_code) = server.cancel_tasks(format!("uids={task_uid}").as_str()).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".**.originalFilter" => "[of]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @r###" { "uid": "[uid]", @@ -992,7 +1004,7 @@ async fn test_summarized_task_cancelation() { "details": { "matchedTasks": 1, "canceledTasks": 0, - "originalFilter": "?uids=0" + "originalFilter": "[of]" }, "error": null, "duration": "[duration]", From cffbe3fcb68c3d8fa9cf238c9f20602d9f82496d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 14:17:19 +0300 Subject: [PATCH 093/292] Trigger build Signed-off-by: Martin Tzvetanov Grigorov From 5efc78db550f82776c701b430f2469d99ae67179 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 14:47:18 +0300 Subject: [PATCH 094/292] tests: Faster vector::binary_quantized IT tests Use shared server + unique indices where possible Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/vector/binary_quantized.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/meilisearch/tests/vector/binary_quantized.rs b/crates/meilisearch/tests/vector/binary_quantized.rs index 96e32c1a3..89d32cc50 100644 --- a/crates/meilisearch/tests/vector/binary_quantized.rs +++ b/crates/meilisearch/tests/vector/binary_quantized.rs @@ -6,8 +6,8 @@ use crate::vector::generate_default_user_provided_documents; #[actix_rt::test] async fn retrieve_binary_quantize_status_in_the_settings() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -65,8 +65,8 @@ async fn retrieve_binary_quantize_status_in_the_settings() { #[actix_rt::test] async fn binary_quantize_before_sending_documents() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -139,8 +139,8 @@ async fn binary_quantize_before_sending_documents() { #[actix_rt::test] async fn binary_quantize_after_sending_documents() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -226,8 +226,8 @@ async fn binary_quantize_after_sending_documents() { #[actix_rt::test] async fn try_to_disable_binary_quantization() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -256,11 +256,11 @@ async fn try_to_disable_binary_quantization() { .await; snapshot!(code, @"202 Accepted"); let ret = server.wait_task(response.uid()).await; - snapshot!(ret, @r#" + snapshot!(json_string!(ret, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".finishedAt" => "[date]", ".startedAt" => "[date]" }), @r#" { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "doggo", + "indexUid": "[uuid]", "status": "failed", "type": "settingsUpdate", "canceledBy": null, @@ -274,7 +274,7 @@ async fn try_to_disable_binary_quantization() { } }, "error": { - "message": "Index `doggo`: `.embedders.manual.binaryQuantized`: Cannot disable the binary quantization.\n - Note: Binary quantization is a lossy operation that cannot be reverted.\n - Hint: Add a new embedder that is non-quantized and regenerate the vectors.", + "message": "Index `[uuid]`: `.embedders.manual.binaryQuantized`: Cannot disable the binary quantization.\n - Note: Binary quantization is a lossy operation that cannot be reverted.\n - Hint: Add a new embedder that is non-quantized and regenerate the vectors.", "code": "invalid_settings_embedders", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_settings_embedders" From 3b30b6a57abe5044b4f97929fb001c671eab9bc0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:04:48 +0300 Subject: [PATCH 095/292] tests: Faster documents::delete_documents IT tests Use shared server + unique indices Assert .succeeded()/.failed() for the waited tasks Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/documents/delete_documents.rs | 141 +++++++++--------- 1 file changed, 67 insertions(+), 74 deletions(-) diff --git a/crates/meilisearch/tests/documents/delete_documents.rs b/crates/meilisearch/tests/documents/delete_documents.rs index 060f17958..26dfba8c8 100644 --- a/crates/meilisearch/tests/documents/delete_documents.rs +++ b/crates/meilisearch/tests/documents/delete_documents.rs @@ -5,35 +5,32 @@ use crate::json; #[actix_rt::test] async fn delete_one_document_unexisting_index() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, code) = index.delete_document(0).await; assert_eq!(code, 202); - let response = index.wait_task(task.uid()).await; - - assert_eq!(response["status"], "failed"); + index.wait_task(task.uid()).await.failed(); } #[actix_rt::test] async fn delete_one_unexisting_document() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index.create(None).await; let (response, code) = index.delete_document(0).await; - assert_eq!(code, 202, "{}", response); - let update = index.wait_task(response.uid()).await; - assert_eq!(update["status"], "succeeded"); + assert_eq!(code, 202, "{response}"); + index.wait_task(response.uid()).await.succeeded(); } #[actix_rt::test] async fn delete_one_document() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.add_documents(json!([{ "id": 0, "content": "foobar" }]), None).await; index.wait_task(task.uid()).await.succeeded(); - let (task, status_code) = server.index("test").delete_document(0).await; + let (task, status_code) = index.delete_document(0).await; assert_eq!(status_code, 202); index.wait_task(task.uid()).await.succeeded(); @@ -43,20 +40,18 @@ async fn delete_one_document() { #[actix_rt::test] async fn clear_all_documents_unexisting_index() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, code) = index.clear_all_documents().await; assert_eq!(code, 202); - let response = index.wait_task(task.uid()).await; - - assert_eq!(response["status"], "failed"); + index.wait_task(task.uid()).await.failed(); } #[actix_rt::test] async fn clear_all_documents() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index .add_documents( json!([{ "id": 1, "content": "foobar" }, { "id": 0, "content": "foobar" }]), @@ -67,7 +62,7 @@ async fn clear_all_documents() { let (task, code) = index.clear_all_documents().await; assert_eq!(code, 202); - let _update = index.wait_task(task.uid()).await; + let _update = index.wait_task(task.uid()).await.succeeded(); let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; assert_eq!(code, 200); assert!(response["results"].as_array().unwrap().is_empty()); @@ -75,14 +70,14 @@ async fn clear_all_documents() { #[actix_rt::test] async fn clear_all_documents_empty_index() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, code) = index.clear_all_documents().await; assert_eq!(code, 202); - let _update = index.wait_task(task.uid()).await; + let _update = index.wait_task(task.uid()).await.succeeded(); let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; assert_eq!(code, 200); assert!(response["results"].as_array().unwrap().is_empty()); @@ -90,33 +85,31 @@ async fn clear_all_documents_empty_index() { #[actix_rt::test] async fn error_delete_batch_unexisting_index() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, code) = index.delete_batch(vec![]).await; let expected_response = json!({ - "message": "Index `test` not found.", + "message": format!("Index `{}` not found.", index.uid), "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" }); assert_eq!(code, 202); - let response = index.wait_task(task.uid()).await; - - assert_eq!(response["status"], "failed"); + let response = index.wait_task(task.uid()).await.failed(); assert_eq!(response["error"], expected_response); } #[actix_rt::test] async fn delete_batch() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task,_status_code) = index.add_documents(json!([{ "id": 1, "content": "foobar" }, { "id": 0, "content": "foobar" }, { "id": 3, "content": "foobar" }]), Some("id")).await; index.wait_task(task.uid()).await.succeeded(); let (task, code) = index.delete_batch(vec![1, 0]).await; assert_eq!(code, 202); - let _update = index.wait_task(task.uid()).await; + let _update = index.wait_task(task.uid()).await.succeeded(); let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; assert_eq!(code, 200); assert_eq!(response["results"].as_array().unwrap().len(), 1); @@ -125,14 +118,14 @@ async fn delete_batch() { #[actix_rt::test] async fn delete_no_document_batch() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task,_status_code) = index.add_documents(json!([{ "id": 1, "content": "foobar" }, { "id": 0, "content": "foobar" }, { "id": 3, "content": "foobar" }]), Some("id")).await; index.wait_task(task.uid()).await.succeeded(); - let (_response, code) = index.delete_batch(vec![]).await; - assert_eq!(code, 202, "{}", _response); + let (response, code) = index.delete_batch(vec![]).await; + assert_eq!(code, 202, "{response}"); - let _update = index.wait_task(_response.uid()).await; + let _update = index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; assert_eq!(code, 200); assert_eq!(response["results"].as_array().unwrap().len(), 3); @@ -140,8 +133,8 @@ async fn delete_no_document_batch() { #[actix_rt::test] async fn delete_document_by_filter() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); index.update_settings_filterable_attributes(json!(["color"])).await; let (task, _status_code) = index .add_documents( @@ -178,22 +171,22 @@ async fn delete_document_by_filter() { let (response, code) = index.delete_document_by_filter(json!({ "filter": "color = blue"})).await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 2, - "indexUid": "doggo", + "taskUid": "[task_uid]", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentDeletion", "enqueuedAt": "[date]" } "###); - let response = index.wait_task(response.uid()).await; - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + let response = index.wait_task(response.uid()).await.succeeded(); + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "uid": 2, - "batchUid": 2, - "indexUid": "doggo", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", "canceledBy": null, @@ -251,22 +244,22 @@ async fn delete_document_by_filter() { let (response, code) = index.delete_document_by_filter(json!({ "filter": "color NOT EXISTS"})).await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "taskUid": 3, - "indexUid": "doggo", + "taskUid": "[task_uid]", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentDeletion", "enqueuedAt": "[date]" } "###); - let response = index.wait_task(response.uid()).await; - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + let response = index.wait_task(response.uid()).await.succeeded(); + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "uid": 3, - "batchUid": 3, - "indexUid": "doggo", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", "canceledBy": null, @@ -321,8 +314,8 @@ async fn delete_document_by_filter() { #[actix_rt::test] async fn delete_document_by_complex_filter() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); index.update_settings_filterable_attributes(json!(["color"])).await; let (task, _status_code) = index .add_documents( @@ -343,22 +336,22 @@ async fn delete_document_by_complex_filter() { ) .await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]" }), @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]" }), @r###" { - "taskUid": 2, - "indexUid": "doggo", + "taskUid": "[task_uid]", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentDeletion", "enqueuedAt": "[date]" } "###); - let response = index.wait_task(response.uid()).await; - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + let response = index.wait_task(response.uid()).await.succeeded(); + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "uid": 2, - "batchUid": 2, - "indexUid": "doggo", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", "canceledBy": null, @@ -402,22 +395,22 @@ async fn delete_document_by_complex_filter() { .delete_document_by_filter(json!({ "filter": [["color = green", "color NOT EXISTS"]] })) .await; snapshot!(code, @"202 Accepted"); - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + snapshot!(json_string!(response, { ".taskUid" => "[task_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "taskUid": 3, - "indexUid": "doggo", + "taskUid": "[task_uid]", + "indexUid": "[uuid]", "status": "enqueued", "type": "documentDeletion", "enqueuedAt": "[date]" } "###); - let response = index.wait_task(response.uid()).await; - snapshot!(json_string!(response, { ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" + let response = index.wait_task(response.uid()).await.succeeded(); + snapshot!(json_string!(response, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", ".duration" => "[duration]" }), @r###" { - "uid": 3, - "batchUid": 3, - "indexUid": "doggo", + "uid": "[uid]", + "batchUid": "[batch_uid]", + "indexUid": "[uuid]", "status": "succeeded", "type": "documentDeletion", "canceledBy": null, From f80182f0a91dfe6cb40340cfedca4dc4ebdfa1d2 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:20:17 +0300 Subject: [PATCH 096/292] tests: Faster similar::errors IT tests Use shared server + unique indices Related to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/similar/errors.rs | 136 ++++++++++----------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/crates/meilisearch/tests/similar/errors.rs b/crates/meilisearch/tests/similar/errors.rs index 30ff5b145..fa4118fe3 100644 --- a/crates/meilisearch/tests/similar/errors.rs +++ b/crates/meilisearch/tests/similar/errors.rs @@ -6,11 +6,11 @@ use crate::json; #[actix_rt::test] async fn similar_unexisting_index() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let expected_response = json!({ - "message": "Index `test` not found.", + "message": format!("Index `{}` not found.", index.uid), "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -26,12 +26,12 @@ async fn similar_unexisting_index() { #[actix_rt::test] async fn similar_unexisting_parameter() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); index .similar(json!({"id": 287947, "marin": "hello"}), |response, code| { - assert_eq!(code, 400, "{}", response); + assert_eq!(code, 400, "{response}"); assert_eq!(response["code"], "bad_request"); }) .await; @@ -39,8 +39,8 @@ async fn similar_unexisting_parameter() { #[actix_rt::test] async fn similar_bad_id() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -53,7 +53,7 @@ async fn similar_bad_id() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index.similar_post(json!({"id": ["doggo"], "embedder": "manual"})).await; snapshot!(code, @"400 Bad Request"); @@ -69,8 +69,8 @@ async fn similar_bad_id() { #[actix_rt::test] async fn similar_bad_ranking_score_threshold() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -83,7 +83,7 @@ async fn similar_bad_ranking_score_threshold() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index.similar_post(json!({"rankingScoreThreshold": ["doggo"]})).await; snapshot!(code, @"400 Bad Request"); @@ -99,8 +99,8 @@ async fn similar_bad_ranking_score_threshold() { #[actix_rt::test] async fn similar_invalid_ranking_score_threshold() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -113,7 +113,7 @@ async fn similar_invalid_ranking_score_threshold() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index.similar_post(json!({"rankingScoreThreshold": 42})).await; snapshot!(code, @"400 Bad Request"); @@ -129,8 +129,8 @@ async fn similar_invalid_ranking_score_threshold() { #[actix_rt::test] async fn similar_invalid_id() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -143,7 +143,7 @@ async fn similar_invalid_id() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index.similar_post(json!({"id": "http://invalid-docid/", "embedder": "manual"})).await; @@ -160,8 +160,8 @@ async fn similar_invalid_id() { #[actix_rt::test] async fn similar_not_found_id() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -174,7 +174,7 @@ async fn similar_not_found_id() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index.similar_post(json!({"id": "definitely-doesnt-exist", "embedder": "manual"})).await; @@ -191,8 +191,8 @@ async fn similar_not_found_id() { #[actix_rt::test] async fn similar_bad_offset() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -205,7 +205,7 @@ async fn similar_bad_offset() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index.similar_post(json!({"id": 287947, "offset": "doggo", "embedder": "manual"})).await; @@ -233,8 +233,8 @@ async fn similar_bad_offset() { #[actix_rt::test] async fn similar_bad_limit() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -247,7 +247,7 @@ async fn similar_bad_limit() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index.similar_post(json!({"id": 287947, "limit": "doggo", "embedder": "manual"})).await; @@ -277,8 +277,8 @@ async fn similar_bad_limit() { async fn similar_bad_filter() { // Since a filter is deserialized as a json Value it will never fail to deserialize. // Thus the error message is not generated by deserr but written by us. - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -291,7 +291,7 @@ async fn similar_bad_filter() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); snapshot!(code, @"202 Accepted"); @@ -316,8 +316,8 @@ async fn similar_bad_filter() { #[actix_rt::test] async fn filter_invalid_syntax_object() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -330,7 +330,7 @@ async fn filter_invalid_syntax_object() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -354,8 +354,8 @@ async fn filter_invalid_syntax_object() { #[actix_rt::test] async fn filter_invalid_syntax_array() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -368,7 +368,7 @@ async fn filter_invalid_syntax_array() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -392,8 +392,8 @@ async fn filter_invalid_syntax_array() { #[actix_rt::test] async fn filter_invalid_syntax_string() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -406,7 +406,7 @@ async fn filter_invalid_syntax_string() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -432,8 +432,8 @@ async fn filter_invalid_syntax_string() { #[actix_rt::test] async fn filter_invalid_attribute_array() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -446,7 +446,7 @@ async fn filter_invalid_attribute_array() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -473,8 +473,8 @@ async fn filter_invalid_attribute_array() { #[actix_rt::test] async fn filter_invalid_attribute_string() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -487,7 +487,7 @@ async fn filter_invalid_attribute_string() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -514,8 +514,8 @@ async fn filter_invalid_attribute_string() { #[actix_rt::test] async fn filter_reserved_geo_attribute_array() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -528,7 +528,7 @@ async fn filter_reserved_geo_attribute_array() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -554,8 +554,8 @@ async fn filter_reserved_geo_attribute_array() { #[actix_rt::test] async fn filter_reserved_geo_attribute_string() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -568,7 +568,7 @@ async fn filter_reserved_geo_attribute_string() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -594,8 +594,8 @@ async fn filter_reserved_geo_attribute_string() { #[actix_rt::test] async fn filter_reserved_attribute_array() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -608,7 +608,7 @@ async fn filter_reserved_attribute_array() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -634,8 +634,8 @@ async fn filter_reserved_attribute_array() { #[actix_rt::test] async fn filter_reserved_attribute_string() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -648,7 +648,7 @@ async fn filter_reserved_attribute_string() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -674,8 +674,8 @@ async fn filter_reserved_attribute_string() { #[actix_rt::test] async fn filter_reserved_geo_point_array() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -688,7 +688,7 @@ async fn filter_reserved_geo_point_array() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -714,8 +714,8 @@ async fn filter_reserved_geo_point_array() { #[actix_rt::test] async fn filter_reserved_geo_point_string() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -728,7 +728,7 @@ async fn filter_reserved_geo_point_string() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; @@ -754,8 +754,8 @@ async fn filter_reserved_geo_point_string() { #[actix_rt::test] async fn similar_bad_retrieve_vectors() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index.similar_post(json!({"retrieveVectors": "doggo", "embedder": "manual"})).await; @@ -806,8 +806,8 @@ async fn similar_bad_retrieve_vectors() { #[actix_rt::test] async fn similar_bad_embedder() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -820,7 +820,7 @@ async fn similar_bad_embedder() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; From 52591761af4c0ec73f05a88ab4bf163cccf7e512 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:32:32 +0300 Subject: [PATCH 097/292] tests: Faster search::geo IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/geo.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/crates/meilisearch/tests/search/geo.rs b/crates/meilisearch/tests/search/geo.rs index a314ca241..b74e4e9e4 100644 --- a/crates/meilisearch/tests/search/geo.rs +++ b/crates/meilisearch/tests/search/geo.rs @@ -43,8 +43,8 @@ static DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn geo_sort_with_geo_strings() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_filterable_attributes(json!(["_geo"])).await; @@ -59,7 +59,7 @@ async fn geo_sort_with_geo_strings() { "sort": ["_geoPoint(0.0, 0.0):asc"] }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); }, ) .await; @@ -67,8 +67,8 @@ async fn geo_sort_with_geo_strings() { #[actix_rt::test] async fn geo_bounding_box_with_string_and_number() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.update_settings_filterable_attributes(json!(["_geo"])).await; @@ -82,7 +82,7 @@ async fn geo_bounding_box_with_string_and_number() { "filter": "_geoBoundingBox([89, 179], [-89, -179])", }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ @@ -124,8 +124,8 @@ async fn geo_bounding_box_with_string_and_number() { #[actix_rt::test] async fn bug_4640() { // https://github.com/meilisearch/meilisearch/issues/4640 - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; @@ -140,7 +140,7 @@ async fn bug_4640() { "sort": ["_geoPoint(45.4777599, 9.1967508):asc"], }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ @@ -203,7 +203,7 @@ async fn geo_asc_with_words() { &json!({"searchableAttributes": ["id", "doggo"], "rankingRules": ["words", "geo:asc"]}), &json!({"q": "jean"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ @@ -248,7 +248,7 @@ async fn geo_asc_with_words() { &json!({"searchableAttributes": ["id", "doggo"], "rankingRules": ["words", "geo:asc"]}), &json!({"q": "bob"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ @@ -285,7 +285,7 @@ async fn geo_asc_with_words() { &json!({"searchableAttributes": ["id", "doggo"], "rankingRules": ["words", "geo:asc"]}), &json!({"q": "intel"}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ @@ -325,7 +325,7 @@ async fn geo_sort_with_words() { &json!({"searchableAttributes": ["id", "doggo"], "rankingRules": ["words", "sort"], "sortableAttributes": [RESERVED_GEO_FIELD_NAME]}), &json!({"q": "jean", "sort": ["_geoPoint(0.0, 0.0):asc"]}), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ From 921e3c4ffebf6b0e67498cec4dd6bde6aa45c7b0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:36:08 +0300 Subject: [PATCH 098/292] tests: Faster documents::get_documents IT tests Use shared server + unique index Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/documents/get_documents.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/documents/get_documents.rs b/crates/meilisearch/tests/documents/get_documents.rs index f87a18b9f..4f82faf99 100644 --- a/crates/meilisearch/tests/documents/get_documents.rs +++ b/crates/meilisearch/tests/documents/get_documents.rs @@ -832,8 +832,8 @@ async fn get_document_by_ids_and_filter() { #[actix_rt::test] async fn get_document_with_vectors() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ From 5cb75d1f2a79eba35bbceb92482046d2d0d1f8fd Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Mon, 2 Jun 2025 17:06:53 +0200 Subject: [PATCH 099/292] ignore flaky test --- crates/meilisearch/tests/search/multi/proxy.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/meilisearch/tests/search/multi/proxy.rs b/crates/meilisearch/tests/search/multi/proxy.rs index d267ee153..55736d058 100644 --- a/crates/meilisearch/tests/search/multi/proxy.rs +++ b/crates/meilisearch/tests/search/multi/proxy.rs @@ -2296,6 +2296,7 @@ async fn error_remote_500_once() { } #[actix_rt::test] +#[ignore] async fn error_remote_timeout() { let ms0 = Server::new().await; let ms1 = Server::new().await; From a3d2f64725f7bb0c40460e70f78f8823a1f6e6e8 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:12:09 +0300 Subject: [PATCH 100/292] tests: Faster search::distinct IT tests Use shared server + unique indices Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/distinct.rs | 40 +++++++++---------- .../distinct_at_search_time/succeed.snap | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/crates/meilisearch/tests/search/distinct.rs b/crates/meilisearch/tests/search/distinct.rs index 094ef7bbf..bdc5875e0 100644 --- a/crates/meilisearch/tests/search/distinct.rs +++ b/crates/meilisearch/tests/search/distinct.rs @@ -146,8 +146,8 @@ static DOCUMENT_DISTINCT_KEY: &str = "product_id"; /// testing: https://github.com/meilisearch/meilisearch/issues/4078 #[actix_rt::test] async fn distinct_search_with_offset_no_ranking() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.add_documents(documents, Some(DOCUMENT_PRIMARY_KEY)).await; @@ -163,50 +163,50 @@ async fn distinct_search_with_offset_no_ranking() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"2"); - snapshot!(format!("{:?}", hits), @r#"["123456", "789012"]"#); + snapshot!(format!("{hits:?}"), @r#"["123456", "789012"]"#); snapshot!(response["estimatedTotalHits"] , @"11"); let (response, code) = index.search_post(json!({"offset": 2, "limit": 2})).await; let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"2"); - snapshot!(format!("{:?}", hits), @r#"["456789", "987654"]"#); + snapshot!(format!("{hits:?}"), @r#"["456789", "987654"]"#); snapshot!(response["estimatedTotalHits"], @"10"); let (response, code) = index.search_post(json!({"offset": 4, "limit": 2})).await; let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"2"); - snapshot!(format!("{:?}", hits), @r#"["234567", "345678"]"#); + snapshot!(format!("{hits:?}"), @r#"["234567", "345678"]"#); snapshot!(response["estimatedTotalHits"], @"6"); let (response, code) = index.search_post(json!({"offset": 5, "limit": 2})).await; let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"1"); - snapshot!(format!("{:?}", hits), @r#"["345678"]"#); + snapshot!(format!("{hits:?}"), @r#"["345678"]"#); snapshot!(response["estimatedTotalHits"], @"6"); let (response, code) = index.search_post(json!({"offset": 6, "limit": 2})).await; let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"0"); - snapshot!(format!("{:?}", hits), @r#"[]"#); + snapshot!(format!("{hits:?}"), @r#"[]"#); snapshot!(response["estimatedTotalHits"], @"6"); let (response, code) = index.search_post(json!({"offset": 7, "limit": 2})).await; let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"0"); - snapshot!(format!("{:?}", hits), @r#"[]"#); + snapshot!(format!("{hits:?}"), @r#"[]"#); snapshot!(response["estimatedTotalHits"], @"6"); } /// testing: https://github.com/meilisearch/meilisearch/issues/4130 #[actix_rt::test] async fn distinct_search_with_pagination_no_ranking() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = DOCUMENTS.clone(); index.add_documents(documents, Some(DOCUMENT_PRIMARY_KEY)).await; @@ -222,7 +222,7 @@ async fn distinct_search_with_pagination_no_ranking() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"0"); - snapshot!(format!("{:?}", hits), @r#"[]"#); + snapshot!(format!("{hits:?}"), @r#"[]"#); snapshot!(response["page"], @"0"); snapshot!(response["totalPages"], @"3"); snapshot!(response["totalHits"], @"6"); @@ -231,7 +231,7 @@ async fn distinct_search_with_pagination_no_ranking() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"2"); - snapshot!(format!("{:?}", hits), @r#"["123456", "789012"]"#); + snapshot!(format!("{hits:?}"), @r#"["123456", "789012"]"#); snapshot!(response["page"], @"1"); snapshot!(response["totalPages"], @"3"); snapshot!(response["totalHits"], @"6"); @@ -240,7 +240,7 @@ async fn distinct_search_with_pagination_no_ranking() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"2"); - snapshot!(format!("{:?}", hits), @r#"["456789", "987654"]"#); + snapshot!(format!("{hits:?}"), @r#"["456789", "987654"]"#); snapshot!(response["page"], @"2"); snapshot!(response["totalPages"], @"3"); snapshot!(response["totalHits"], @"6"); @@ -249,7 +249,7 @@ async fn distinct_search_with_pagination_no_ranking() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"2"); - snapshot!(format!("{:?}", hits), @r#"["234567", "345678"]"#); + snapshot!(format!("{hits:?}"), @r#"["234567", "345678"]"#); snapshot!(response["page"], @"3"); snapshot!(response["totalPages"], @"3"); snapshot!(response["totalHits"], @"6"); @@ -258,7 +258,7 @@ async fn distinct_search_with_pagination_no_ranking() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"0"); - snapshot!(format!("{:?}", hits), @r#"[]"#); + snapshot!(format!("{hits:?}"), @r#"[]"#); snapshot!(response["page"], @"4"); snapshot!(response["totalPages"], @"3"); snapshot!(response["totalHits"], @"6"); @@ -267,7 +267,7 @@ async fn distinct_search_with_pagination_no_ranking() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"3"); - snapshot!(format!("{:?}", hits), @r#"["987654", "234567", "345678"]"#); + snapshot!(format!("{hits:?}"), @r#"["987654", "234567", "345678"]"#); snapshot!(response["page"], @"2"); snapshot!(response["totalPages"], @"2"); snapshot!(response["totalHits"], @"6"); @@ -275,13 +275,13 @@ async fn distinct_search_with_pagination_no_ranking() { #[actix_rt::test] async fn distinct_at_search_time() { - let server = Server::new().await; - let index = server.index("tamo"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); index.add_documents(documents, Some(DOCUMENT_PRIMARY_KEY)).await; let (task, _) = index.update_settings_filterable_attributes(json!(["color.main"])).await; - let task = index.wait_task(task.uid()).await; + let task = index.wait_task(task.uid()).await.succeeded(); snapshot!(task, name: "succeed"); fn get_hits(response: &Value) -> Vec { @@ -299,7 +299,7 @@ async fn distinct_at_search_time() { let hits = get_hits(&response); snapshot!(code, @"200 OK"); snapshot!(hits.len(), @"3"); - snapshot!(format!("{:?}", hits), @r###"["1", "2", "3"]"###); + snapshot!(format!("{hits:?}"), @r###"["1", "2", "3"]"###); snapshot!(response["page"], @"1"); snapshot!(response["totalPages"], @"1"); snapshot!(response["totalHits"], @"3"); diff --git a/crates/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap b/crates/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap index ea55d9c61..c1b01a5e2 100644 --- a/crates/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap +++ b/crates/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap @@ -4,7 +4,7 @@ source: crates/meilisearch/tests/search/distinct.rs { "uid": "[uid]", "batchUid": "[batch_uid]", - "indexUid": "tamo", + "indexUid": "[uuid]", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, From 161cb736ea501b1913c62917b622424c75a1f4a9 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 3 Jun 2025 10:37:29 +0200 Subject: [PATCH 101/292] Adapt tests to the Chinese word segmenter changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new Chinese segmenter is splitting words in smaller parts. The words `小化妆包` was previously seegmented as `小 / 化妆包` and is now segmented as `小 / 化妆 / 包`, which changes the tests results. --- crates/milli/src/update/index_documents/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/milli/src/update/index_documents/mod.rs b/crates/milli/src/update/index_documents/mod.rs index 4acb78b9a..e0f85ca2d 100644 --- a/crates/milli/src/update/index_documents/mod.rs +++ b/crates/milli/src/update/index_documents/mod.rs @@ -1580,12 +1580,12 @@ mod tests { let rtxn = index.read_txn().unwrap(); // Only the first document should match. - let count = index.word_docids.get(&rtxn, "huàzhuāngbāo").unwrap().unwrap().len(); + let count = index.word_docids.get(&rtxn, "huàzhuāng").unwrap().unwrap().len(); assert_eq!(count, 1); // Only the second document should match. let count = index.word_docids.get(&rtxn, "bāo").unwrap().unwrap().len(); - assert_eq!(count, 1); + assert_eq!(count, 2); let mut search = crate::Search::new(&rtxn, &index); search.query("化妆包"); From cb7bb36080ba1216a724baaf0683107d5f82461e Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 3 Jun 2025 10:48:41 +0200 Subject: [PATCH 102/292] update charabia v0.9.6 --- Cargo.lock | 224 +++++++++++++++------------------------- crates/milli/Cargo.toml | 2 +- 2 files changed, 84 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 84e13a78c..0e9a072d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,7 +203,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.5", + "socket2 0.5.10", "time", "url", ] @@ -982,9 +982,9 @@ dependencies = [ [[package]] name = "charabia" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da3b398d57d5526189869b32ac0b4f7fb436f490f47a2a19685cee634df72d2" +checksum = "3b01abfd2db0eb8c4e7a47ccab5d1f67993736f4e76923ed9ae281c49070645d" dependencies = [ "aho-corasick", "csv", @@ -2538,9 +2538,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -2550,9 +2550,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "1.4.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -2584,23 +2584,28 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 0.26.1", ] [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.2.0", "http-body", "hyper", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -2878,9 +2883,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "irg-kvariants" @@ -2893,6 +2898,16 @@ dependencies = [ "serde", ] +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.13" @@ -3154,9 +3169,9 @@ dependencies = [ [[package]] name = "lindera" -version = "0.42.3" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa3936dbcfc54b90a53da68ec8fe209656cfa691147f951944f48c61dcde317" +checksum = "f20720cb4206e87b6844b05c66b23301e7bb532718f200ff55bbbdfbce9b7f2b" dependencies = [ "anyhow", "bincode", @@ -3184,9 +3199,9 @@ dependencies = [ [[package]] name = "lindera-cc-cedict" -version = "0.42.3" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4720c69e32b278614eefb8181e0ef78907fa115d947edaeaedb1150785b902" +checksum = "0f6ddd4aeaeaf1ce47ea5785bd6a273179d32df4af4b306d9b65a7a7f81a0e61" dependencies = [ "bincode", "byteorder", @@ -3197,9 +3212,9 @@ dependencies = [ [[package]] name = "lindera-dictionary" -version = "0.42.3" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b123ac54a74c9418616c96d0d7cf5eb8fbf372211c07032d1e174c94e40ff030" +checksum = "f9b5e417c4c6e001459e019b178f65f759be9c2cbf2d9bd803ec5d8ed0e62124" dependencies = [ "anyhow", "bincode", @@ -3225,9 +3240,9 @@ dependencies = [ [[package]] name = "lindera-ipadic" -version = "0.42.3" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c3786e6cf65dd1e8537c3c35637f887289bf83687f6fbcac3a6679bfa33265" +checksum = "c2867975f1b92d1093ccbb52c5c1664a56dfbd27a2fece0166c765ad1f043f31" dependencies = [ "bincode", "byteorder", @@ -3238,9 +3253,9 @@ dependencies = [ [[package]] name = "lindera-ipadic-neologd" -version = "0.42.3" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42646cc30bf8ceabf3db1154358329e1031f2af25ca1721ddba8ee3666881a08" +checksum = "c54c4c2d3fb8b380d0ace5ae97111ca444bcfa7721966f552117d57f07d8b3b1" dependencies = [ "bincode", "byteorder", @@ -3251,9 +3266,9 @@ dependencies = [ [[package]] name = "lindera-ko-dic" -version = "0.42.3" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f94a00fc5931636c10d2e6af4cfa43fbf95f8a529caa45d10600f3cb2853c9" +checksum = "7f495e64f62deee60d9b71dbe3fd39b69b8688c9d591842f81f94e200eb4d81f" dependencies = [ "bincode", "byteorder", @@ -3264,9 +3279,9 @@ dependencies = [ [[package]] name = "lindera-unidic" -version = "0.42.3" +version = "0.43.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5933014ca145351d59bb50a6e509a53af1f89ceda687fe9efd6d534e6b59a27" +checksum = "e85ff97ce04c519fbca0f05504ea028761ccc456b1e84cf1e75fac57f9b3caf1" dependencies = [ "bincode", "byteorder", @@ -4549,7 +4564,7 @@ checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" dependencies = [ "libc", "once_cell", - "socket2 0.5.5", + "socket2 0.5.10", "tracing", "windows-sys 0.52.0", ] @@ -4754,9 +4769,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.15" +version = "0.12.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" dependencies = [ "base64 0.22.1", "bytes", @@ -4778,7 +4793,6 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", @@ -4788,14 +4802,14 @@ dependencies = [ "tokio-rustls", "tokio-util", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots", - "windows-registry", + "webpki-roots 1.0.0", ] [[package]] @@ -5308,12 +5322,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5735,9 +5749,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -5746,7 +5760,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2 0.5.10", "tokio-macros", "windows-sys 0.52.0", ] @@ -5846,6 +5860,24 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower-http" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2" +dependencies = [ + "bitflags 2.9.0", + "bytes", + "futures-util", + "http 1.2.0", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -6116,7 +6148,7 @@ dependencies = [ "serde_json", "socks", "url", - "webpki-roots", + "webpki-roots 0.26.1", ] [[package]] @@ -6411,6 +6443,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "whatlang" version = "0.16.4" @@ -6470,7 +6511,7 @@ checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ "windows-implement", "windows-interface", - "windows-result 0.1.2", + "windows-result", "windows-targets 0.52.6", ] @@ -6496,23 +6537,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result 0.3.2", - "windows-strings", - "windows-targets 0.53.0", -] - [[package]] name = "windows-result" version = "0.1.2" @@ -6522,24 +6546,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -6615,29 +6621,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -6656,12 +6646,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -6680,12 +6664,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -6704,24 +6682,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -6740,12 +6706,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -6764,12 +6724,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -6788,12 +6742,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -6812,12 +6760,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.5.40" diff --git a/crates/milli/Cargo.toml b/crates/milli/Cargo.toml index 3ce02b444..08e0c4728 100644 --- a/crates/milli/Cargo.toml +++ b/crates/milli/Cargo.toml @@ -18,7 +18,7 @@ bincode = "1.3.3" bstr = "1.11.3" bytemuck = { version = "1.21.0", features = ["extern_crate_alloc"] } byteorder = "1.5.0" -charabia = { version = "0.9.5", default-features = false } +charabia = { version = "0.9.6", default-features = false } concat-arrays = "0.1.2" convert_case = "0.6.0" crossbeam-channel = "0.5.15" From 41b1cd5a73ab8cb7643fbe30908bbff78f041ca7 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 13:08:12 +0300 Subject: [PATCH 103/292] Extract GEO_DOCUMENTS static variable and shared index with these docs Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/mod.rs | 54 ++++++++++++++++++++++ crates/meilisearch/tests/search/geo.rs | 63 ++------------------------ 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/crates/meilisearch/tests/common/mod.rs b/crates/meilisearch/tests/common/mod.rs index 046519a0e..9823bf483 100644 --- a/crates/meilisearch/tests/common/mod.rs +++ b/crates/meilisearch/tests/common/mod.rs @@ -453,3 +453,57 @@ pub async fn shared_index_with_test_set() -> &'static Index<'static, Shared> { }) .await } + +pub static GEO_DOCUMENTS: Lazy = Lazy::new(|| { + json!([ + { + "id": 1, + "name": "Taco Truck", + "address": "444 Salsa Street, Burritoville", + "type": "Mexican", + "rating": 9, + "_geo": { + "lat": 34.0522, + "lng": -118.2437 + } + }, + { + "id": 2, + "name": "La Bella Italia", + "address": "456 Elm Street, Townsville", + "type": "Italian", + "rating": 9, + "_geo": { + "lat": "45.4777599", + "lng": "9.1967508" + } + }, + { + "id": 3, + "name": "Crêpe Truck", + "address": "2 Billig Avenue, Rouenville", + "type": "French", + "rating": 10 + } + ]) +}); + +pub async fn shared_index_with_geo_documents() -> &'static Index<'static, Shared> { + static INDEX: OnceCell> = OnceCell::const_new(); + INDEX + .get_or_init(|| async { + let server = Server::new_shared(); + let index = server._index("SHARED_GEO_DOCUMENTS").to_shared(); + let (response, _code) = index._add_documents(GEO_DOCUMENTS.clone(), None).await; + index.wait_task(response.uid()).await.succeeded(); + + let (response, _code) = index + ._update_settings( + json!({"filterableAttributes": ["_geo"], "sortableAttributes": ["_geo"]}), + ) + .await; + index.wait_task(response.uid()).await.succeeded(); + index + }) + .await +} diff --git a/crates/meilisearch/tests/search/geo.rs b/crates/meilisearch/tests/search/geo.rs index b74e4e9e4..5e731ffde 100644 --- a/crates/meilisearch/tests/search/geo.rs +++ b/crates/meilisearch/tests/search/geo.rs @@ -2,55 +2,14 @@ use meili_snap::{json_string, snapshot}; use meilisearch_types::milli::constants::RESERVED_GEO_FIELD_NAME; use once_cell::sync::Lazy; -use crate::common::{Server, Value}; +use crate::common::shared_index_with_geo_documents; use crate::json; use super::test_settings_documents_indexing_swapping_and_search; -static DOCUMENTS: Lazy = Lazy::new(|| { - json!([ - { - "id": 1, - "name": "Taco Truck", - "address": "444 Salsa Street, Burritoville", - "type": "Mexican", - "rating": 9, - "_geo": { - "lat": 34.0522, - "lng": -118.2437 - } - }, - { - "id": 2, - "name": "La Bella Italia", - "address": "456 Elm Street, Townsville", - "type": "Italian", - "rating": 9, - "_geo": { - "lat": "45.4777599", - "lng": "9.1967508" - } - }, - { - "id": 3, - "name": "Crêpe Truck", - "address": "2 Billig Avenue, Rouenville", - "type": "French", - "rating": 10 - } - ]) -}); - #[actix_rt::test] async fn geo_sort_with_geo_strings() { - let server = Server::new_shared(); - let index = server.unique_index(); - - let documents = DOCUMENTS.clone(); - index.update_settings_filterable_attributes(json!(["_geo"])).await; - index.update_settings_sortable_attributes(json!(["_geo"])).await; - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let index = shared_index_with_geo_documents().await; index .search( @@ -67,14 +26,7 @@ async fn geo_sort_with_geo_strings() { #[actix_rt::test] async fn geo_bounding_box_with_string_and_number() { - let server = Server::new_shared(); - let index = server.unique_index(); - - let documents = DOCUMENTS.clone(); - index.update_settings_filterable_attributes(json!(["_geo"])).await; - index.update_settings_sortable_attributes(json!(["_geo"])).await; - let (ret, _code) = index.add_documents(documents, None).await; - index.wait_task(ret.uid()).await.succeeded(); + let index = shared_index_with_geo_documents().await; index .search( @@ -124,14 +76,7 @@ async fn geo_bounding_box_with_string_and_number() { #[actix_rt::test] async fn bug_4640() { // https://github.com/meilisearch/meilisearch/issues/4640 - let server = Server::new_shared(); - let index = server.unique_index(); - - let documents = DOCUMENTS.clone(); - index.add_documents(documents, None).await; - index.update_settings_filterable_attributes(json!(["_geo"])).await; - let (ret, _code) = index.update_settings_sortable_attributes(json!(["_geo"])).await; - index.wait_task(ret.uid()).await.succeeded(); + let index = shared_index_with_geo_documents().await; // Sort the document with the second one first index From 54fdf379bb7da4849e57fb92f638934c8271baf1 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 13:41:13 +0300 Subject: [PATCH 104/292] Use shared_does_not_exists_index() index for delete_one_document_unexisting_index() test case Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/documents/delete_documents.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/meilisearch/tests/documents/delete_documents.rs b/crates/meilisearch/tests/documents/delete_documents.rs index 26dfba8c8..5ea122bd0 100644 --- a/crates/meilisearch/tests/documents/delete_documents.rs +++ b/crates/meilisearch/tests/documents/delete_documents.rs @@ -1,13 +1,12 @@ use meili_snap::{json_string, snapshot}; -use crate::common::{GetAllDocumentsOptions, Server}; +use crate::common::{shared_does_not_exists_index, GetAllDocumentsOptions, Server}; use crate::json; #[actix_rt::test] async fn delete_one_document_unexisting_index() { - let server = Server::new_shared(); - let index = server.unique_index(); - let (task, code) = index.delete_document(0).await; + let index = shared_does_not_exists_index().await; + let (task, code) = index.delete_document_by_filter_fail(json!({"filter": "a = b"})).await; assert_eq!(code, 202); index.wait_task(task.uid()).await.failed(); From 3668f5f021a74db5c08fbceca83f1eeb3b3a4096 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Tue, 3 Jun 2025 13:44:38 +0300 Subject: [PATCH 105/292] Use unique server+index for `list_tasks()` test case Co-authored-by: Tamo --- crates/meilisearch/tests/tasks/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 57cb87364..303e0aa91 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -49,8 +49,9 @@ async fn get_task_status() { #[actix_rt::test] async fn list_tasks() { - let server = Server::new_shared(); - let index = server.unique_index(); + // Do not use a shared server because we want to assert stuff against the global list of tasks + let server = Server::new().await; + let index = server.index("test"); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index From a50b69b868f07bda7c28376aadd8c510c162bce9 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Tue, 3 Jun 2025 13:45:17 +0300 Subject: [PATCH 106/292] Use unique server+index for `list_tasks_status_filtered()` test case Co-authored-by: Tamo --- crates/meilisearch/tests/tasks/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 303e0aa91..9f60d3caf 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -152,8 +152,9 @@ async fn list_tasks_with_star_filters() { #[actix_rt::test] async fn list_tasks_status_filtered() { - let server = Server::new_shared(); - let index = server.unique_index(); + // Do not use a shared server because we want to assert stuff against the global list of tasks + let server = Server::new().await; + let index = server.index("test"); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = index.create(None).await; From f95f29c492606f37024300185fbcf6e6c61b3967 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Tue, 3 Jun 2025 13:45:46 +0300 Subject: [PATCH 107/292] Use unique server+index for `list_tasks_type_filtered()` test case Co-authored-by: Tamo --- crates/meilisearch/tests/tasks/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 9f60d3caf..093817476 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -175,8 +175,9 @@ async fn list_tasks_status_filtered() { #[actix_rt::test] async fn list_tasks_type_filtered() { - let server = Server::new_shared(); - let index = server.unique_index(); + // Do not use a shared server because we want to assert stuff against the global list of tasks + let server = Server::new().await; + let index = server.index("test"); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index From d3d501585422a57a45c7fdf65411c7cff92a1a6d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 13:50:04 +0300 Subject: [PATCH 108/292] Use the cancelled task uid Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/tasks/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 093817476..2bf8f0aa8 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -200,11 +200,12 @@ async fn list_tasks_invalid_canceled_by_filter() { let index = server.unique_index(); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); - index + let (task, _code) = index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; - let (response, code) = index.filtered_tasks(&[], &[], &["0"]).await; + let (response, code) = + index.filtered_tasks(&[], &[], &[format!("{}", task.uid()).as_str()]).await; assert_eq!(code, 200, "{response}"); assert_eq!(response["results"].as_array().unwrap().len(), 0); } From 0b1f634afa82db8d5c2efb8ebd2701c13a8efced Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 13:52:55 +0300 Subject: [PATCH 109/292] Remove useless code Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/tasks/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 2bf8f0aa8..16948c571 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -12,8 +12,6 @@ use crate::json; async fn error_get_unexisting_task_status() { let server = Server::new_shared(); let index = server.unique_index(); - let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); let (response, code) = index.get_task(u32::MAX as u64).await; let expected_response = json!({ From 96c81762ed7b8ad228e71e7dda8e11706310e754 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Tue, 3 Jun 2025 14:00:38 +0300 Subject: [PATCH 110/292] Apply suggestions from code review Do not redactions for the snapshot assertions Co-authored-by: Tamo --- crates/meilisearch/tests/tasks/mod.rs | 62 ++++++++++----------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 16948c571..fb45223e6 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -210,8 +210,9 @@ async fn list_tasks_invalid_canceled_by_filter() { #[actix_rt::test] async fn list_tasks_status_and_type_filtered() { - let server = Server::new_shared(); - let index = server.unique_index(); + // Do not use a shared server because we want to assert stuff against the global list of tasks + let server = Server::new().await; + let index = server.index("test"); let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); index @@ -285,8 +286,7 @@ async fn test_summarized_document_addition_or_update() { index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -311,8 +311,7 @@ async fn test_summarized_document_addition_or_update() { index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -346,8 +345,7 @@ async fn test_summarized_delete_documents_by_batch() { .await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -378,8 +376,7 @@ async fn test_summarized_delete_documents_by_batch() { let (del_task, _status_code) = index.delete_batch(vec![42]).await; index.wait_task(del_task.uid()).await.succeeded(); let (task, _) = index.get_task(del_task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -411,8 +408,7 @@ async fn test_summarized_delete_documents_by_filter() { index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -444,8 +440,7 @@ async fn test_summarized_delete_documents_by_filter() { index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -477,8 +472,7 @@ async fn test_summarized_delete_documents_by_filter() { index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -508,8 +502,7 @@ async fn test_summarized_delete_document_by_id() { let (task, _status_code) = index.delete_document(1).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -540,8 +533,7 @@ async fn test_summarized_delete_document_by_id() { let (task, _status_code) = index.delete_document(42).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -583,8 +575,7 @@ async fn test_summarized_settings_update() { let (task,_status_code) = index.update_settings(json!({ "displayedAttributes": ["doggos", "name"], "filterableAttributes": ["age", "nb_paw_pads"], "sortableAttributes": ["iq"] })).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -622,8 +613,7 @@ async fn test_summarized_index_creation() { let (task, _status_code) = index.create(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -646,8 +636,7 @@ async fn test_summarized_index_creation() { let (task, _status_code) = index.create(Some("doggos")).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -790,8 +779,7 @@ async fn test_summarized_index_update() { let (task, _status_code) = index.update(None).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -819,8 +807,7 @@ async fn test_summarized_index_update() { let (task, _status_code) = index.update(Some("bones")).await; index.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -851,8 +838,7 @@ async fn test_summarized_index_update() { let (task, _status_code) = index.update(None).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -875,8 +861,7 @@ async fn test_summarized_index_update() { let (task, _status_code) = index.update(Some("bones")).await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -907,8 +892,7 @@ async fn test_summarized_index_swap() { .await; server.wait_task(task.uid()).await.failed(); let (task, _) = server.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -1027,8 +1011,7 @@ async fn test_summarized_task_deletion() { let (task, _status_code) = server.delete_tasks("uids=0").await; index.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", @@ -1057,8 +1040,7 @@ async fn test_summarized_dump_creation() { let (task, _status_code) = server.create_dump().await; server.wait_task(task.uid()).await; let (task, _) = server.get_task(task.uid()).await; - snapshot!(json_string!(task, - { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".details.dumpUid" => "[dumpUid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), + snapshot!(task, @r###" { "uid": "[uid]", From 70aa78a2c2c5aa0bff68f2d5caa81f8de82ef724 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 14:04:15 +0300 Subject: [PATCH 111/292] Remove unused import Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/geo.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/meilisearch/tests/search/geo.rs b/crates/meilisearch/tests/search/geo.rs index 5e731ffde..5f4eff947 100644 --- a/crates/meilisearch/tests/search/geo.rs +++ b/crates/meilisearch/tests/search/geo.rs @@ -1,6 +1,5 @@ use meili_snap::{json_string, snapshot}; use meilisearch_types::milli::constants::RESERVED_GEO_FIELD_NAME; -use once_cell::sync::Lazy; use crate::common::shared_index_with_geo_documents; use crate::json; From d6ae39bf0f51ee0f9e5e0059a22289ba4ce1459e Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:56:03 +0300 Subject: [PATCH 112/292] tests: Faster search::hybrid IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/hybrid.rs | 62 +++++++++++------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/crates/meilisearch/tests/search/hybrid.rs b/crates/meilisearch/tests/search/hybrid.rs index 3a8fb2b4c..01de9a057 100644 --- a/crates/meilisearch/tests/search/hybrid.rs +++ b/crates/meilisearch/tests/search/hybrid.rs @@ -2,31 +2,31 @@ use meili_snap::snapshot; use once_cell::sync::Lazy; use crate::common::index::Index; -use crate::common::{Server, Value}; +use crate::common::{Server, Shared, Value}; use crate::json; async fn index_with_documents_user_provided<'a>( - server: &'a Server, + server: &'a Server, documents: &Value, ) -> Index<'a> { - let index = server.index("test"); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ "embedders": {"default": { "source": "userProvided", "dimensions": 2}}} )) .await; - assert_eq!(202, code, "{:?}", response); + assert_eq!(202, code, "{response:?}"); index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.add_documents(documents.clone(), None).await; - assert_eq!(202, code, "{:?}", response); + assert_eq!(202, code, "{response:?}"); index.wait_task(response.uid()).await.succeeded(); index } -async fn index_with_documents_hf<'a>(server: &'a Server, documents: &Value) -> Index<'a> { - let index = server.index("test"); +async fn index_with_documents_hf<'a>(server: &'a Server, documents: &Value) -> Index<'a> { + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ "embedders": {"default": { @@ -36,11 +36,11 @@ async fn index_with_documents_hf<'a>(server: &'a Server, documents: &Value) -> I "documentTemplate": "{{doc.title}}, {{doc.desc}}" }}} )) .await; - assert_eq!(202, code, "{:?}", response); + assert_eq!(202, code, "{response:?}"); index.wait_task(response.uid()).await.succeeded(); let (response, code) = index.add_documents(documents.clone(), None).await; - assert_eq!(202, code, "{:?}", response); + assert_eq!(202, code, "{response:?}"); index.wait_task(response.uid()).await.succeeded(); index } @@ -139,8 +139,8 @@ static SIMPLE_SEARCH_DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn simple_search() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; let (response, code) = index .search_post( @@ -172,8 +172,8 @@ async fn simple_search() { #[actix_rt::test] async fn limit_offset() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; let (response, code) = index .search_post( @@ -185,8 +185,8 @@ async fn limit_offset() { snapshot!(response["semanticHitCount"], @"0"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; let (response, code) = index .search_post( @@ -201,8 +201,8 @@ async fn limit_offset() { #[actix_rt::test] async fn simple_search_hf() { - let server = Server::new().await; - let index = index_with_documents_hf(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents_hf(server, &SIMPLE_SEARCH_DOCUMENTS).await; let (response, code) = index .search_post( @@ -253,8 +253,8 @@ async fn simple_search_hf() { #[actix_rt::test] async fn distribution_shift() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; let search = json!({"q": "Captain", "vector": [1.0, 1.0], "showRankingScore": true, "hybrid": {"embedder": "default", "semanticRatio": 1.0}, "retrieveVectors": true}); let (response, code) = index.search_post(search.clone()).await; @@ -275,7 +275,7 @@ async fn distribution_shift() { .await; snapshot!(code, @"202 Accepted"); - let response = server.wait_task(response.uid()).await; + let response = server.wait_task(response.uid()).await.succeeded(); snapshot!(response["details"], @r#"{"embedders":{"default":{"distribution":{"mean":0.998,"sigma":0.01}}}}"#); let (response, code) = index.search_post(search).await; @@ -285,8 +285,8 @@ async fn distribution_shift() { #[actix_rt::test] async fn highlighter() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; let (response, code) = index .search_post(json!({"q": "Captain Marvel", "vector": [1.0, 1.0], @@ -340,8 +340,8 @@ async fn highlighter() { #[actix_rt::test] async fn invalid_semantic_ratio() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; let (response, code) = index .search_post( @@ -412,8 +412,8 @@ async fn invalid_semantic_ratio() { #[actix_rt::test] async fn single_document() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SINGLE_DOCUMENT_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SINGLE_DOCUMENT_VEC).await; let (response, code) = index .search_post( @@ -428,8 +428,8 @@ async fn single_document() { #[actix_rt::test] async fn query_combination() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &SIMPLE_SEARCH_DOCUMENTS_VEC).await; // search without query and vector, but with hybrid => still placeholder let (response, code) = index @@ -581,7 +581,7 @@ async fn distinct_is_applied() { #[actix_rt::test] async fn retrieve_vectors() { - let server = Server::new().await; + let server = Server::new_shared(); let index = index_with_documents_hf(&server, &SIMPLE_SEARCH_DOCUMENTS).await; let (response, code) = index @@ -632,7 +632,7 @@ async fn retrieve_vectors() { let (response, code) = index .update_settings(json!({ "displayedAttributes": ["id", "title", "desc", "_vectors"]} )) .await; - assert_eq!(202, code, "{:?}", response); + assert_eq!(202, code, "{response:?}"); index.wait_task(response.uid()).await.succeeded(); let (response, code) = index @@ -682,7 +682,7 @@ async fn retrieve_vectors() { // remove `_vectors` from displayed attributes let (response, code) = index.update_settings(json!({ "displayedAttributes": ["id", "title", "desc"]} )).await; - assert_eq!(202, code, "{:?}", response); + assert_eq!(202, code, "{response:?}"); index.wait_task(response.uid()).await.succeeded(); let (response, code) = index From 7c6162f0bf65039fd20db63c32e4472f295fdcae Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 08:25:33 +0300 Subject: [PATCH 113/292] Fix clippy error Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/hybrid.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/search/hybrid.rs b/crates/meilisearch/tests/search/hybrid.rs index 01de9a057..96a7ee1c9 100644 --- a/crates/meilisearch/tests/search/hybrid.rs +++ b/crates/meilisearch/tests/search/hybrid.rs @@ -582,7 +582,7 @@ async fn distinct_is_applied() { #[actix_rt::test] async fn retrieve_vectors() { let server = Server::new_shared(); - let index = index_with_documents_hf(&server, &SIMPLE_SEARCH_DOCUMENTS).await; + let index = index_with_documents_hf(server, &SIMPLE_SEARCH_DOCUMENTS).await; let (response, code) = index .search_post( From 733175359a073686b021d8cf03e2152933eb1481 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 15:29:45 +0300 Subject: [PATCH 114/292] Update the new test case to use the new signature of index_with_documents_user_provided() Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/hybrid.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/search/hybrid.rs b/crates/meilisearch/tests/search/hybrid.rs index 96a7ee1c9..c6eb39a3a 100644 --- a/crates/meilisearch/tests/search/hybrid.rs +++ b/crates/meilisearch/tests/search/hybrid.rs @@ -538,8 +538,8 @@ async fn query_combination() { // see #[actix_rt::test] async fn distinct_is_applied() { - let server = Server::new().await; - let index = index_with_documents_user_provided(&server, &TEST_DISTINCT_DOCUMENTS).await; + let server = Server::new_shared(); + let index = index_with_documents_user_provided(server, &TEST_DISTINCT_DOCUMENTS).await; let (response, code) = index.update_settings(json!({ "distinctAttribute": "distinct" } )).await; assert_eq!(202, code, "{:?}", response); From 693fcd5752b1fc59ee0e56101bf11f063c020e11 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 15:40:40 +0300 Subject: [PATCH 115/292] Try with GITHUB_TOKEN Signed-off-by: Martin Tzvetanov Grigorov --- .github/workflows/db-change-missing.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/db-change-missing.yml b/.github/workflows/db-change-missing.yml index 12a616f88..1ae48527f 100644 --- a/.github/workflows/db-change-missing.yml +++ b/.github/workflows/db-change-missing.yml @@ -4,22 +4,22 @@ on: pull_request: types: [opened, synchronize, reopened, labeled, unlabeled] -env: - GH_TOKEN: ${{ secrets.MEILI_BOT_GH_PAT }} - jobs: check-labels: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check db change labels id: check_labels + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | URL=/repos/meilisearch/meilisearch/pulls/${{ github.event.pull_request.number }}/labels echo ${{ github.event.pull_request.number }} echo $URL LABELS=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/meilisearch/meilisearch/issues/${{ github.event.pull_request.number }}/labels -q .[].name) + echo "Labels: $LABELS" if [[ ! "$LABELS" =~ "db change" && ! "$LABELS" =~ "no db change" ]]; then echo "::error::Pull request must contain either the 'db change' or 'no db change' label." exit 1 From af54c8381e7d6986b7ce0710b5cea755fa910617 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 3 Jun 2025 15:46:16 +0300 Subject: [PATCH 116/292] Use ${{ github.repository }} instead of hardcoding the repo/owner Signed-off-by: Martin Tzvetanov Grigorov --- .github/workflows/db-change-missing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/db-change-missing.yml b/.github/workflows/db-change-missing.yml index 1ae48527f..6d15afd69 100644 --- a/.github/workflows/db-change-missing.yml +++ b/.github/workflows/db-change-missing.yml @@ -18,7 +18,7 @@ jobs: URL=/repos/meilisearch/meilisearch/pulls/${{ github.event.pull_request.number }}/labels echo ${{ github.event.pull_request.number }} echo $URL - LABELS=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/meilisearch/meilisearch/issues/${{ github.event.pull_request.number }}/labels -q .[].name) + LABELS=$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels -q .[].name) echo "Labels: $LABELS" if [[ ! "$LABELS" =~ "db change" && ! "$LABELS" =~ "no db change" ]]; then echo "::error::Pull request must contain either the 'db change' or 'no db change' label." From 5400f3941a3a22457ced8362767dafb53c7da511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 13 May 2025 11:19:32 +0200 Subject: [PATCH 117/292] Introduce the first version of the /chat route that mimics the OpenAI API --- Cargo.lock | 211 +++++++++++++++++++++++++- crates/benchmarks/Cargo.toml | 2 +- crates/meilisearch-types/src/keys.rs | 6 + crates/meilisearch/Cargo.toml | 1 + crates/meilisearch/src/routes/chat.rs | 32 ++++ crates/meilisearch/src/routes/mod.rs | 4 +- 6 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 crates/meilisearch/src/routes/chat.rs diff --git a/Cargo.lock b/Cargo.lock index 0e9a072d3..cd314a025 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -429,6 +429,43 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-openai" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ac0334b0fef1ddaf141154a3ef6d55a95b5b1a52c720753554b0a1ca670e68" +dependencies = [ + "async-openai-macros", + "backoff", + "base64 0.22.1", + "bytes", + "derive_builder 0.20.2", + "eventsource-stream", + "futures", + "rand 0.8.5", + "reqwest", + "reqwest-eventsource", + "secrecy", + "serde", + "serde_json", + "thiserror 2.0.12", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", +] + +[[package]] +name = "async-openai-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0289cba6d5143bfe8251d57b4a8cac036adf158525a76533a7082ba65ec76398" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "async-trait" version = "0.1.85" @@ -452,6 +489,20 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "futures-core", + "getrandom 0.2.15", + "instant", + "pin-project-lite", + "rand 0.8.5", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.68" @@ -1184,6 +1235,26 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1856,6 +1927,17 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" +[[package]] +name = "eventsource-stream" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" +dependencies = [ + "futures-core", + "nom", + "pin-project-lite", +] + [[package]] name = "fancy-regex" version = "0.13.0" @@ -2036,6 +2118,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -2580,6 +2668,7 @@ dependencies = [ "hyper", "hyper-util", "rustls", + "rustls-native-certs 0.7.3", "rustls-pki-types", "tokio", "tokio-rustls", @@ -3505,6 +3594,7 @@ dependencies = [ "actix-utils", "actix-web", "anyhow", + "async-openai", "async-trait", "brotli", "bstr", @@ -4080,6 +4170,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "option-ext" version = "0.2.0" @@ -4788,11 +4884,13 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "once_cell", "percent-encoding", "pin-project-lite", "quinn", "rustls", + "rustls-native-certs 0.8.1", "rustls-pki-types", "serde", "serde_json", @@ -4812,6 +4910,22 @@ dependencies = [ "webpki-roots 1.0.0", ] +[[package]] +name = "reqwest-eventsource" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632c55746dbb44275691640e7b40c907c16a2dc1a5842aa98aaec90da6ec6bde" +dependencies = [ + "eventsource-stream", + "futures-core", + "futures-timer", + "mime", + "nom", + "pin-project-lite", + "reqwest", + "thiserror 1.0.69", +] + [[package]] name = "rhai" version = "1.20.0" @@ -4982,6 +5096,31 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.2.0", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -5039,6 +5178,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -5051,6 +5199,52 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "segment" version = "0.2.5" @@ -5788,10 +5982,21 @@ dependencies = [ ] [[package]] -name = "tokio-util" -version = "0.7.11" +name = "tokio-stream" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", diff --git a/crates/benchmarks/Cargo.toml b/crates/benchmarks/Cargo.toml index a2cddd554..a5b3a39e1 100644 --- a/crates/benchmarks/Cargo.toml +++ b/crates/benchmarks/Cargo.toml @@ -31,7 +31,7 @@ anyhow = "1.0.95" bytes = "1.9.0" convert_case = "0.6.0" flate2 = "1.0.35" -reqwest = { version = "0.12.12", features = ["blocking", "rustls-tls"], default-features = false } +reqwest = { version = "0.12.15", features = ["blocking", "rustls-tls"], default-features = false } [features] default = ["milli/all-tokenizations"] diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 27f2047ee..805394781 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -308,6 +308,9 @@ pub enum Action { #[serde(rename = "network.update")] #[deserr(rename = "network.update")] NetworkUpdate, + #[serde(rename = "chat.get")] + #[deserr(rename = "chat.get")] + ChatGet, } impl Action { @@ -349,6 +352,7 @@ impl Action { EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), NETWORK_GET => Some(Self::NetworkGet), NETWORK_UPDATE => Some(Self::NetworkUpdate), + CHAT_GET => Some(Self::ChatGet), _otherwise => None, } } @@ -397,4 +401,6 @@ pub mod actions { pub const NETWORK_GET: u8 = NetworkGet.repr(); pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); + + pub const CHAT_GET: u8 = ChatGet.repr(); } diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index 40c0d98b5..ff6e5ceeb 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -111,6 +111,7 @@ utoipa = { version = "5.3.1", features = [ "openapi_extensions", ] } utoipa-scalar = { version = "0.3.0", optional = true, features = ["actix-web"] } +async-openai = "0.28.1" [dev-dependencies] actix-rt = "2.10.0" diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs new file mode 100644 index 000000000..1cb813acd --- /dev/null +++ b/crates/meilisearch/src/routes/chat.rs @@ -0,0 +1,32 @@ +use actix_web::web::{self, Data}; +use actix_web::HttpResponse; +use async_openai::config::OpenAIConfig; +use async_openai::types::CreateChatCompletionRequest; +use async_openai::Client; +use index_scheduler::IndexScheduler; +use meilisearch_types::error::ResponseError; +use meilisearch_types::keys::actions; + +use crate::extractors::authentication::policies::ActionPolicy; +use crate::extractors::authentication::GuardedData; + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.service(web::resource("").route(web::post().to(chat))); +} + +/// Get a chat completion +async fn chat( + _index_scheduler: GuardedData, Data>, + web::Json(chat_completion): web::Json, +) -> Result { + // To enable later on, when the feature will be experimental + // index_scheduler.features().check_chat("Using the /chat route")?; + + let api_key = std::env::var("MEILI_OPENAI_API_KEY") + .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); + let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base + let client = Client::with_config(config); + let response = client.chat().create(chat_completion).await.unwrap(); + + Ok(HttpResponse::Ok().json(response)) +} diff --git a/crates/meilisearch/src/routes/mod.rs b/crates/meilisearch/src/routes/mod.rs index 2c71fa68b..602fb6b40 100644 --- a/crates/meilisearch/src/routes/mod.rs +++ b/crates/meilisearch/src/routes/mod.rs @@ -52,6 +52,7 @@ const PAGINATION_DEFAULT_LIMIT_FN: fn() -> usize = || 20; mod api_key; pub mod batches; +pub mod chat; mod dump; pub mod features; pub mod indexes; @@ -113,7 +114,8 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service(web::scope("/swap-indexes").configure(swap_indexes::configure)) .service(web::scope("/metrics").configure(metrics::configure)) .service(web::scope("/experimental-features").configure(features::configure)) - .service(web::scope("/network").configure(network::configure)); + .service(web::scope("/network").configure(network::configure)) + .service(web::scope("/chat").configure(chat::configure)); #[cfg(feature = "swagger")] { From 951be6706008de597f58f9e8000ff54640f566b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 13 May 2025 15:26:24 +0200 Subject: [PATCH 118/292] Support querying the index named main --- Cargo.lock | 1 + crates/meilisearch/Cargo.toml | 1 + crates/meilisearch/src/routes/chat.rs | 209 +++++++++++++++++++++++++- 3 files changed, 207 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd314a025..c205bbb3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3620,6 +3620,7 @@ dependencies = [ "itertools 0.14.0", "jsonwebtoken", "lazy_static", + "liquid", "manifest-dir-macros", "maplit", "meili-snap", diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index ff6e5ceeb..a0ce49193 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -48,6 +48,7 @@ is-terminal = "0.4.13" itertools = "0.14.0" jsonwebtoken = "9.3.0" lazy_static = "1.5.0" +liquid = "0.26.9" meilisearch-auth = { path = "../meilisearch-auth" } meilisearch-types = { path = "../meilisearch-types" } mimalloc = { version = "0.1.43", default-features = false } diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 1cb813acd..335d5bf43 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -1,14 +1,48 @@ +use std::mem; + use actix_web::web::{self, Data}; use actix_web::HttpResponse; use async_openai::config::OpenAIConfig; -use async_openai::types::CreateChatCompletionRequest; +use async_openai::types::{ + ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, + ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, + ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, FinishReason, + FunctionObjectArgs, +}; use async_openai::Client; use index_scheduler::IndexScheduler; use meilisearch_types::error::ResponseError; use meilisearch_types::keys::actions; +use meilisearch_types::milli::index::IndexEmbeddingConfig; +use meilisearch_types::milli::prompt::PromptData; +use meilisearch_types::milli::vector::EmbeddingConfig; +use meilisearch_types::{Document, Index}; +use serde::Deserialize; +use serde_json::json; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; +use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; +use crate::routes::indexes::search::search_kind; +use crate::search::{ + add_search_rules, perform_search, HybridQuery, RetrieveVectors, SearchQuery, SemanticRatio, +}; +use crate::search_queue::SearchQueue; + +/// The default description of the searchInIndex tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION: &str = + "Search the database for relevant JSON documents using an optional query."; +/// The default description of the searchInIndex `q` parameter tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION: &str = + "The search query string used to find relevant documents in the index. \ +This should contain keywords or phrases that best represent what the user is looking for. \ +More specific queries will yield more precise results."; +/// The default description of the searchInIndex `index` parameter tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION: &str = +"The name of the index to search within. An index is a collection of documents organized for search. \ +Selecting the right index ensures the most relevant results for the user query"; + +const EMBEDDER_NAME: &str = "openai"; pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("").route(web::post().to(chat))); @@ -16,8 +50,9 @@ pub fn configure(cfg: &mut web::ServiceConfig) { /// Get a chat completion async fn chat( - _index_scheduler: GuardedData, Data>, - web::Json(chat_completion): web::Json, + index_scheduler: GuardedData, Data>, + search_queue: web::Data, + web::Json(mut chat_completion): web::Json, ) -> Result { // To enable later on, when the feature will be experimental // index_scheduler.features().check_chat("Using the /chat route")?; @@ -26,7 +61,173 @@ async fn chat( .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base let client = Client::with_config(config); - let response = client.chat().create(chat_completion).await.unwrap(); + + assert_eq!( + chat_completion.n.unwrap_or(1), + 1, + "Meilisearch /chat only support one completion at a time (n = 1, n = null)" + ); + + let mut response; + loop { + let mut tools = chat_completion.tools.get_or_insert_default(); + tools.push(ChatCompletionToolArgs::default() + .r#type(ChatCompletionToolType::Function) + .function(FunctionObjectArgs::default() + .name("searchInIndex") + .description(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) + .parameters(json!({ + "type": "object", + "properties": { + "index_uid": { + "type": "string", + "enum": ["main"], + "description": DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION, + }, + "q": { + "type": ["string", "null"], + "description": DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION, + } + }, + "required": ["index_uid", "q"], + "additionalProperties": false, + })) + .strict(true) + .build() + .unwrap(), + ) + .build() + .unwrap() + ); + response = dbg!(client.chat().create(chat_completion.clone()).await.unwrap()); + + let choice = &mut response.choices[0]; + match choice.finish_reason { + Some(FinishReason::ToolCalls) => { + let tool_calls = mem::take(&mut choice.message.tool_calls).unwrap_or_default(); + + let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + tool_calls.into_iter().partition(|call| call.function.name == "searchInIndex"); + + chat_completion.messages.push( + ChatCompletionRequestAssistantMessageArgs::default() + .tool_calls(meili_calls.clone()) + .build() + .unwrap() + .into(), + ); + + for call in meili_calls { + let SearchInIndexParameters { index_uid, q } = + serde_json::from_str(dbg!(&call.function.arguments)).unwrap(); + + let mut query = SearchQuery { + q, + hybrid: Some(HybridQuery { + semantic_ratio: SemanticRatio::default(), + embedder: EMBEDDER_NAME.to_string(), + }), + ..Default::default() + }; + + // Tenant token search_rules. + if let Some(search_rules) = + index_scheduler.filters().get_index_search_rules(&index_uid) + { + add_search_rules(&mut query.filter, search_rules); + } + + // TBD + // let mut aggregate = SearchAggregator::::from_query(&query); + + let index = index_scheduler.index(&index_uid)?; + let search_kind = search_kind( + &query, + index_scheduler.get_ref(), + index_uid.to_string(), + &index, + )?; + + let permit = search_queue.try_get_search_permit().await?; + let features = index_scheduler.features(); + let index_cloned = index.clone(); + let search_result = tokio::task::spawn_blocking(move || { + perform_search( + index_uid.to_string(), + &index_cloned, + query, + search_kind, + RetrieveVectors::new(false), + features, + ) + }) + .await; + permit.drop().await; + + let search_result = search_result?; + if let Ok(ref search_result) = search_result { + // aggregate.succeed(search_result); + if search_result.degraded { + MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); + } + } + // analytics.publish(aggregate, &req); + + let search_result = search_result?; + let formatted = format_documents( + &index, + search_result.hits.into_iter().map(|doc| doc.document), + ); + let text = formatted.join("\n"); + chat_completion.messages.push(ChatCompletionRequestMessage::Tool( + ChatCompletionRequestToolMessage { + tool_call_id: call.id, + content: ChatCompletionRequestToolMessageContent::Text(text), + }, + )); + } + + // Let the client call other tools by themselves + if !other_calls.is_empty() { + response.choices[0].message.tool_calls = Some(other_calls); + break; + } + } + _ => break, + } + } Ok(HttpResponse::Ok().json(response)) } + +#[derive(Deserialize)] +struct SearchInIndexParameters { + /// The index uid to search in. + index_uid: String, + /// The query parameter to use. + q: Option, +} + +fn format_documents(index: &Index, documents: impl Iterator) -> Vec { + let rtxn = index.read_txn().unwrap(); + let IndexEmbeddingConfig { name: _, config, user_provided: _ } = index + .embedding_configs(&rtxn) + .unwrap() + .into_iter() + .find(|conf| conf.name == EMBEDDER_NAME) + .unwrap(); + + let EmbeddingConfig { + embedder_options: _, + prompt: PromptData { template, max_bytes }, + quantized: _, + } = config; + + let template = liquid::ParserBuilder::with_stdlib().build().unwrap().parse(&template).unwrap(); + documents + .map(|doc| { + let object = liquid::to_object(&doc).unwrap(); + template.render(&object).unwrap() + }) + .collect() +} From 82fa70da83ced99932ad8b03f3b9596c554852f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 13 May 2025 16:33:58 +0200 Subject: [PATCH 119/292] Support overwriten prompts of the search query --- crates/index-scheduler/src/lib.rs | 20 +++++++++++++++++--- crates/meilisearch/src/routes/chat.rs | 20 +++++++++++++++++++- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 6ff274da7..11572cd06 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -53,8 +53,8 @@ use flate2::Compression; use meilisearch_types::batches::Batch; use meilisearch_types::features::{InstanceTogglableFeatures, Network, RuntimeTogglableFeatures}; use meilisearch_types::heed::byteorder::BE; -use meilisearch_types::heed::types::I128; -use meilisearch_types::heed::{self, Env, RoTxn, WithoutTls}; +use meilisearch_types::heed::types::{Str, I128}; +use meilisearch_types::heed::{self, Database, Env, RoTxn, WithoutTls}; use meilisearch_types::milli::index::IndexEmbeddingConfig; use meilisearch_types::milli::update::IndexerConfig; use meilisearch_types::milli::vector::{Embedder, EmbedderOptions, EmbeddingConfigs}; @@ -153,6 +153,9 @@ pub struct IndexScheduler { /// In charge of fetching and setting the status of experimental features. features: features::FeatureData, + /// Stores the custom prompts for the chat + chat_prompts: Database, + /// Everything related to the processing of the tasks pub scheduler: scheduler::Scheduler, @@ -211,11 +214,16 @@ impl IndexScheduler { #[cfg(test)] run_loop_iteration: self.run_loop_iteration.clone(), features: self.features.clone(), + chat_prompts: self.chat_prompts.clone(), } } pub(crate) const fn nb_db() -> u32 { - Versioning::nb_db() + Queue::nb_db() + IndexMapper::nb_db() + features::FeatureData::nb_db() + Versioning::nb_db() + + Queue::nb_db() + + IndexMapper::nb_db() + + features::FeatureData::nb_db() + + 1 // chat-prompts } /// Create an index scheduler and start its run loop. @@ -269,6 +277,7 @@ impl IndexScheduler { let features = features::FeatureData::new(&env, &mut wtxn, options.instance_features)?; let queue = Queue::new(&env, &mut wtxn, &options)?; let index_mapper = IndexMapper::new(&env, &mut wtxn, &options, budget)?; + let chat_prompts = env.create_database(&mut wtxn, Some("chat-prompts"))?; wtxn.commit()?; // allow unreachable_code to get rids of the warning in the case of a test build. @@ -292,6 +301,7 @@ impl IndexScheduler { #[cfg(test)] run_loop_iteration: Arc::new(RwLock::new(0)), features, + chat_prompts, }; this.run(); @@ -864,6 +874,10 @@ impl IndexScheduler { .collect(); res.map(EmbeddingConfigs::new) } + + pub fn chat_prompts<'t>(&self, rtxn: &'t RoTxn, name: &str) -> heed::Result> { + self.chat_prompts.get(rtxn, name) + } } /// The outcome of calling the [`IndexScheduler::tick`] function. diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 335d5bf43..3e5bf6957 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -17,7 +17,7 @@ use meilisearch_types::milli::index::IndexEmbeddingConfig; use meilisearch_types::milli::prompt::PromptData; use meilisearch_types::milli::vector::EmbeddingConfig; use meilisearch_types::{Document, Index}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use serde_json::json; use crate::extractors::authentication::policies::ActionPolicy; @@ -68,6 +68,24 @@ async fn chat( "Meilisearch /chat only support one completion at a time (n = 1, n = null)" ); + let rtxn = index_scheduler.read_txn().unwrap(); + let search_in_index_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) + .to_string(); + let search_in_index_q_param_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-q-param-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION) + .to_string(); + let search_in_index_index_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-index-param-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION) + .to_string(); + drop(rtxn); + let mut response; loop { let mut tools = chat_completion.tools.get_or_insert_default(); From 2cd85c732a1d0981eb446663d20a208f817e4f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 13 May 2025 16:35:46 +0200 Subject: [PATCH 120/292] Make it work by retrieving content from the index --- crates/meilisearch/src/routes/chat.rs | 64 +++++++++++++++------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 3e5bf6957..8f0552561 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -88,34 +88,36 @@ async fn chat( let mut response; loop { - let mut tools = chat_completion.tools.get_or_insert_default(); - tools.push(ChatCompletionToolArgs::default() - .r#type(ChatCompletionToolType::Function) - .function(FunctionObjectArgs::default() - .name("searchInIndex") - .description(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) - .parameters(json!({ - "type": "object", - "properties": { - "index_uid": { - "type": "string", - "enum": ["main"], - "description": DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION, - }, - "q": { - "type": ["string", "null"], - "description": DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION, - } - }, - "required": ["index_uid", "q"], - "additionalProperties": false, - })) - .strict(true) + let tools = chat_completion.tools.get_or_insert_default(); + tools.push( + ChatCompletionToolArgs::default() + .r#type(ChatCompletionToolType::Function) + .function( + FunctionObjectArgs::default() + .name("searchInIndex") + .description(&search_in_index_description) + .parameters(json!({ + "type": "object", + "properties": { + "index_uid": { + "type": "string", + "enum": ["main"], + "description": search_in_index_index_description, + }, + "q": { + "type": ["string", "null"], + "description": search_in_index_q_param_description, + } + }, + "required": ["index_uid", "q"], + "additionalProperties": false, + })) + .strict(true) + .build() + .unwrap(), + ) .build() .unwrap(), - ) - .build() - .unwrap() ); response = dbg!(client.chat().create(chat_completion.clone()).await.unwrap()); @@ -137,7 +139,7 @@ async fn chat( for call in meili_calls { let SearchInIndexParameters { index_uid, q } = - serde_json::from_str(dbg!(&call.function.arguments)).unwrap(); + serde_json::from_str(&call.function.arguments).unwrap(); let mut query = SearchQuery { q, @@ -145,6 +147,7 @@ async fn chat( semantic_ratio: SemanticRatio::default(), embedder: EMBEDDER_NAME.to_string(), }), + limit: 20, ..Default::default() }; @@ -241,10 +244,15 @@ fn format_documents(index: &Index, documents: impl Iterator) -> quantized: _, } = config; + #[derive(Serialize)] + struct Doc { + doc: T, + } + let template = liquid::ParserBuilder::with_stdlib().build().unwrap().parse(&template).unwrap(); documents .map(|doc| { - let object = liquid::to_object(&doc).unwrap(); + let object = liquid::to_object(&Doc { doc }).unwrap(); template.render(&object).unwrap() }) .collect() From 0f05c0eb6fbae67a2555a9f04c90b3e5fe5c2b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 14 May 2025 11:18:21 +0200 Subject: [PATCH 121/292] Implement a first version of a streamed chat API --- Cargo.lock | 158 +++++++++++++++++++++++--- crates/meilisearch/Cargo.toml | 1 + crates/meilisearch/src/routes/chat.rs | 38 ++++++- 3 files changed, 180 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c205bbb3d..6ce6b5186 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" dependencies = [ "actix-utils", "actix-web", - "derive_more", + "derive_more 0.99.17", "futures-util", "log", "once_cell", @@ -36,24 +36,24 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" +checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-tls", "actix-utils", - "ahash 0.8.11", "base64 0.22.1", "bitflags 2.9.0", - "brotli", + "brotli 8.0.1", "bytes", "bytestring", - "derive_more", + "derive_more 2.0.1", "encoding_rs", "flate2", + "foldhash", "futures-core", "h2 0.3.26", "http 0.2.11", @@ -65,7 +65,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.8.5", + "rand 0.9.1", "sha1", "smallvec", "tokio", @@ -92,6 +92,7 @@ dependencies = [ "bytestring", "cfg-if", "http 0.2.11", + "regex", "regex-lite", "serde", "tracing", @@ -187,7 +188,7 @@ dependencies = [ "bytestring", "cfg-if", "cookie", - "derive_more", + "derive_more 0.99.17", "encoding_rs", "futures-core", "futures-util", @@ -220,6 +221,43 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "actix-web-lab" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33034dd88446a5deb20e42156dbfe43d07e0499345db3ae65b3f51854190531" +dependencies = [ + "actix-http", + "actix-router", + "actix-service", + "actix-utils", + "actix-web", + "ahash 0.8.11", + "arc-swap", + "bytes", + "bytestring", + "csv", + "derive_more 2.0.1", + "form_urlencoded", + "futures-core", + "futures-util", + "http 0.2.11", + "impl-more", + "itertools 0.14.0", + "local-channel", + "mime", + "pin-project-lite", + "regex", + "serde", + "serde_html_form", + "serde_json", + "serde_path_to_error", + "tokio", + "tokio-stream", + "tracing", + "url", +] + [[package]] name = "addr2line" version = "0.20.0" @@ -391,6 +429,12 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.7.4" @@ -556,7 +600,7 @@ dependencies = [ "milli", "mimalloc", "rand 0.8.5", - "rand_chacha", + "rand_chacha 0.3.1", "reqwest", "roaring", "serde_json", @@ -708,7 +752,18 @@ checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor", + "brotli-decompressor 4.0.1", +] + +[[package]] +name = "brotli" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 5.0.0", ] [[package]] @@ -721,6 +776,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bstr" version = "1.11.3" @@ -1634,6 +1699,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "unicode-xid", +] + [[package]] name = "deserr" version = "0.6.3" @@ -2847,9 +2933,9 @@ dependencies = [ [[package]] name = "impl-more" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "include-flate" @@ -3593,10 +3679,11 @@ dependencies = [ "actix-rt", "actix-utils", "actix-web", + "actix-web-lab", "anyhow", "async-openai", "async-trait", - "brotli", + "brotli 6.0.0", "bstr", "build-info", "byte-unit", @@ -4688,7 +4775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", + "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -4698,6 +4785,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ + "rand_chacha 0.9.0", "rand_core 0.9.3", ] @@ -4711,6 +4799,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -4725,6 +4823,9 @@ name = "rand_core" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] [[package]] name = "rand_distr" @@ -5304,6 +5405,19 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "serde_html_form" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" +dependencies = [ + "form_urlencoded", + "indexmap", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_json" version = "1.0.140" @@ -5317,6 +5431,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_plain" version = "1.0.2" @@ -6320,6 +6444,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "unicode_categories" version = "0.1.1" diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index a0ce49193..f7469e7ac 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -113,6 +113,7 @@ utoipa = { version = "5.3.1", features = [ ] } utoipa-scalar = { version = "0.3.0", optional = true, features = ["actix-web"] } async-openai = "0.28.1" +actix-web-lab = { version = "0.24.1", default-features = false } [dev-dependencies] actix-rt = "2.10.0" diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 8f0552561..ad46d91c8 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -1,7 +1,8 @@ use std::mem; use actix_web::web::{self, Data}; -use actix_web::HttpResponse; +use actix_web::{Either, HttpResponse, Responder}; +use actix_web_lab::sse::{self, Event}; use async_openai::config::OpenAIConfig; use async_openai::types::{ ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, @@ -10,6 +11,7 @@ use async_openai::types::{ FunctionObjectArgs, }; use async_openai::Client; +use futures::StreamExt; use index_scheduler::IndexScheduler; use meilisearch_types::error::ResponseError; use meilisearch_types::keys::actions; @@ -53,10 +55,22 @@ async fn chat( index_scheduler: GuardedData, Data>, search_queue: web::Data, web::Json(mut chat_completion): web::Json, -) -> Result { +) -> impl Responder { // To enable later on, when the feature will be experimental // index_scheduler.features().check_chat("Using the /chat route")?; + if chat_completion.stream.unwrap_or(false) { + Either::Right(streamed_chat(index_scheduler, search_queue, chat_completion).await) + } else { + Either::Left(non_streamed_chat(index_scheduler, search_queue, chat_completion).await) + } +} + +async fn non_streamed_chat( + index_scheduler: GuardedData, Data>, + search_queue: web::Data, + mut chat_completion: CreateChatCompletionRequest, +) -> Result { let api_key = std::env::var("MEILI_OPENAI_API_KEY") .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base @@ -119,7 +133,7 @@ async fn chat( .build() .unwrap(), ); - response = dbg!(client.chat().create(chat_completion.clone()).await.unwrap()); + response = client.chat().create(chat_completion.clone()).await.unwrap(); let choice = &mut response.choices[0]; match choice.finish_reason { @@ -221,6 +235,24 @@ async fn chat( Ok(HttpResponse::Ok().json(response)) } +async fn streamed_chat( + index_scheduler: GuardedData, Data>, + search_queue: web::Data, + mut chat_completion: CreateChatCompletionRequest, +) -> impl Responder { + assert!(chat_completion.stream.unwrap_or(false)); + + let api_key = std::env::var("MEILI_OPENAI_API_KEY") + .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); + let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base + let client = Client::with_config(config); + let response = client.chat().create_stream(chat_completion).await.unwrap(); + actix_web_lab::sse::Sse::from_stream(response.map(|response| { + response + .map(|mut r| Event::Data(sse::Data::new_json(r.choices.pop().unwrap().delta).unwrap())) + })) +} + #[derive(Deserialize)] struct SearchInIndexParameters { /// The index uid to search in. From d4a16f23496b270c22aaefbb71d054ed93f1d6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 14 May 2025 11:53:03 +0200 Subject: [PATCH 122/292] Aggregate tool calls and display the calls to make. --- crates/meilisearch/src/routes/chat.rs | 127 +++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 14 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index ad46d91c8..4c9c9934b 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::mem; use actix_web::web::{self, Data}; @@ -5,10 +6,11 @@ use actix_web::{Either, HttpResponse, Responder}; use actix_web_lab::sse::{self, Event}; use async_openai::config::OpenAIConfig; use async_openai::types::{ - ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, - ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, + ChatCompletionMessageToolCallChunk, ChatCompletionRequestAssistantMessageArgs, + ChatCompletionRequestMessage, ChatCompletionRequestToolMessage, + ChatCompletionRequestToolMessageContent, ChatCompletionStreamResponseDelta, ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, FinishReason, - FunctionObjectArgs, + FunctionCallStream, FunctionObjectArgs, }; use async_openai::Client; use futures::StreamExt; @@ -59,6 +61,12 @@ async fn chat( // To enable later on, when the feature will be experimental // index_scheduler.features().check_chat("Using the /chat route")?; + assert_eq!( + chat_completion.n.unwrap_or(1), + 1, + "Meilisearch /chat only support one completion at a time (n = 1, n = null)" + ); + if chat_completion.stream.unwrap_or(false) { Either::Right(streamed_chat(index_scheduler, search_queue, chat_completion).await) } else { @@ -76,12 +84,6 @@ async fn non_streamed_chat( let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base let client = Client::with_config(config); - assert_eq!( - chat_completion.n.unwrap_or(1), - 1, - "Meilisearch /chat only support one completion at a time (n = 1, n = null)" - ); - let rtxn = index_scheduler.read_txn().unwrap(); let search_in_index_description = index_scheduler .chat_prompts(&rtxn, "searchInIndex-description") @@ -240,19 +242,116 @@ async fn streamed_chat( search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> impl Responder { - assert!(chat_completion.stream.unwrap_or(false)); - let api_key = std::env::var("MEILI_OPENAI_API_KEY") .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); + + let rtxn = index_scheduler.read_txn().unwrap(); + let search_in_index_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) + .to_string(); + let search_in_index_q_param_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-q-param-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION) + .to_string(); + let search_in_index_index_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-index-param-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION) + .to_string(); + drop(rtxn); + + let tools = chat_completion.tools.get_or_insert_default(); + tools.push( + ChatCompletionToolArgs::default() + .r#type(ChatCompletionToolType::Function) + .function( + FunctionObjectArgs::default() + .name("searchInIndex") + .description(&search_in_index_description) + .parameters(json!({ + "type": "object", + "properties": { + "index_uid": { + "type": "string", + "enum": ["main"], + "description": search_in_index_index_description, + }, + "q": { + "type": ["string", "null"], + "description": search_in_index_q_param_description, + } + }, + "required": ["index_uid", "q"], + "additionalProperties": false, + })) + .strict(true) + .build() + .unwrap(), + ) + .build() + .unwrap(), + ); + let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base let client = Client::with_config(config); let response = client.chat().create_stream(chat_completion).await.unwrap(); - actix_web_lab::sse::Sse::from_stream(response.map(|response| { - response - .map(|mut r| Event::Data(sse::Data::new_json(r.choices.pop().unwrap().delta).unwrap())) + let mut global_tool_calls = HashMap::::new(); + actix_web_lab::sse::Sse::from_stream(response.map(move |response| { + response.map(|mut r| { + let delta = r.choices.pop().unwrap().delta; + let ChatCompletionStreamResponseDelta { + ref content, + ref function_call, + ref tool_calls, + ref role, + ref refusal, + } = delta; + + match tool_calls { + Some(tool_calls) => { + for chunk in tool_calls { + let ChatCompletionMessageToolCallChunk { index, id, r#type, function } = + chunk; + let FunctionCallStream { ref name, ref arguments } = + function.as_ref().unwrap(); + global_tool_calls + .entry(*index) + .or_insert_with(|| Call { + id: id.as_ref().unwrap().clone(), + function_name: name.as_ref().unwrap().clone(), + arguments: arguments.as_ref().unwrap().clone(), + }) + .append(arguments.as_ref().unwrap()); + } + } + None if !global_tool_calls.is_empty() => { + dbg!(&global_tool_calls); + } + _ => (), + } + + Event::Data(sse::Data::new_json(delta).unwrap()) + }) })) } +/// The structure used to aggregate the function calls to make. +#[derive(Debug)] +struct Call { + id: String, + function_name: String, + arguments: String, +} + +impl Call { + fn append(&mut self, arguments: &str) { + self.arguments.push_str(arguments); + } +} + #[derive(Deserialize)] struct SearchInIndexParameters { /// The index uid to search in. From 12355239188b9d2a6fd777f287736fc93536cb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 14 May 2025 12:03:43 +0200 Subject: [PATCH 123/292] Return the right message format --- crates/meilisearch/src/routes/chat.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 4c9c9934b..70d565b99 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -301,7 +301,7 @@ async fn streamed_chat( let mut global_tool_calls = HashMap::::new(); actix_web_lab::sse::Sse::from_stream(response.map(move |response| { response.map(|mut r| { - let delta = r.choices.pop().unwrap().delta; + let delta = &r.choices[0].delta; let ChatCompletionStreamResponseDelta { ref content, ref function_call, @@ -330,10 +330,10 @@ async fn streamed_chat( None if !global_tool_calls.is_empty() => { dbg!(&global_tool_calls); } - _ => (), + None => (), } - Event::Data(sse::Data::new_json(delta).unwrap()) + Event::Data(sse::Data::new_json(r).unwrap()) }) })) } From 5fab2aee512a9fecb9fd3a3d4d12a45cf35d16bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 14 May 2025 14:29:41 +0200 Subject: [PATCH 124/292] Nearly support tools on the streaming route --- crates/meilisearch/src/routes/chat.rs | 149 ++++++++++++++++++++++---- 1 file changed, 128 insertions(+), 21 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 70d565b99..207feb256 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -6,14 +6,16 @@ use actix_web::{Either, HttpResponse, Responder}; use actix_web_lab::sse::{self, Event}; use async_openai::config::OpenAIConfig; use async_openai::types::{ - ChatCompletionMessageToolCallChunk, ChatCompletionRequestAssistantMessageArgs, - ChatCompletionRequestMessage, ChatCompletionRequestToolMessage, - ChatCompletionRequestToolMessageContent, ChatCompletionStreamResponseDelta, - ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, FinishReason, - FunctionCallStream, FunctionObjectArgs, + ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, + ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, + ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, + ChatCompletionStreamResponseDelta, ChatCompletionToolArgs, ChatCompletionToolType, + CreateChatCompletionRequest, FinishReason, FunctionCall, FunctionCallStream, + FunctionObjectArgs, }; use async_openai::Client; use futures::StreamExt; +use futures_util::stream; use index_scheduler::IndexScheduler; use meilisearch_types::error::ResponseError; use meilisearch_types::keys::actions; @@ -23,6 +25,7 @@ use meilisearch_types::milli::vector::EmbeddingConfig; use meilisearch_types::{Document, Index}; use serde::{Deserialize, Serialize}; use serde_json::json; +use tokio::runtime::Handle; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; @@ -297,26 +300,25 @@ async fn streamed_chat( let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base let client = Client::with_config(config); - let response = client.chat().create_stream(chat_completion).await.unwrap(); + let response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); let mut global_tool_calls = HashMap::::new(); - actix_web_lab::sse::Sse::from_stream(response.map(move |response| { - response.map(|mut r| { - let delta = &r.choices[0].delta; + actix_web_lab::sse::Sse::from_stream(response.flat_map(move |response| match response { + Ok(resp) => { + let delta = &resp.choices[0].delta; let ChatCompletionStreamResponseDelta { - ref content, - ref function_call, + content: _, + function_call: _, ref tool_calls, - ref role, - ref refusal, + role: _, + refusal: _, } = delta; match tool_calls { Some(tool_calls) => { for chunk in tool_calls { - let ChatCompletionMessageToolCallChunk { index, id, r#type, function } = + let ChatCompletionMessageToolCallChunk { index, id, r#type: _, function } = chunk; - let FunctionCallStream { ref name, ref arguments } = - function.as_ref().unwrap(); + let FunctionCallStream { name, arguments } = function.as_ref().unwrap(); global_tool_calls .entry(*index) .or_insert_with(|| Call { @@ -326,15 +328,120 @@ async fn streamed_chat( }) .append(arguments.as_ref().unwrap()); } + stream::iter(vec![Ok(Event::Data(sse::Data::new_json(resp).unwrap()))]) } None if !global_tool_calls.is_empty() => { dbg!(&global_tool_calls); - } - None => (), - } - Event::Data(sse::Data::new_json(r).unwrap()) - }) + let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + mem::take(&mut global_tool_calls) + .into_iter() + .map(|(_, call)| ChatCompletionMessageToolCall { + id: call.id, + r#type: ChatCompletionToolType::Function, + function: FunctionCall { + name: call.function_name, + arguments: call.arguments, + }, + }) + .partition(|call| call.function.name == "searchInIndex"); + + chat_completion.messages.push( + ChatCompletionRequestAssistantMessageArgs::default() + .tool_calls(meili_calls.clone()) + .build() + .unwrap() + .into(), + ); + + for call in meili_calls { + let SearchInIndexParameters { index_uid, q } = + serde_json::from_str(&call.function.arguments).unwrap(); + + let mut query = SearchQuery { + q, + hybrid: Some(HybridQuery { + semantic_ratio: SemanticRatio::default(), + embedder: EMBEDDER_NAME.to_string(), + }), + limit: 20, + ..Default::default() + }; + + // Tenant token search_rules. + if let Some(search_rules) = + index_scheduler.filters().get_index_search_rules(&index_uid) + { + add_search_rules(&mut query.filter, search_rules); + } + + // TBD + // let mut aggregate = SearchAggregator::::from_query(&query); + + let index = index_scheduler.index(&index_uid).unwrap(); + let search_kind = search_kind( + &query, + index_scheduler.get_ref(), + index_uid.to_string(), + &index, + ) + .unwrap(); + + // let permit = search_queue.try_get_search_permit().await?; + let features = index_scheduler.features(); + let index_cloned = index.clone(); + // let search_result = tokio::task::spawn_blocking(move || { + let search_result = perform_search( + index_uid.to_string(), + &index_cloned, + query, + search_kind, + RetrieveVectors::new(false), + features, + ); + // }) + // .await; + // permit.drop().await; + + // let search_result = search_result.unwrap(); + if let Ok(ref search_result) = search_result { + // aggregate.succeed(search_result); + if search_result.degraded { + MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); + } + } + // analytics.publish(aggregate, &req); + + let search_result = search_result.unwrap(); + let formatted = format_documents( + &index, + search_result.hits.into_iter().map(|doc| doc.document), + ); + let text = formatted.join("\n"); + chat_completion.messages.push(ChatCompletionRequestMessage::Tool( + ChatCompletionRequestToolMessage { + tool_call_id: call.id, + content: ChatCompletionRequestToolMessageContent::Text(text), + }, + )); + } + + let response = Handle::current().block_on(async { + client.chat().create_stream(chat_completion.clone()).await.unwrap() + }); + + // stream::iter(vec![ + // Ok(Event::Data(sse::Data::new_json(json!({ "text": "Hello" })).unwrap())), + // Ok(Event::Data(sse::Data::new_json(json!({ "text": " world" })).unwrap())), + // Ok(Event::Data(sse::Data::new_json(json!({ "text": " !" })).unwrap())), + // ]) + + response + } + None => stream::iter(vec![Ok(Event::Data(sse::Data::new_json(resp).unwrap()))]), + } + } + Err(err) => stream::iter(vec![Err(err)]), })) } From aef8448fc62bb1e6905055d19cb451a971da20a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 14 May 2025 14:58:01 +0200 Subject: [PATCH 125/292] Streaming supports tool calling --- crates/meilisearch/src/routes/chat.rs | 293 ++++++++++++++------------ 1 file changed, 158 insertions(+), 135 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 207feb256..d2def9488 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; use std::mem; +use std::time::Duration; use actix_web::web::{self, Data}; use actix_web::{Either, HttpResponse, Responder}; -use actix_web_lab::sse::{self, Event}; +use actix_web_lab::sse::{self, Event, Sse}; use async_openai::config::OpenAIConfig; use async_openai::types::{ ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, @@ -15,7 +16,6 @@ use async_openai::types::{ }; use async_openai::Client; use futures::StreamExt; -use futures_util::stream; use index_scheduler::IndexScheduler; use meilisearch_types::error::ResponseError; use meilisearch_types::keys::actions; @@ -59,7 +59,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { async fn chat( index_scheduler: GuardedData, Data>, search_queue: web::Data, - web::Json(mut chat_completion): web::Json, + web::Json(chat_completion): web::Json, ) -> impl Responder { // To enable later on, when the feature will be experimental // index_scheduler.features().check_chat("Using the /chat route")?; @@ -298,151 +298,174 @@ async fn streamed_chat( .unwrap(), ); - let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base - let client = Client::with_config(config); - let response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); - let mut global_tool_calls = HashMap::::new(); - actix_web_lab::sse::Sse::from_stream(response.flat_map(move |response| match response { - Ok(resp) => { - let delta = &resp.choices[0].delta; - let ChatCompletionStreamResponseDelta { - content: _, - function_call: _, - ref tool_calls, - role: _, - refusal: _, - } = delta; + let (tx, rx) = tokio::sync::mpsc::channel(10); + let _join_handle = Handle::current().spawn(async move { + let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base + let client = Client::with_config(config); + let mut global_tool_calls = HashMap::::new(); - match tool_calls { - Some(tool_calls) => { - for chunk in tool_calls { - let ChatCompletionMessageToolCallChunk { index, id, r#type: _, function } = - chunk; - let FunctionCallStream { name, arguments } = function.as_ref().unwrap(); - global_tool_calls - .entry(*index) - .or_insert_with(|| Call { - id: id.as_ref().unwrap().clone(), - function_name: name.as_ref().unwrap().clone(), - arguments: arguments.as_ref().unwrap().clone(), - }) - .append(arguments.as_ref().unwrap()); - } - stream::iter(vec![Ok(Event::Data(sse::Data::new_json(resp).unwrap()))]) - } - None if !global_tool_calls.is_empty() => { - dbg!(&global_tool_calls); + 'main: loop { + let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); - let (meili_calls, other_calls): (Vec<_>, Vec<_>) = - mem::take(&mut global_tool_calls) - .into_iter() - .map(|(_, call)| ChatCompletionMessageToolCall { - id: call.id, - r#type: ChatCompletionToolType::Function, - function: FunctionCall { - name: call.function_name, - arguments: call.arguments, - }, - }) - .partition(|call| call.function.name == "searchInIndex"); + while let Some(result) = response.next().await { + match result { + Ok(resp) => { + let delta = &resp.choices[0].delta; + let ChatCompletionStreamResponseDelta { + content, + function_call: _, + ref tool_calls, + role: _, + refusal: _, + } = delta; - chat_completion.messages.push( - ChatCompletionRequestAssistantMessageArgs::default() - .tool_calls(meili_calls.clone()) - .build() - .unwrap() - .into(), - ); - - for call in meili_calls { - let SearchInIndexParameters { index_uid, q } = - serde_json::from_str(&call.function.arguments).unwrap(); - - let mut query = SearchQuery { - q, - hybrid: Some(HybridQuery { - semantic_ratio: SemanticRatio::default(), - embedder: EMBEDDER_NAME.to_string(), - }), - limit: 20, - ..Default::default() - }; - - // Tenant token search_rules. - if let Some(search_rules) = - index_scheduler.filters().get_index_search_rules(&index_uid) + if content.is_none() && tool_calls.is_none() && global_tool_calls.is_empty() { - add_search_rules(&mut query.filter, search_rules); + break 'main; } - // TBD - // let mut aggregate = SearchAggregator::::from_query(&query); + if let Some(text) = content { + tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())).await.unwrap() + } - let index = index_scheduler.index(&index_uid).unwrap(); - let search_kind = search_kind( - &query, - index_scheduler.get_ref(), - index_uid.to_string(), - &index, - ) - .unwrap(); - - // let permit = search_queue.try_get_search_permit().await?; - let features = index_scheduler.features(); - let index_cloned = index.clone(); - // let search_result = tokio::task::spawn_blocking(move || { - let search_result = perform_search( - index_uid.to_string(), - &index_cloned, - query, - search_kind, - RetrieveVectors::new(false), - features, - ); - // }) - // .await; - // permit.drop().await; - - // let search_result = search_result.unwrap(); - if let Ok(ref search_result) = search_result { - // aggregate.succeed(search_result); - if search_result.degraded { - MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); + match tool_calls { + Some(tool_calls) => { + for chunk in tool_calls { + let ChatCompletionMessageToolCallChunk { + index, + id, + r#type: _, + function, + } = chunk; + let FunctionCallStream { name, arguments } = + function.as_ref().unwrap(); + global_tool_calls + .entry(*index) + .or_insert_with(|| Call { + id: id.as_ref().unwrap().clone(), + function_name: name.as_ref().unwrap().clone(), + arguments: arguments.as_ref().unwrap().clone(), + }) + .append(arguments.as_ref().unwrap()); + } + tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())) + .await + .unwrap() } + None if !global_tool_calls.is_empty() => { + // dbg!(&global_tool_calls); + + let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + mem::take(&mut global_tool_calls) + .into_iter() + .map(|(_, call)| ChatCompletionMessageToolCall { + id: call.id, + r#type: ChatCompletionToolType::Function, + function: FunctionCall { + name: call.function_name, + arguments: call.arguments, + }, + }) + .partition(|call| call.function.name == "searchInIndex"); + + chat_completion.messages.push( + ChatCompletionRequestAssistantMessageArgs::default() + .tool_calls(meili_calls.clone()) + .build() + .unwrap() + .into(), + ); + + for call in meili_calls { + let SearchInIndexParameters { index_uid, q } = + serde_json::from_str(&call.function.arguments).unwrap(); + + let mut query = SearchQuery { + q, + hybrid: Some(HybridQuery { + semantic_ratio: SemanticRatio::default(), + embedder: EMBEDDER_NAME.to_string(), + }), + limit: 20, + ..Default::default() + }; + + // Tenant token search_rules. + if let Some(search_rules) = + index_scheduler.filters().get_index_search_rules(&index_uid) + { + add_search_rules(&mut query.filter, search_rules); + } + + // TBD + // let mut aggregate = SearchAggregator::::from_query(&query); + + let index = index_scheduler.index(&index_uid).unwrap(); + let search_kind = search_kind( + &query, + index_scheduler.get_ref(), + index_uid.to_string(), + &index, + ) + .unwrap(); + + let permit = + search_queue.try_get_search_permit().await.unwrap(); + let features = index_scheduler.features(); + let index_cloned = index.clone(); + let search_result = tokio::task::spawn_blocking(move || { + perform_search( + index_uid.to_string(), + &index_cloned, + query, + search_kind, + RetrieveVectors::new(false), + features, + ) + }) + .await; + permit.drop().await; + + let search_result = search_result.unwrap(); + if let Ok(ref search_result) = search_result { + // aggregate.succeed(search_result); + if search_result.degraded { + MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); + } + } + // analytics.publish(aggregate, &req); + + let search_result = search_result.unwrap(); + let formatted = format_documents( + &index, + search_result.hits.into_iter().map(|doc| doc.document), + ); + let text = formatted.join("\n"); + chat_completion.messages.push( + ChatCompletionRequestMessage::Tool( + ChatCompletionRequestToolMessage { + tool_call_id: call.id, + content: + ChatCompletionRequestToolMessageContent::Text( + text, + ), + }, + ), + ); + } + } + None => (), } - // analytics.publish(aggregate, &req); - - let search_result = search_result.unwrap(); - let formatted = format_documents( - &index, - search_result.hits.into_iter().map(|doc| doc.document), - ); - let text = formatted.join("\n"); - chat_completion.messages.push(ChatCompletionRequestMessage::Tool( - ChatCompletionRequestToolMessage { - tool_call_id: call.id, - content: ChatCompletionRequestToolMessageContent::Text(text), - }, - )); } - - let response = Handle::current().block_on(async { - client.chat().create_stream(chat_completion.clone()).await.unwrap() - }); - - // stream::iter(vec![ - // Ok(Event::Data(sse::Data::new_json(json!({ "text": "Hello" })).unwrap())), - // Ok(Event::Data(sse::Data::new_json(json!({ "text": " world" })).unwrap())), - // Ok(Event::Data(sse::Data::new_json(json!({ "text": " !" })).unwrap())), - // ]) - - response + Err(_err) => { + // writeln!(lock, "error: {err}").unwrap(); + } } - None => stream::iter(vec![Ok(Event::Data(sse::Data::new_json(resp).unwrap()))]), } } - Err(err) => stream::iter(vec![Err(err)]), - })) + }); + + Sse::from_infallible_receiver(rx).with_retry_duration(Duration::from_secs(10)) } /// The structure used to aggregate the function calls to make. From 511eef87bf59a98e2ce6eaae52ebebd2352a6104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 14 May 2025 17:15:32 +0200 Subject: [PATCH 126/292] Send an event with the content of the tool calling --- crates/meilisearch/src/routes/chat.rs | 32 +++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index d2def9488..f340b3449 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -324,7 +324,7 @@ async fn streamed_chat( break 'main; } - if let Some(text) = content { + if let Some(_) = content { tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())).await.unwrap() } @@ -348,9 +348,6 @@ async fn streamed_chat( }) .append(arguments.as_ref().unwrap()); } - tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())) - .await - .unwrap() } None if !global_tool_calls.is_empty() => { // dbg!(&global_tool_calls); @@ -441,17 +438,24 @@ async fn streamed_chat( search_result.hits.into_iter().map(|doc| doc.document), ); let text = formatted.join("\n"); - chat_completion.messages.push( - ChatCompletionRequestMessage::Tool( - ChatCompletionRequestToolMessage { - tool_call_id: call.id, - content: - ChatCompletionRequestToolMessageContent::Text( - text, - ), - }, - ), + let tool = ChatCompletionRequestMessage::Tool( + ChatCompletionRequestToolMessage { + tool_call_id: call.id, + content: ChatCompletionRequestToolMessageContent::Text( + text, + ), + }, ); + tx.send(Event::Data( + sse::Data::new_json(&json!({ + "object": "chat.completion.tool.event", + "tool": tool, + })) + .unwrap(), + )) + .await + .unwrap(); + chat_completion.messages.push(tool); } } None => (), From 148816a3da0fdabaf4038a4b1d818700ba063d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 11:17:34 +0200 Subject: [PATCH 127/292] Display the different tool calls we need to do --- crates/meilisearch/src/routes/chat.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index f340b3449..8db6a1dde 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -374,6 +374,16 @@ async fn streamed_chat( ); for call in meili_calls { + tx.send(Event::Data( + sse::Data::new_json(&json!({ + "object": "chat.completion.tool.call", + "tool": call, + })) + .unwrap(), + )) + .await + .unwrap(); + let SearchInIndexParameters { index_uid, q } = serde_json::from_str(&call.function.arguments).unwrap(); @@ -448,7 +458,7 @@ async fn streamed_chat( ); tx.send(Event::Data( sse::Data::new_json(&json!({ - "object": "chat.completion.tool.event", + "object": "chat.completion.tool.output", "tool": tool, })) .unwrap(), From 77e03e3f8cf04b2281081339bb110b2564745acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 15:39:38 +0200 Subject: [PATCH 128/292] Factorise a bit the code --- crates/meilisearch/src/routes/chat.rs | 376 ++++++++++++-------------- 1 file changed, 169 insertions(+), 207 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 8db6a1dde..e4a9b65e2 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -55,6 +55,14 @@ pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("").route(web::post().to(chat))); } +/// Creates OpenAI client with API key +fn create_openai_client() -> Client { + let api_key = std::env::var("MEILI_OPENAI_API_KEY") + .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); + let config = OpenAIConfig::default().with_api_key(&api_key); + Client::with_config(config) +} + /// Get a chat completion async fn chat( index_scheduler: GuardedData, Data>, @@ -77,16 +85,112 @@ async fn chat( } } -async fn non_streamed_chat( - index_scheduler: GuardedData, Data>, - search_queue: web::Data, - mut chat_completion: CreateChatCompletionRequest, -) -> Result { - let api_key = std::env::var("MEILI_OPENAI_API_KEY") - .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); - let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base - let client = Client::with_config(config); +/// Setup search tool in chat completion request +fn setup_search_tool( + chat_completion: &mut CreateChatCompletionRequest, + search_in_index_description: &str, + search_in_index_q_param_description: &str, + search_in_index_index_description: &str, +) { + let tools = chat_completion.tools.get_or_insert_default(); + tools.push( + ChatCompletionToolArgs::default() + .r#type(ChatCompletionToolType::Function) + .function( + FunctionObjectArgs::default() + .name("searchInIndex") + .description(search_in_index_description) + .parameters(json!({ + "type": "object", + "properties": { + "index_uid": { + "type": "string", + "enum": ["main"], + "description": search_in_index_index_description, + }, + "q": { + "type": ["string", "null"], + "description": search_in_index_q_param_description, + } + }, + "required": ["index_uid", "q"], + "additionalProperties": false, + })) + .strict(true) + .build() + .unwrap(), + ) + .build() + .unwrap(), + ); +} +/// Process search request and return formatted results +async fn process_search_request( + index_scheduler: &GuardedData, Data>, + search_queue: &web::Data, + index_uid: String, + q: Option, +) -> Result<(Index, String), ResponseError> { + let mut query = SearchQuery { + q, + hybrid: Some(HybridQuery { + semantic_ratio: SemanticRatio::default(), + embedder: EMBEDDER_NAME.to_string(), + }), + limit: 20, + ..Default::default() + }; + + // Tenant token search_rules. + if let Some(search_rules) = index_scheduler.filters().get_index_search_rules(&index_uid) { + add_search_rules(&mut query.filter, search_rules); + } + + // TBD + // let mut aggregate = SearchAggregator::::from_query(&query); + + let index = index_scheduler.index(&index_uid)?; + let search_kind = + search_kind(&query, index_scheduler.get_ref(), index_uid.to_string(), &index)?; + + let permit = search_queue.try_get_search_permit().await?; + let features = index_scheduler.features(); + let index_cloned = index.clone(); + let search_result = tokio::task::spawn_blocking(move || { + perform_search( + index_uid.to_string(), + &index_cloned, + query, + search_kind, + RetrieveVectors::new(false), + features, + ) + }) + .await; + permit.drop().await; + + let search_result = search_result?; + if let Ok(ref search_result) = search_result { + // aggregate.succeed(search_result); + if search_result.degraded { + MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); + } + } + // analytics.publish(aggregate, &req); + + let search_result = search_result?; + let formatted = + format_documents(&index, search_result.hits.into_iter().map(|doc| doc.document)); + let text = formatted.join("\n"); + + Ok((index, text)) +} + +/// Get prompt descriptions from index scheduler +fn get_prompt_descriptions( + index_scheduler: &GuardedData, Data>, +) -> (String, String, String) { let rtxn = index_scheduler.read_txn().unwrap(); let search_in_index_description = index_scheduler .chat_prompts(&rtxn, "searchInIndex-description") @@ -105,39 +209,35 @@ async fn non_streamed_chat( .to_string(); drop(rtxn); + ( + search_in_index_description, + search_in_index_q_param_description, + search_in_index_index_description, + ) +} + +async fn non_streamed_chat( + index_scheduler: GuardedData, Data>, + search_queue: web::Data, + mut chat_completion: CreateChatCompletionRequest, +) -> Result { + let client = create_openai_client(); + + let ( + search_in_index_description, + search_in_index_q_param_description, + search_in_index_index_description, + ) = get_prompt_descriptions(&index_scheduler); + let mut response; loop { - let tools = chat_completion.tools.get_or_insert_default(); - tools.push( - ChatCompletionToolArgs::default() - .r#type(ChatCompletionToolType::Function) - .function( - FunctionObjectArgs::default() - .name("searchInIndex") - .description(&search_in_index_description) - .parameters(json!({ - "type": "object", - "properties": { - "index_uid": { - "type": "string", - "enum": ["main"], - "description": search_in_index_index_description, - }, - "q": { - "type": ["string", "null"], - "description": search_in_index_q_param_description, - } - }, - "required": ["index_uid", "q"], - "additionalProperties": false, - })) - .strict(true) - .build() - .unwrap(), - ) - .build() - .unwrap(), + setup_search_tool( + &mut chat_completion, + &search_in_index_description, + &search_in_index_q_param_description, + &search_in_index_index_description, ); + response = client.chat().create(chat_completion.clone()).await.unwrap(); let choice = &mut response.choices[0]; @@ -160,65 +260,10 @@ async fn non_streamed_chat( let SearchInIndexParameters { index_uid, q } = serde_json::from_str(&call.function.arguments).unwrap(); - let mut query = SearchQuery { - q, - hybrid: Some(HybridQuery { - semantic_ratio: SemanticRatio::default(), - embedder: EMBEDDER_NAME.to_string(), - }), - limit: 20, - ..Default::default() - }; + let (_, text) = + process_search_request(&index_scheduler, &search_queue, index_uid, q) + .await?; - // Tenant token search_rules. - if let Some(search_rules) = - index_scheduler.filters().get_index_search_rules(&index_uid) - { - add_search_rules(&mut query.filter, search_rules); - } - - // TBD - // let mut aggregate = SearchAggregator::::from_query(&query); - - let index = index_scheduler.index(&index_uid)?; - let search_kind = search_kind( - &query, - index_scheduler.get_ref(), - index_uid.to_string(), - &index, - )?; - - let permit = search_queue.try_get_search_permit().await?; - let features = index_scheduler.features(); - let index_cloned = index.clone(); - let search_result = tokio::task::spawn_blocking(move || { - perform_search( - index_uid.to_string(), - &index_cloned, - query, - search_kind, - RetrieveVectors::new(false), - features, - ) - }) - .await; - permit.drop().await; - - let search_result = search_result?; - if let Ok(ref search_result) = search_result { - // aggregate.succeed(search_result); - if search_result.degraded { - MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); - } - } - // analytics.publish(aggregate, &req); - - let search_result = search_result?; - let formatted = format_documents( - &index, - search_result.hits.into_iter().map(|doc| doc.document), - ); - let text = formatted.join("\n"); chat_completion.messages.push(ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { tool_call_id: call.id, @@ -245,63 +290,22 @@ async fn streamed_chat( search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> impl Responder { - let api_key = std::env::var("MEILI_OPENAI_API_KEY") - .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); + let ( + search_in_index_description, + search_in_index_q_param_description, + search_in_index_index_description, + ) = get_prompt_descriptions(&index_scheduler); - let rtxn = index_scheduler.read_txn().unwrap(); - let search_in_index_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) - .to_string(); - let search_in_index_q_param_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-q-param-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION) - .to_string(); - let search_in_index_index_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-index-param-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION) - .to_string(); - drop(rtxn); - - let tools = chat_completion.tools.get_or_insert_default(); - tools.push( - ChatCompletionToolArgs::default() - .r#type(ChatCompletionToolType::Function) - .function( - FunctionObjectArgs::default() - .name("searchInIndex") - .description(&search_in_index_description) - .parameters(json!({ - "type": "object", - "properties": { - "index_uid": { - "type": "string", - "enum": ["main"], - "description": search_in_index_index_description, - }, - "q": { - "type": ["string", "null"], - "description": search_in_index_q_param_description, - } - }, - "required": ["index_uid", "q"], - "additionalProperties": false, - })) - .strict(true) - .build() - .unwrap(), - ) - .build() - .unwrap(), + setup_search_tool( + &mut chat_completion, + &search_in_index_description, + &search_in_index_q_param_description, + &search_in_index_index_description, ); let (tx, rx) = tokio::sync::mpsc::channel(10); let _join_handle = Handle::current().spawn(async move { - let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base - let client = Client::with_config(config); + let client = create_openai_client(); let mut global_tool_calls = HashMap::::new(); 'main: loop { @@ -313,7 +317,9 @@ async fn streamed_chat( let delta = &resp.choices[0].delta; let ChatCompletionStreamResponseDelta { content, - function_call: _, + // Using deprecated field but keeping for compatibility + #[allow(deprecated)] + function_call: _, ref tool_calls, role: _, refusal: _, @@ -352,7 +358,7 @@ async fn streamed_chat( None if !global_tool_calls.is_empty() => { // dbg!(&global_tool_calls); - let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + let (meili_calls, _other_calls): (Vec<_>, Vec<_>) = mem::take(&mut global_tool_calls) .into_iter() .map(|(_, call)| ChatCompletionMessageToolCall { @@ -387,67 +393,23 @@ async fn streamed_chat( let SearchInIndexParameters { index_uid, q } = serde_json::from_str(&call.function.arguments).unwrap(); - let mut query = SearchQuery { + let result = process_search_request( + &index_scheduler, + &search_queue, + index_uid, q, - hybrid: Some(HybridQuery { - semantic_ratio: SemanticRatio::default(), - embedder: EMBEDDER_NAME.to_string(), - }), - limit: 20, - ..Default::default() - }; - - // Tenant token search_rules. - if let Some(search_rules) = - index_scheduler.filters().get_index_search_rules(&index_uid) - { - add_search_rules(&mut query.filter, search_rules); - } - - // TBD - // let mut aggregate = SearchAggregator::::from_query(&query); - - let index = index_scheduler.index(&index_uid).unwrap(); - let search_kind = search_kind( - &query, - index_scheduler.get_ref(), - index_uid.to_string(), - &index, ) - .unwrap(); - - let permit = - search_queue.try_get_search_permit().await.unwrap(); - let features = index_scheduler.features(); - let index_cloned = index.clone(); - let search_result = tokio::task::spawn_blocking(move || { - perform_search( - index_uid.to_string(), - &index_cloned, - query, - search_kind, - RetrieveVectors::new(false), - features, - ) - }) .await; - permit.drop().await; - let search_result = search_result.unwrap(); - if let Ok(ref search_result) = search_result { - // aggregate.succeed(search_result); - if search_result.degraded { - MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); - } + // Handle potential errors more explicitly + if let Err(err) = &result { + // Log the error or handle it as needed + eprintln!("Error processing search request: {:?}", err); + continue; } - // analytics.publish(aggregate, &req); - let search_result = search_result.unwrap(); - let formatted = format_documents( - &index, - search_result.hits.into_iter().map(|doc| doc.document), - ); - let text = formatted.join("\n"); + let (_, text) = result.unwrap(); + let tool = ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { tool_call_id: call.id, @@ -515,7 +477,7 @@ fn format_documents(index: &Index, documents: impl Iterator) -> let EmbeddingConfig { embedder_options: _, - prompt: PromptData { template, max_bytes }, + prompt: PromptData { template, max_bytes: _ }, quantized: _, } = config; From a52b513023b2454eba701ec6a9de70d44d7d029e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 17:40:55 +0200 Subject: [PATCH 129/292] Expose new chat settings routes --- crates/index-scheduler/src/lib.rs | 23 +-- crates/meilisearch-types/src/keys.rs | 8 ++ crates/meilisearch/src/routes/chat.rs | 136 +++++++----------- crates/meilisearch/src/routes/mod.rs | 4 +- .../meilisearch/src/routes/settings/chat.rs | 111 ++++++++++++++ crates/meilisearch/src/routes/settings/mod.rs | 1 + 6 files changed, 191 insertions(+), 92 deletions(-) create mode 100644 crates/meilisearch/src/routes/settings/chat.rs create mode 100644 crates/meilisearch/src/routes/settings/mod.rs diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 11572cd06..15766c691 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -53,7 +53,7 @@ use flate2::Compression; use meilisearch_types::batches::Batch; use meilisearch_types::features::{InstanceTogglableFeatures, Network, RuntimeTogglableFeatures}; use meilisearch_types::heed::byteorder::BE; -use meilisearch_types::heed::types::{Str, I128}; +use meilisearch_types::heed::types::{SerdeJson, Str, I128}; use meilisearch_types::heed::{self, Database, Env, RoTxn, WithoutTls}; use meilisearch_types::milli::index::IndexEmbeddingConfig; use meilisearch_types::milli::update::IndexerConfig; @@ -153,8 +153,8 @@ pub struct IndexScheduler { /// In charge of fetching and setting the status of experimental features. features: features::FeatureData, - /// Stores the custom prompts for the chat - chat_prompts: Database, + /// Stores the custom chat prompts and other settings of the indexes. + chat_settings: Database>, /// Everything related to the processing of the tasks pub scheduler: scheduler::Scheduler, @@ -214,7 +214,7 @@ impl IndexScheduler { #[cfg(test)] run_loop_iteration: self.run_loop_iteration.clone(), features: self.features.clone(), - chat_prompts: self.chat_prompts.clone(), + chat_settings: self.chat_settings.clone(), } } @@ -277,7 +277,7 @@ impl IndexScheduler { let features = features::FeatureData::new(&env, &mut wtxn, options.instance_features)?; let queue = Queue::new(&env, &mut wtxn, &options)?; let index_mapper = IndexMapper::new(&env, &mut wtxn, &options, budget)?; - let chat_prompts = env.create_database(&mut wtxn, Some("chat-prompts"))?; + let chat_settings = env.create_database(&mut wtxn, Some("chat-settings"))?; wtxn.commit()?; // allow unreachable_code to get rids of the warning in the case of a test build. @@ -301,7 +301,7 @@ impl IndexScheduler { #[cfg(test)] run_loop_iteration: Arc::new(RwLock::new(0)), features, - chat_prompts, + chat_settings, }; this.run(); @@ -875,8 +875,15 @@ impl IndexScheduler { res.map(EmbeddingConfigs::new) } - pub fn chat_prompts<'t>(&self, rtxn: &'t RoTxn, name: &str) -> heed::Result> { - self.chat_prompts.get(rtxn, name) + pub fn chat_settings(&self) -> Result> { + let rtxn = self.env.read_txn().map_err(Error::HeedTransaction)?; + self.chat_settings.get(&rtxn, &"main").map_err(Into::into) + } + + pub fn put_chat_settings(&self, settings: &serde_json::Value) -> Result<()> { + let mut wtxn = self.env.write_txn().map_err(Error::HeedTransaction)?; + self.chat_settings.put(&mut wtxn, &"main", &settings)?; + Ok(()) } } diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 805394781..ffa533be9 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -311,6 +311,12 @@ pub enum Action { #[serde(rename = "chat.get")] #[deserr(rename = "chat.get")] ChatGet, + #[serde(rename = "chatSettings.get")] + #[deserr(rename = "chatSettings.get")] + ChatSettingsGet, + #[serde(rename = "chatSettings.update")] + #[deserr(rename = "chatSettings.update")] + ChatSettingsUpdate, } impl Action { @@ -403,4 +409,6 @@ pub mod actions { pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); pub const CHAT_GET: u8 = ChatGet.repr(); + pub const CHAT_SETTINGS_GET: u8 = ChatSettingsGet.repr(); + pub const CHAT_SETTINGS_UPDATE: u8 = ChatSettingsUpdate.repr(); } diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index e4a9b65e2..33cc06bce 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -9,6 +9,7 @@ use async_openai::config::OpenAIConfig; use async_openai::types::{ ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, + ChatCompletionRequestSystemMessage, ChatCompletionRequestSystemMessageContent, ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, ChatCompletionStreamResponseDelta, ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, FinishReason, FunctionCall, FunctionCallStream, @@ -27,6 +28,7 @@ use serde::{Deserialize, Serialize}; use serde_json::json; use tokio::runtime::Handle; +use super::settings::chat::{ChatPrompts, ChatSettings}; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; @@ -36,33 +38,12 @@ use crate::search::{ }; use crate::search_queue::SearchQueue; -/// The default description of the searchInIndex tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION: &str = - "Search the database for relevant JSON documents using an optional query."; -/// The default description of the searchInIndex `q` parameter tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION: &str = - "The search query string used to find relevant documents in the index. \ -This should contain keywords or phrases that best represent what the user is looking for. \ -More specific queries will yield more precise results."; -/// The default description of the searchInIndex `index` parameter tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION: &str = -"The name of the index to search within. An index is a collection of documents organized for search. \ -Selecting the right index ensures the most relevant results for the user query"; - const EMBEDDER_NAME: &str = "openai"; pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("").route(web::post().to(chat))); } -/// Creates OpenAI client with API key -fn create_openai_client() -> Client { - let api_key = std::env::var("MEILI_OPENAI_API_KEY") - .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); - let config = OpenAIConfig::default().with_api_key(&api_key); - Client::with_config(config) -} - /// Get a chat completion async fn chat( index_scheduler: GuardedData, Data>, @@ -86,12 +67,7 @@ async fn chat( } /// Setup search tool in chat completion request -fn setup_search_tool( - chat_completion: &mut CreateChatCompletionRequest, - search_in_index_description: &str, - search_in_index_q_param_description: &str, - search_in_index_index_description: &str, -) { +fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: &ChatPrompts) { let tools = chat_completion.tools.get_or_insert_default(); tools.push( ChatCompletionToolArgs::default() @@ -99,18 +75,18 @@ fn setup_search_tool( .function( FunctionObjectArgs::default() .name("searchInIndex") - .description(search_in_index_description) + .description(&prompts.search_description) .parameters(json!({ "type": "object", "properties": { "index_uid": { "type": "string", "enum": ["main"], - "description": search_in_index_index_description, + "description": prompts.search_index_uid_param, }, "q": { "type": ["string", "null"], - "description": search_in_index_q_param_description, + "description": prompts.search_q_param, } }, "required": ["index_uid", "q"], @@ -125,6 +101,17 @@ fn setup_search_tool( ); } +/// Prepend system message to the conversation +fn prepend_system_message(chat_completion: &mut CreateChatCompletionRequest, system_prompt: &str) { + chat_completion.messages.insert( + 0, + ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { + content: ChatCompletionRequestSystemMessageContent::Text(system_prompt.to_string()), + name: None, + }), + ); +} + /// Process search request and return formatted results async fn process_search_request( index_scheduler: &GuardedData, Data>, @@ -187,56 +174,32 @@ async fn process_search_request( Ok((index, text)) } -/// Get prompt descriptions from index scheduler -fn get_prompt_descriptions( - index_scheduler: &GuardedData, Data>, -) -> (String, String, String) { - let rtxn = index_scheduler.read_txn().unwrap(); - let search_in_index_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) - .to_string(); - let search_in_index_q_param_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-q-param-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION) - .to_string(); - let search_in_index_index_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-index-param-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION) - .to_string(); - drop(rtxn); - - ( - search_in_index_description, - search_in_index_q_param_description, - search_in_index_index_description, - ) -} - async fn non_streamed_chat( index_scheduler: GuardedData, Data>, search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> Result { - let client = create_openai_client(); + let chat_settings = match index_scheduler.chat_settings().unwrap() { + Some(value) => serde_json::from_value(value).unwrap(), + None => ChatSettings::default(), + }; - let ( - search_in_index_description, - search_in_index_q_param_description, - search_in_index_index_description, - ) = get_prompt_descriptions(&index_scheduler); + let mut config = OpenAIConfig::default(); + if let Some(api_key) = chat_settings.api_key.as_ref() { + config = config.with_api_key(api_key); + } + // We cannot change the endpoint + // if let Some(endpoint) = chat_settings.endpoint.as_ref() { + // config.with_api_base(&endpoint); + // } + let client = Client::with_config(config); + + // Prepend system message to the conversation + prepend_system_message(&mut chat_completion, &chat_settings.prompts.system); let mut response; loop { - setup_search_tool( - &mut chat_completion, - &search_in_index_description, - &search_in_index_q_param_description, - &search_in_index_index_description, - ); + setup_search_tool(&mut chat_completion, &chat_settings.prompts); response = client.chat().create(chat_completion.clone()).await.unwrap(); @@ -290,22 +253,29 @@ async fn streamed_chat( search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> impl Responder { - let ( - search_in_index_description, - search_in_index_q_param_description, - search_in_index_index_description, - ) = get_prompt_descriptions(&index_scheduler); + let chat_settings = match index_scheduler.chat_settings().unwrap() { + Some(value) => serde_json::from_value(value).unwrap(), + None => ChatSettings::default(), + }; - setup_search_tool( - &mut chat_completion, - &search_in_index_description, - &search_in_index_q_param_description, - &search_in_index_index_description, - ); + let mut config = OpenAIConfig::default(); + if let Some(api_key) = chat_settings.api_key.as_ref() { + config = config.with_api_key(api_key); + } + // We cannot change the endpoint + // if let Some(endpoint) = chat_settings.endpoint.as_ref() { + // config.with_api_base(&endpoint); + // } + + // Prepend system message to the conversation + prepend_system_message(&mut chat_completion, &chat_settings.prompts.system); + + // Setup the search tool + setup_search_tool(&mut chat_completion, &chat_settings.prompts); let (tx, rx) = tokio::sync::mpsc::channel(10); let _join_handle = Handle::current().spawn(async move { - let client = create_openai_client(); + let client = Client::with_config(config.clone()); let mut global_tool_calls = HashMap::::new(); 'main: loop { diff --git a/crates/meilisearch/src/routes/mod.rs b/crates/meilisearch/src/routes/mod.rs index 602fb6b40..3d56ce8e8 100644 --- a/crates/meilisearch/src/routes/mod.rs +++ b/crates/meilisearch/src/routes/mod.rs @@ -62,6 +62,7 @@ mod multi_search; mod multi_search_analytics; pub mod network; mod open_api_utils; +pub mod settings; mod snapshot; mod swap_indexes; pub mod tasks; @@ -115,7 +116,8 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service(web::scope("/metrics").configure(metrics::configure)) .service(web::scope("/experimental-features").configure(features::configure)) .service(web::scope("/network").configure(network::configure)) - .service(web::scope("/chat").configure(chat::configure)); + .service(web::scope("/chat").configure(chat::configure)) + .service(web::scope("/settings/chat").configure(settings::chat::configure)); #[cfg(feature = "swagger")] { diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/settings/chat.rs new file mode 100644 index 000000000..9708e1409 --- /dev/null +++ b/crates/meilisearch/src/routes/settings/chat.rs @@ -0,0 +1,111 @@ +use std::collections::BTreeMap; + +use actix_web::web::{self, Data}; +use actix_web::HttpResponse; +use index_scheduler::IndexScheduler; +use meilisearch_types::error::ResponseError; +use meilisearch_types::keys::actions; +use serde::{Deserialize, Serialize}; + +use crate::extractors::authentication::policies::ActionPolicy; +use crate::extractors::authentication::GuardedData; +use crate::extractors::sequential_extractor::SeqHandler; + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.service( + web::resource("") + .route(web::get().to(get_settings)) + .route(web::patch().to(SeqHandler(patch_settings))), + ); +} + +async fn get_settings( + index_scheduler: GuardedData< + ActionPolicy<{ actions::CHAT_SETTINGS_GET }>, + Data, + >, +) -> Result { + let settings = match index_scheduler.chat_settings()? { + Some(value) => serde_json::from_value(value).unwrap(), + None => ChatSettings::default(), + }; + Ok(HttpResponse::Ok().json(settings)) +} + +async fn patch_settings( + index_scheduler: GuardedData< + ActionPolicy<{ actions::CHAT_SETTINGS_UPDATE }>, + Data, + >, + web::Json(chat_settings): web::Json, +) -> Result { + let chat_settings = serde_json::to_value(chat_settings).unwrap(); + index_scheduler.put_chat_settings(&chat_settings)?; + Ok(HttpResponse::Ok().finish()) +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct ChatSettings { + pub source: String, + pub endpoint: Option, + pub api_key: Option, + pub prompts: ChatPrompts, + pub indexes: BTreeMap, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct ChatPrompts { + pub system: String, + pub search_description: String, + pub search_q_param: String, + pub search_index_uid_param: String, + pub pre_query: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct ChatIndexSettings { + pub description: String, + pub document_template: String, +} + +const DEFAULT_SYSTEM_MESSAGE: &str = "You are a highly capable research assistant with access to powerful search tools. IMPORTANT INSTRUCTIONS:\ + 1. When answering questions, you MUST make multiple tool calls (at least 2-3) to gather comprehensive information.\ + 2. Use different search queries for each tool call - vary keywords, rephrase questions, and explore different semantic angles to ensure broad coverage.\ + 3. Always explicitly announce BEFORE making each tool call by saying: \"I'll search for [specific information] now.\"\ + 4. Combine information from ALL tool calls to provide complete, nuanced answers rather than relying on a single source.\ + 5. For complex topics, break down your research into multiple targeted queries rather than using a single generic search."; + +/// The default description of the searchInIndex tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION: &str = + "Search the database for relevant JSON documents using an optional query."; +/// The default description of the searchInIndex `q` parameter tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION: &str = + "The search query string used to find relevant documents in the index. \ +This should contain keywords or phrases that best represent what the user is looking for. \ +More specific queries will yield more precise results."; +/// The default description of the searchInIndex `index` parameter tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION: &str = +"The name of the index to search within. An index is a collection of documents organized for search. \ +Selecting the right index ensures the most relevant results for the user query"; + +impl Default for ChatSettings { + fn default() -> Self { + ChatSettings { + source: "openai".to_string(), + endpoint: None, + api_key: None, + prompts: ChatPrompts { + system: DEFAULT_SYSTEM_MESSAGE.to_string(), + search_description: DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION.to_string(), + search_q_param: DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION.to_string(), + search_index_uid_param: DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION + .to_string(), + pre_query: "".to_string(), + }, + indexes: BTreeMap::new(), + } + } +} diff --git a/crates/meilisearch/src/routes/settings/mod.rs b/crates/meilisearch/src/routes/settings/mod.rs new file mode 100644 index 000000000..30a62fc50 --- /dev/null +++ b/crates/meilisearch/src/routes/settings/mod.rs @@ -0,0 +1 @@ +pub mod chat; From c7839b5a8483f5f3190b9ad27c5097bbd940fc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 17:52:26 +0200 Subject: [PATCH 130/292] Remove useless function --- crates/meilisearch/src/routes/chat.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 33cc06bce..3b85811c3 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -99,14 +99,11 @@ fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: .build() .unwrap(), ); -} -/// Prepend system message to the conversation -fn prepend_system_message(chat_completion: &mut CreateChatCompletionRequest, system_prompt: &str) { chat_completion.messages.insert( 0, ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { - content: ChatCompletionRequestSystemMessageContent::Text(system_prompt.to_string()), + content: ChatCompletionRequestSystemMessageContent::Text(prompts.system.clone()), name: None, }), ); @@ -194,13 +191,10 @@ async fn non_streamed_chat( // } let client = Client::with_config(config); - // Prepend system message to the conversation - prepend_system_message(&mut chat_completion, &chat_settings.prompts.system); + setup_search_tool(&mut chat_completion, &chat_settings.prompts); let mut response; loop { - setup_search_tool(&mut chat_completion, &chat_settings.prompts); - response = client.chat().create(chat_completion.clone()).await.unwrap(); let choice = &mut response.choices[0]; @@ -267,10 +261,6 @@ async fn streamed_chat( // config.with_api_base(&endpoint); // } - // Prepend system message to the conversation - prepend_system_message(&mut chat_completion, &chat_settings.prompts.system); - - // Setup the search tool setup_search_tool(&mut chat_completion, &chat_settings.prompts); let (tx, rx) = tokio::sync::mpsc::channel(10); From 7d8415448c3ff76dd204bccb4ebb81e3893ea3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 18:03:26 +0200 Subject: [PATCH 131/292] Commit when putting stuff in LMDB --- crates/index-scheduler/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 15766c691..f96539454 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -883,6 +883,7 @@ impl IndexScheduler { pub fn put_chat_settings(&self, settings: &serde_json::Value) -> Result<()> { let mut wtxn = self.env.write_txn().map_err(Error::HeedTransaction)?; self.chat_settings.put(&mut wtxn, &"main", &settings)?; + wtxn.commit().map_err(Error::HeedTransaction)?; Ok(()) } } From 7fa74b49316847e451e4b7f5e9cda47f49196b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 18:10:09 +0200 Subject: [PATCH 132/292] Display pre-query prompt in search tool response --- crates/meilisearch/src/routes/chat.rs | 31 +++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 3b85811c3..f8a3e8237 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -27,6 +27,7 @@ use meilisearch_types::{Document, Index}; use serde::{Deserialize, Serialize}; use serde_json::json; use tokio::runtime::Handle; +use tracing::error; use super::settings::chat::{ChatPrompts, ChatSettings}; use crate::extractors::authentication::policies::ActionPolicy; @@ -361,32 +362,40 @@ async fn streamed_chat( ) .await; - // Handle potential errors more explicitly - if let Err(err) = &result { - // Log the error or handle it as needed - eprintln!("Error processing search request: {:?}", err); - continue; - } - - let (_, text) = result.unwrap(); + let text = match result { + Ok((_, text)) => text, + Err(err) => { + error!("Error processing search request: {err:?}"); + continue; + } + }; let tool = ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { - tool_call_id: call.id, + tool_call_id: call.id.clone(), content: ChatCompletionRequestToolMessageContent::Text( - text, + format!("{}\n\n{text}", chat_settings.prompts.pre_query), ), }, ); + tx.send(Event::Data( sse::Data::new_json(&json!({ "object": "chat.completion.tool.output", - "tool": tool, + "tool": ChatCompletionRequestMessage::Tool( + ChatCompletionRequestToolMessage { + tool_call_id: call.id, + content: ChatCompletionRequestToolMessageContent::Text( + text, + ), + }, + ), })) .unwrap(), )) .await .unwrap(); + chat_completion.messages.push(tool); } } From 564f85280c5d3962ff67f29bc48b786e36aca6f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 18:16:06 +0200 Subject: [PATCH 133/292] Make clippy happy --- crates/index-scheduler/src/lib.rs | 6 +++--- crates/meilisearch/src/routes/chat.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index f96539454..9fb92f041 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -214,7 +214,7 @@ impl IndexScheduler { #[cfg(test)] run_loop_iteration: self.run_loop_iteration.clone(), features: self.features.clone(), - chat_settings: self.chat_settings.clone(), + chat_settings: self.chat_settings, } } @@ -877,12 +877,12 @@ impl IndexScheduler { pub fn chat_settings(&self) -> Result> { let rtxn = self.env.read_txn().map_err(Error::HeedTransaction)?; - self.chat_settings.get(&rtxn, &"main").map_err(Into::into) + self.chat_settings.get(&rtxn, "main").map_err(Into::into) } pub fn put_chat_settings(&self, settings: &serde_json::Value) -> Result<()> { let mut wtxn = self.env.write_txn().map_err(Error::HeedTransaction)?; - self.chat_settings.put(&mut wtxn, &"main", &settings)?; + self.chat_settings.put(&mut wtxn, "main", settings)?; wtxn.commit().map_err(Error::HeedTransaction)?; Ok(()) } diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index f8a3e8237..82ee4b435 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -276,11 +276,11 @@ async fn streamed_chat( match result { Ok(resp) => { let delta = &resp.choices[0].delta; + #[allow(deprecated)] let ChatCompletionStreamResponseDelta { content, // Using deprecated field but keeping for compatibility - #[allow(deprecated)] - function_call: _, + function_call: _, ref tool_calls, role: _, refusal: _, @@ -291,7 +291,7 @@ async fn streamed_chat( break 'main; } - if let Some(_) = content { + if content.is_some() { tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())).await.unwrap() } @@ -321,8 +321,8 @@ async fn streamed_chat( let (meili_calls, _other_calls): (Vec<_>, Vec<_>) = mem::take(&mut global_tool_calls) - .into_iter() - .map(|(_, call)| ChatCompletionMessageToolCall { + .into_values() + .map(|call| ChatCompletionMessageToolCall { id: call.id, r#type: ChatCompletionToolType::Function, function: FunctionCall { @@ -342,7 +342,7 @@ async fn streamed_chat( for call in meili_calls { tx.send(Event::Data( - sse::Data::new_json(&json!({ + sse::Data::new_json(json!({ "object": "chat.completion.tool.call", "tool": call, })) @@ -380,7 +380,7 @@ async fn streamed_chat( ); tx.send(Event::Data( - sse::Data::new_json(&json!({ + sse::Data::new_json(json!({ "object": "chat.completion.tool.output", "tool": ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { From b9716ec346cf64a7cb09c5a9c746576fbf149e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 15 May 2025 18:28:02 +0200 Subject: [PATCH 134/292] Support base_api in the settings --- crates/meilisearch/src/routes/chat.rs | 14 ++++++-------- crates/meilisearch/src/routes/settings/chat.rs | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 82ee4b435..8d07342c8 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -186,10 +186,9 @@ async fn non_streamed_chat( if let Some(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - // We cannot change the endpoint - // if let Some(endpoint) = chat_settings.endpoint.as_ref() { - // config.with_api_base(&endpoint); - // } + if let Some(base_api) = chat_settings.base_api.as_ref() { + config = config.with_api_base(base_api); + } let client = Client::with_config(config); setup_search_tool(&mut chat_completion, &chat_settings.prompts); @@ -257,10 +256,9 @@ async fn streamed_chat( if let Some(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - // We cannot change the endpoint - // if let Some(endpoint) = chat_settings.endpoint.as_ref() { - // config.with_api_base(&endpoint); - // } + if let Some(base_api) = chat_settings.base_api.as_ref() { + config = config.with_api_base(base_api); + } setup_search_tool(&mut chat_completion, &chat_settings.prompts); diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/settings/chat.rs index 9708e1409..d8be27ab3 100644 --- a/crates/meilisearch/src/routes/settings/chat.rs +++ b/crates/meilisearch/src/routes/settings/chat.rs @@ -48,7 +48,7 @@ async fn patch_settings( #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct ChatSettings { pub source: String, - pub endpoint: Option, + pub base_api: Option, pub api_key: Option, pub prompts: ChatPrompts, pub indexes: BTreeMap, @@ -95,7 +95,7 @@ impl Default for ChatSettings { fn default() -> Self { ChatSettings { source: "openai".to_string(), - endpoint: None, + base_api: None, api_key: None, prompts: ChatPrompts { system: DEFAULT_SYSTEM_MESSAGE.to_string(), From 341183cd578a050ceb8916a0379435b0ade2fe20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Fri, 16 May 2025 14:33:53 +0200 Subject: [PATCH 135/292] Make it compatible with the Mistral API --- Cargo.lock | 8 +++----- crates/meilisearch/Cargo.toml | 2 +- crates/meilisearch/src/routes/chat.rs | 16 ++++++++++------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ce6b5186..260df24ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,9 +475,8 @@ dependencies = [ [[package]] name = "async-openai" -version = "0.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ac0334b0fef1ddaf141154a3ef6d55a95b5b1a52c720753554b0a1ca670e68" +version = "0.28.1" +source = "git+https://github.com/meilisearch/async-openai?branch=optional-type-function#603f1d17bb4530c45fb9a6e93294ab715a7af869" dependencies = [ "async-openai-macros", "backoff", @@ -502,8 +501,7 @@ dependencies = [ [[package]] name = "async-openai-macros" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0289cba6d5143bfe8251d57b4a8cac036adf158525a76533a7082ba65ec76398" +source = "git+https://github.com/meilisearch/async-openai?branch=optional-type-function#dd328d4c35ca24c30284c8aff616541ac82eb47a" dependencies = [ "proc-macro2", "quote", diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index f7469e7ac..398b62dad 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -112,7 +112,7 @@ utoipa = { version = "5.3.1", features = [ "openapi_extensions", ] } utoipa-scalar = { version = "0.3.0", optional = true, features = ["actix-web"] } -async-openai = "0.28.1" +async-openai = { git = "https://github.com/meilisearch/async-openai", branch = "optional-type-function" } actix-web-lab = { version = "0.24.1", default-features = false } [dev-dependencies] diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 8d07342c8..7869b677d 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -86,7 +86,9 @@ fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: "description": prompts.search_index_uid_param, }, "q": { - "type": ["string", "null"], + // Unfortunately, Mistral does not support an array of types, here. + // "type": ["string", "null"], + "type": "string", "description": prompts.search_q_param, } }, @@ -269,7 +271,6 @@ async fn streamed_chat( 'main: loop { let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); - while let Some(result) = response.next().await { match result { Ok(resp) => { @@ -306,12 +307,14 @@ async fn streamed_chat( function.as_ref().unwrap(); global_tool_calls .entry(*index) + .and_modify(|call| { + call.append(arguments.as_ref().unwrap()); + }) .or_insert_with(|| Call { id: id.as_ref().unwrap().clone(), function_name: name.as_ref().unwrap().clone(), arguments: arguments.as_ref().unwrap().clone(), - }) - .append(arguments.as_ref().unwrap()); + }); } } None if !global_tool_calls.is_empty() => { @@ -322,7 +325,7 @@ async fn streamed_chat( .into_values() .map(|call| ChatCompletionMessageToolCall { id: call.id, - r#type: ChatCompletionToolType::Function, + r#type: Some(ChatCompletionToolType::Function), function: FunctionCall { name: call.function_name, arguments: call.arguments, @@ -400,8 +403,9 @@ async fn streamed_chat( None => (), } } - Err(_err) => { + Err(err) => { // writeln!(lock, "error: {err}").unwrap(); + tracing::error!("{err:?}"); } } } From 1d2dbcb51fd6d71931a933aba637a075f45cea5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Fri, 16 May 2025 15:17:01 +0200 Subject: [PATCH 136/292] Update the streaming detection to work with Mistral --- crates/meilisearch/src/routes/chat.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 7869b677d..fe5fdd415 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -281,11 +281,14 @@ async fn streamed_chat( // Using deprecated field but keeping for compatibility function_call: _, ref tool_calls, - role: _, + role, refusal: _, } = delta; - if content.is_none() && tool_calls.is_none() && global_tool_calls.is_empty() + if content.as_ref().map_or(true, |s| s.is_empty()) + && tool_calls.is_none() + && global_tool_calls.is_empty() + && role.is_none() { break 'main; } From 39320a6fcef923a5dfb4f3b4e6a7507c701c13ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Fri, 16 May 2025 17:12:48 +0200 Subject: [PATCH 137/292] Better stop the stream --- Cargo.lock | 2 +- crates/meilisearch/src/routes/chat.rs | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 260df24ed..dd47ee94c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -501,7 +501,7 @@ dependencies = [ [[package]] name = "async-openai-macros" version = "0.1.0" -source = "git+https://github.com/meilisearch/async-openai?branch=optional-type-function#dd328d4c35ca24c30284c8aff616541ac82eb47a" +source = "git+https://github.com/meilisearch/async-openai?branch=optional-type-function#603f1d17bb4530c45fb9a6e93294ab715a7af869" dependencies = [ "proc-macro2", "quote", diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index fe5fdd415..04de94b88 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -268,30 +268,25 @@ async fn streamed_chat( let _join_handle = Handle::current().spawn(async move { let client = Client::with_config(config.clone()); let mut global_tool_calls = HashMap::::new(); + let mut finish_reason = None; - 'main: loop { + 'main: while finish_reason.map_or(true, |fr| fr == FinishReason::ToolCalls) { let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); while let Some(result) = response.next().await { match result { Ok(resp) => { - let delta = &resp.choices[0].delta; + let choice = &resp.choices[0]; + finish_reason = choice.finish_reason; + #[allow(deprecated)] let ChatCompletionStreamResponseDelta { content, // Using deprecated field but keeping for compatibility function_call: _, ref tool_calls, - role, + role: _, refusal: _, - } = delta; - - if content.as_ref().map_or(true, |s| s.is_empty()) - && tool_calls.is_none() - && global_tool_calls.is_empty() - && role.is_none() - { - break 'main; - } + } = &choice.delta; if content.is_some() { tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())).await.unwrap() @@ -409,6 +404,7 @@ async fn streamed_chat( Err(err) => { // writeln!(lock, "error: {err}").unwrap(); tracing::error!("{err:?}"); + break 'main; } } } From 1a84f00fbf35bbb2e17256e7d34425bf45ab407f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 10:14:56 +0200 Subject: [PATCH 138/292] Change the /chat route to /chat/completions to be OpenAI-compatible --- crates/meilisearch/src/routes/chat.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 04de94b88..e58552d57 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -42,7 +42,7 @@ use crate::search_queue::SearchQueue; const EMBEDDER_NAME: &str = "openai"; pub fn configure(cfg: &mut web::ServiceConfig) { - cfg.service(web::resource("").route(web::post().to(chat))); + cfg.service(web::resource("/completions").route(web::post().to(chat))); } /// Get a chat completion From 56c1bd3afe377f75c114cca3681a774e4b4081d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 11:00:19 +0200 Subject: [PATCH 139/292] Generate a new default chat API key --- crates/meilisearch-auth/src/lib.rs | 1 + crates/meilisearch-types/src/keys.rs | 21 ++++++++++++++++--- .../src/extractors/authentication/mod.rs | 4 ++-- crates/meilisearch/src/routes/chat.rs | 8 +++---- crates/meilisearch/tests/auth/api_keys.rs | 16 ++++++++++++++ 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/crates/meilisearch-auth/src/lib.rs b/crates/meilisearch-auth/src/lib.rs index 01c986d9f..d72ba386c 100644 --- a/crates/meilisearch-auth/src/lib.rs +++ b/crates/meilisearch-auth/src/lib.rs @@ -351,6 +351,7 @@ pub struct IndexSearchRules { fn generate_default_keys(store: &HeedAuthStore) -> Result<()> { store.put_api_key(Key::default_admin())?; store.put_api_key(Key::default_search())?; + store.put_api_key(Key::default_chat())?; Ok(()) } diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index ffa533be9..dfa50aa1e 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -158,6 +158,21 @@ impl Key { updated_at: now, } } + + pub fn default_chat() -> Self { + let now = OffsetDateTime::now_utc(); + let uid = Uuid::new_v4(); + Self { + name: Some("Default Chat API Key".to_string()), + description: Some("Use it to chat and search from the frontend".to_string()), + uid, + actions: vec![Action::Chat, Action::Search], + indexes: vec![IndexUidPattern::all()], + expires_at: None, + created_at: now, + updated_at: now, + } + } } fn parse_expiration_date( @@ -310,7 +325,7 @@ pub enum Action { NetworkUpdate, #[serde(rename = "chat.get")] #[deserr(rename = "chat.get")] - ChatGet, + Chat, #[serde(rename = "chatSettings.get")] #[deserr(rename = "chatSettings.get")] ChatSettingsGet, @@ -358,7 +373,7 @@ impl Action { EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), NETWORK_GET => Some(Self::NetworkGet), NETWORK_UPDATE => Some(Self::NetworkUpdate), - CHAT_GET => Some(Self::ChatGet), + CHAT => Some(Self::Chat), _otherwise => None, } } @@ -408,7 +423,7 @@ pub mod actions { pub const NETWORK_GET: u8 = NetworkGet.repr(); pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); - pub const CHAT_GET: u8 = ChatGet.repr(); + pub const CHAT: u8 = Chat.repr(); pub const CHAT_SETTINGS_GET: u8 = ChatSettingsGet.repr(); pub const CHAT_SETTINGS_UPDATE: u8 = ChatSettingsUpdate.repr(); } diff --git a/crates/meilisearch/src/extractors/authentication/mod.rs b/crates/meilisearch/src/extractors/authentication/mod.rs index 28a6d770e..7c9f5892e 100644 --- a/crates/meilisearch/src/extractors/authentication/mod.rs +++ b/crates/meilisearch/src/extractors/authentication/mod.rs @@ -299,8 +299,8 @@ pub mod policies { auth: &AuthController, token: &str, ) -> Result { - // Only search action can be accessed by a tenant token. - if A != actions::SEARCH { + // Only search and chat actions can be accessed by a tenant token. + if A != actions::SEARCH && A != actions::CHAT { return Ok(TenantTokenOutcome::NotATenantToken); } diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index e58552d57..6c6c97761 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -47,7 +47,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { /// Get a chat completion async fn chat( - index_scheduler: GuardedData, Data>, + index_scheduler: GuardedData, Data>, search_queue: web::Data, web::Json(chat_completion): web::Json, ) -> impl Responder { @@ -114,7 +114,7 @@ fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: /// Process search request and return formatted results async fn process_search_request( - index_scheduler: &GuardedData, Data>, + index_scheduler: &GuardedData, Data>, search_queue: &web::Data, index_uid: String, q: Option, @@ -175,7 +175,7 @@ async fn process_search_request( } async fn non_streamed_chat( - index_scheduler: GuardedData, Data>, + index_scheduler: GuardedData, Data>, search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> Result { @@ -245,7 +245,7 @@ async fn non_streamed_chat( } async fn streamed_chat( - index_scheduler: GuardedData, Data>, + index_scheduler: GuardedData, Data>, search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> impl Responder { diff --git a/crates/meilisearch/tests/auth/api_keys.rs b/crates/meilisearch/tests/auth/api_keys.rs index 0aea7d722..edfcd1c29 100644 --- a/crates/meilisearch/tests/auth/api_keys.rs +++ b/crates/meilisearch/tests/auth/api_keys.rs @@ -820,6 +820,22 @@ async fn list_api_keys() { "createdAt": "[ignored]", "updatedAt": "[ignored]" }, + { + "name": "Default Chat API Key", + "description": "Use it to chat and search from the frontend", + "key": "[ignored]", + "uid": "[ignored]", + "actions": [ + "search", + "chat.get" + ], + "indexes": [ + "*" + ], + "expiresAt": null, + "createdAt": "[ignored]", + "updatedAt": "[ignored]" + }, { "name": "Default Search API Key", "description": "Use it to search from the frontend", From bcec8d8984afebe4422e3408910c6a35e81f658c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 12:05:51 +0200 Subject: [PATCH 140/292] Stop the stream when the connexion stops and chnage the events --- crates/meilisearch/src/routes/chat.rs | 68 +++++++++++++-------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 6c6c97761..733b8ff65 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -27,7 +27,7 @@ use meilisearch_types::{Document, Index}; use serde::{Deserialize, Serialize}; use serde_json::json; use tokio::runtime::Handle; -use tracing::error; +use tokio::sync::mpsc::error::SendError; use super::settings::chat::{ChatPrompts, ChatSettings}; use crate::extractors::authentication::policies::ActionPolicy; @@ -289,7 +289,9 @@ async fn streamed_chat( } = &choice.delta; if content.is_some() { - tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())).await.unwrap() + if let Err(SendError(_)) = tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())).await { + return; + } } match tool_calls { @@ -305,9 +307,7 @@ async fn streamed_chat( function.as_ref().unwrap(); global_tool_calls .entry(*index) - .and_modify(|call| { - call.append(arguments.as_ref().unwrap()); - }) + .and_modify(|call| call.append(arguments.as_ref().unwrap())) .or_insert_with(|| Call { id: id.as_ref().unwrap().clone(), function_name: name.as_ref().unwrap().clone(), @@ -316,8 +316,6 @@ async fn streamed_chat( } } None if !global_tool_calls.is_empty() => { - // dbg!(&global_tool_calls); - let (meili_calls, _other_calls): (Vec<_>, Vec<_>) = mem::take(&mut global_tool_calls) .into_values() @@ -340,15 +338,16 @@ async fn streamed_chat( ); for call in meili_calls { - tx.send(Event::Data( + if let Err(SendError(_)) = tx.send(Event::Data( sse::Data::new_json(json!({ "object": "chat.completion.tool.call", "tool": call, })) .unwrap(), )) - .await - .unwrap(); + .await { + return; + } let SearchInIndexParameters { index_uid, q } = serde_json::from_str(&call.function.arguments).unwrap(); @@ -361,41 +360,40 @@ async fn streamed_chat( ) .await; + let is_error = result.is_err(); let text = match result { Ok((_, text)) => text, - Err(err) => { - error!("Error processing search request: {err:?}"); - continue; - } + Err(err) => err.to_string(), }; - let tool = ChatCompletionRequestMessage::Tool( - ChatCompletionRequestToolMessage { - tool_call_id: call.id.clone(), - content: ChatCompletionRequestToolMessageContent::Text( - format!("{}\n\n{text}", chat_settings.prompts.pre_query), - ), - }, - ); + let tool = ChatCompletionRequestToolMessage { + tool_call_id: call.id.clone(), + content: ChatCompletionRequestToolMessageContent::Text( + format!("{}\n\n{text}", chat_settings.prompts.pre_query), + ), + }; - tx.send(Event::Data( + if let Err(SendError(_)) = tx.send(Event::Data( sse::Data::new_json(json!({ - "object": "chat.completion.tool.output", - "tool": ChatCompletionRequestMessage::Tool( - ChatCompletionRequestToolMessage { - tool_call_id: call.id, - content: ChatCompletionRequestToolMessageContent::Text( - text, - ), - }, - ), + "object": if is_error { + "chat.completion.tool.error" + } else { + "chat.completion.tool.output" + }, + "tool": ChatCompletionRequestToolMessage { + tool_call_id: call.id, + content: ChatCompletionRequestToolMessageContent::Text( + text, + ), + }, })) .unwrap(), )) - .await - .unwrap(); + .await { + return; + } - chat_completion.messages.push(tool); + chat_completion.messages.push(ChatCompletionRequestMessage::Tool(tool)); } } None => (), From 46680585ae54f3ba979e9a0fa5107b1913eb6788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 12:23:22 +0200 Subject: [PATCH 141/292] Stream errors --- crates/meilisearch/src/routes/chat.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 733b8ff65..5ddcb6088 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -400,13 +400,21 @@ async fn streamed_chat( } } Err(err) => { - // writeln!(lock, "error: {err}").unwrap(); tracing::error!("{err:?}"); + if let Err(SendError(_)) = tx.send(Event::Data(sse::Data::new_json(&json!({ + "object": "chat.completion.error", + "tool": err.to_string(), + })).unwrap())).await { + return; + } + break 'main; } } } } + + let _ = tx.send(Event::Data(sse::Data::new("[DONE]"))); }); Sse::from_infallible_receiver(rx).with_retry_duration(Duration::from_secs(10)) From 7636365a650d46c37f12276838fc5f1a3a085f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 16:15:49 +0200 Subject: [PATCH 142/292] Correctly support tenant tokens and filters --- .../src/extractors/authentication/mod.rs | 57 +++++++++++-------- crates/meilisearch/src/routes/chat.rs | 49 ++++++++++++---- 2 files changed, 72 insertions(+), 34 deletions(-) diff --git a/crates/meilisearch/src/extractors/authentication/mod.rs b/crates/meilisearch/src/extractors/authentication/mod.rs index 7c9f5892e..eb250190d 100644 --- a/crates/meilisearch/src/extractors/authentication/mod.rs +++ b/crates/meilisearch/src/extractors/authentication/mod.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; use std::ops::Deref; use std::pin::Pin; +use actix_web::http::header::AUTHORIZATION; use actix_web::web::Data; use actix_web::FromRequest; pub use error::AuthenticationError; @@ -94,36 +95,44 @@ impl FromRequest for GuardedData _payload: &mut actix_web::dev::Payload, ) -> Self::Future { match req.app_data::>().cloned() { - Some(auth) => match req - .headers() - .get("Authorization") - .map(|type_token| type_token.to_str().unwrap_or_default().splitn(2, ' ')) - { - Some(mut type_token) => match type_token.next() { - Some("Bearer") => { - // TODO: find a less hardcoded way? - let index = req.match_info().get("index_uid"); - match type_token.next() { - Some(token) => Box::pin(Self::auth_bearer( - auth, - token.to_string(), - index.map(String::from), - req.app_data::().cloned(), - )), - None => Box::pin(err(AuthenticationError::InvalidToken.into())), - } - } - _otherwise => { - Box::pin(err(AuthenticationError::MissingAuthorizationHeader.into())) - } - }, - None => Box::pin(Self::auth_token(auth, req.app_data::().cloned())), + Some(auth) => match extract_token_from_request(req) { + Ok(Some(token)) => { + // TODO: find a less hardcoded way? + let index = req.match_info().get("index_uid"); + Box::pin(Self::auth_bearer( + auth, + token.to_string(), + index.map(String::from), + req.app_data::().cloned(), + )) + } + Ok(None) => Box::pin(Self::auth_token(auth, req.app_data::().cloned())), + Err(e) => Box::pin(err(e.into())), }, None => Box::pin(err(AuthenticationError::IrretrievableState.into())), } } } +pub fn extract_token_from_request( + req: &actix_web::HttpRequest, +) -> Result, AuthenticationError> { + match req + .headers() + .get(AUTHORIZATION) + .map(|type_token| type_token.to_str().unwrap_or_default().splitn(2, ' ')) + { + Some(mut type_token) => match type_token.next() { + Some("Bearer") => match type_token.next() { + Some(token) => Ok(Some(token)), + None => Err(AuthenticationError::InvalidToken), + }, + _otherwise => Err(AuthenticationError::MissingAuthorizationHeader), + }, + None => Ok(None), + } +} + pub trait Policy { fn authenticate( auth: Data, diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 5ddcb6088..31e089231 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -3,7 +3,7 @@ use std::mem; use std::time::Duration; use actix_web::web::{self, Data}; -use actix_web::{Either, HttpResponse, Responder}; +use actix_web::{Either, HttpRequest, HttpResponse, Responder}; use actix_web_lab::sse::{self, Event, Sse}; use async_openai::config::OpenAIConfig; use async_openai::types::{ @@ -18,6 +18,7 @@ use async_openai::types::{ use async_openai::Client; use futures::StreamExt; use index_scheduler::IndexScheduler; +use meilisearch_auth::AuthController; use meilisearch_types::error::ResponseError; use meilisearch_types::keys::actions; use meilisearch_types::milli::index::IndexEmbeddingConfig; @@ -31,7 +32,7 @@ use tokio::sync::mpsc::error::SendError; use super::settings::chat::{ChatPrompts, ChatSettings}; use crate::extractors::authentication::policies::ActionPolicy; -use crate::extractors::authentication::GuardedData; +use crate::extractors::authentication::{extract_token_from_request, GuardedData, Policy as _}; use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; use crate::routes::indexes::search::search_kind; use crate::search::{ @@ -48,6 +49,8 @@ pub fn configure(cfg: &mut web::ServiceConfig) { /// Get a chat completion async fn chat( index_scheduler: GuardedData, Data>, + auth_ctrl: web::Data, + req: HttpRequest, search_queue: web::Data, web::Json(chat_completion): web::Json, ) -> impl Responder { @@ -61,9 +64,13 @@ async fn chat( ); if chat_completion.stream.unwrap_or(false) { - Either::Right(streamed_chat(index_scheduler, search_queue, chat_completion).await) + Either::Right( + streamed_chat(index_scheduler, auth_ctrl, req, search_queue, chat_completion).await, + ) } else { - Either::Left(non_streamed_chat(index_scheduler, search_queue, chat_completion).await) + Either::Left( + non_streamed_chat(index_scheduler, auth_ctrl, req, search_queue, chat_completion).await, + ) } } @@ -115,7 +122,9 @@ fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: /// Process search request and return formatted results async fn process_search_request( index_scheduler: &GuardedData, Data>, + auth_ctrl: web::Data, search_queue: &web::Data, + auth_token: &str, index_uid: String, q: Option, ) -> Result<(Index, String), ResponseError> { @@ -129,8 +138,14 @@ async fn process_search_request( ..Default::default() }; + let auth_filter = ActionPolicy::<{ actions::SEARCH }>::authenticate( + auth_ctrl, + auth_token, + Some(index_uid.as_str()), + )?; + // Tenant token search_rules. - if let Some(search_rules) = index_scheduler.filters().get_index_search_rules(&index_uid) { + if let Some(search_rules) = auth_filter.get_index_search_rules(&index_uid) { add_search_rules(&mut query.filter, search_rules); } @@ -176,6 +191,8 @@ async fn process_search_request( async fn non_streamed_chat( index_scheduler: GuardedData, Data>, + auth_ctrl: web::Data, + req: HttpRequest, search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> Result { @@ -193,6 +210,7 @@ async fn non_streamed_chat( } let client = Client::with_config(config); + let auth_token = extract_token_from_request(&req)?.unwrap(); setup_search_tool(&mut chat_completion, &chat_settings.prompts); let mut response; @@ -219,9 +237,15 @@ async fn non_streamed_chat( let SearchInIndexParameters { index_uid, q } = serde_json::from_str(&call.function.arguments).unwrap(); - let (_, text) = - process_search_request(&index_scheduler, &search_queue, index_uid, q) - .await?; + let (_, text) = process_search_request( + &index_scheduler, + auth_ctrl.clone(), + &search_queue, + auth_token, + index_uid, + q, + ) + .await?; chat_completion.messages.push(ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { @@ -246,9 +270,11 @@ async fn non_streamed_chat( async fn streamed_chat( index_scheduler: GuardedData, Data>, + auth_ctrl: web::Data, + req: HttpRequest, search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, -) -> impl Responder { +) -> Result { let chat_settings = match index_scheduler.chat_settings().unwrap() { Some(value) => serde_json::from_value(value).unwrap(), None => ChatSettings::default(), @@ -262,6 +288,7 @@ async fn streamed_chat( config = config.with_api_base(base_api); } + let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); setup_search_tool(&mut chat_completion, &chat_settings.prompts); let (tx, rx) = tokio::sync::mpsc::channel(10); @@ -354,7 +381,9 @@ async fn streamed_chat( let result = process_search_request( &index_scheduler, + auth_ctrl.clone(), &search_queue, + &auth_token, index_uid, q, ) @@ -417,7 +446,7 @@ async fn streamed_chat( let _ = tx.send(Event::Data(sse::Data::new("[DONE]"))); }); - Sse::from_infallible_receiver(rx).with_retry_duration(Duration::from_secs(10)) + Ok(Sse::from_infallible_receiver(rx).with_retry_duration(Duration::from_secs(10))) } /// The structure used to aggregate the function calls to make. From 0b675bd530b9316f2e78d058a09389a293c4b638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 16:44:28 +0200 Subject: [PATCH 143/292] Limit the number of internal loop calls and change the function name --- crates/meilisearch/src/routes/chat.rs | 82 +++++++++++++++------------ 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 31e089231..2715cff72 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -41,6 +41,7 @@ use crate::search::{ use crate::search_queue::SearchQueue; const EMBEDDER_NAME: &str = "openai"; +const SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("/completions").route(web::post().to(chat))); @@ -77,39 +78,41 @@ async fn chat( /// Setup search tool in chat completion request fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: &ChatPrompts) { let tools = chat_completion.tools.get_or_insert_default(); - tools.push( - ChatCompletionToolArgs::default() - .r#type(ChatCompletionToolType::Function) - .function( - FunctionObjectArgs::default() - .name("searchInIndex") - .description(&prompts.search_description) - .parameters(json!({ - "type": "object", - "properties": { - "index_uid": { - "type": "string", - "enum": ["main"], - "description": prompts.search_index_uid_param, - }, - "q": { - // Unfortunately, Mistral does not support an array of types, here. - // "type": ["string", "null"], - "type": "string", - "description": prompts.search_q_param, - } - }, - "required": ["index_uid", "q"], - "additionalProperties": false, - })) - .strict(true) - .build() - .unwrap(), - ) - .build() - .unwrap(), - ); + if tools.iter().find(|t| t.function.name == SEARCH_IN_INDEX_FUNCTION_NAME).is_some() { + panic!("{SEARCH_IN_INDEX_FUNCTION_NAME} function already set"); + } + let tool = ChatCompletionToolArgs::default() + .r#type(ChatCompletionToolType::Function) + .function( + FunctionObjectArgs::default() + .name(SEARCH_IN_INDEX_FUNCTION_NAME) + .description(&prompts.search_description) + .parameters(json!({ + "type": "object", + "properties": { + "index_uid": { + "type": "string", + "enum": ["main"], + "description": prompts.search_index_uid_param, + }, + "q": { + // Unfortunately, Mistral does not support an array of types, here. + // "type": ["string", "null"], + "type": "string", + "description": prompts.search_q_param, + } + }, + "required": ["index_uid", "q"], + "additionalProperties": false, + })) + .strict(true) + .build() + .unwrap(), + ) + .build() + .unwrap(); + tools.push(tool); chat_completion.messages.insert( 0, ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { @@ -222,8 +225,9 @@ async fn non_streamed_chat( Some(FinishReason::ToolCalls) => { let tool_calls = mem::take(&mut choice.message.tool_calls).unwrap_or_default(); - let (meili_calls, other_calls): (Vec<_>, Vec<_>) = - tool_calls.into_iter().partition(|call| call.function.name == "searchInIndex"); + let (meili_calls, other_calls): (Vec<_>, Vec<_>) = tool_calls + .into_iter() + .partition(|call| call.function.name == SEARCH_IN_INDEX_FUNCTION_NAME); chat_completion.messages.push( ChatCompletionRequestAssistantMessageArgs::default() @@ -297,7 +301,8 @@ async fn streamed_chat( let mut global_tool_calls = HashMap::::new(); let mut finish_reason = None; - 'main: while finish_reason.map_or(true, |fr| fr == FinishReason::ToolCalls) { + // Limit the number of internal calls to satisfy the search requests of the LLM + 'main: for _ in 0..20 { let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); while let Some(result) = response.next().await { match result { @@ -354,7 +359,7 @@ async fn streamed_chat( arguments: call.arguments, }, }) - .partition(|call| call.function.name == "searchInIndex"); + .partition(|call| call.function.name == SEARCH_IN_INDEX_FUNCTION_NAME); chat_completion.messages.push( ChatCompletionRequestAssistantMessageArgs::default() @@ -441,6 +446,11 @@ async fn streamed_chat( } } } + + // We must stop if the finish reason is not something we can solve with Meilisearch + if finish_reason.map_or(true, |fr| fr != FinishReason::ToolCalls) { + break; + } } let _ = tx.send(Event::Data(sse::Data::new("[DONE]"))); From fcf694026d24de4b36fba75764fe1fc3e997b0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 17:15:23 +0200 Subject: [PATCH 144/292] Support multiple indexes and not only main --- crates/meilisearch/src/routes/chat.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 2715cff72..f794ba19c 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -76,12 +76,23 @@ async fn chat( } /// Setup search tool in chat completion request -fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: &ChatPrompts) { +fn setup_search_tool( + index_scheduler: &Data, + filters: &meilisearch_auth::AuthFilter, + chat_completion: &mut CreateChatCompletionRequest, + prompts: &ChatPrompts, +) -> Result<(), ResponseError> { let tools = chat_completion.tools.get_or_insert_default(); if tools.iter().find(|t| t.function.name == SEARCH_IN_INDEX_FUNCTION_NAME).is_some() { panic!("{SEARCH_IN_INDEX_FUNCTION_NAME} function already set"); } + let index_uids: Vec<_> = index_scheduler + .index_names()? + .into_iter() + .filter(|index_uid| filters.is_index_authorized(&index_uid)) + .collect(); + let tool = ChatCompletionToolArgs::default() .r#type(ChatCompletionToolType::Function) .function( @@ -93,7 +104,7 @@ fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: "properties": { "index_uid": { "type": "string", - "enum": ["main"], + "enum": index_uids, "description": prompts.search_index_uid_param, }, "q": { @@ -120,6 +131,8 @@ fn setup_search_tool(chat_completion: &mut CreateChatCompletionRequest, prompts: name: None, }), ); + + Ok(()) } /// Process search request and return formatted results @@ -199,6 +212,8 @@ async fn non_streamed_chat( search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> Result { + let filters = index_scheduler.filters(); + let chat_settings = match index_scheduler.chat_settings().unwrap() { Some(value) => serde_json::from_value(value).unwrap(), None => ChatSettings::default(), @@ -214,7 +229,7 @@ async fn non_streamed_chat( let client = Client::with_config(config); let auth_token = extract_token_from_request(&req)?.unwrap(); - setup_search_tool(&mut chat_completion, &chat_settings.prompts); + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; let mut response; loop { @@ -279,6 +294,8 @@ async fn streamed_chat( search_queue: web::Data, mut chat_completion: CreateChatCompletionRequest, ) -> Result { + let filters = index_scheduler.filters(); + let chat_settings = match index_scheduler.chat_settings().unwrap() { Some(value) => serde_json::from_value(value).unwrap(), None => ChatSettings::default(), @@ -293,7 +310,7 @@ async fn streamed_chat( } let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); - setup_search_tool(&mut chat_completion, &chat_settings.prompts); + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; let (tx, rx) = tokio::sync::mpsc::channel(10); let _join_handle = Handle::current().spawn(async move { From 6bf214bb1439c8b7b167c6b1bd70932aeb41164c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 17:55:21 +0200 Subject: [PATCH 145/292] Catch invalid argument calls to search function --- crates/meilisearch/src/routes/chat.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index f794ba19c..0dc54b37d 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -398,18 +398,17 @@ async fn streamed_chat( return; } - let SearchInIndexParameters { index_uid, q } = - serde_json::from_str(&call.function.arguments).unwrap(); - - let result = process_search_request( - &index_scheduler, - auth_ctrl.clone(), - &search_queue, - &auth_token, - index_uid, - q, - ) - .await; + let result = match serde_json::from_str(&call.function.arguments) { + Ok(SearchInIndexParameters { index_uid, q }) => process_search_request( + &index_scheduler, + auth_ctrl.clone(), + &search_queue, + &auth_token, + index_uid, + q, + ).await.map_err(|e| e.to_string()), + Err(err) => Err(err.to_string()), + }; let is_error = result.is_err(); let text = match result { From 439146289ea5e8b6afdc96e2d485ac369b6f69f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 20 May 2025 18:01:08 +0200 Subject: [PATCH 146/292] Make sure errorneous calls are handled and forwarded to the LLM --- crates/meilisearch/src/routes/chat.rs | 37 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 0dc54b37d..b3a67ff10 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -253,23 +253,32 @@ async fn non_streamed_chat( ); for call in meili_calls { - let SearchInIndexParameters { index_uid, q } = - serde_json::from_str(&call.function.arguments).unwrap(); + let result = match serde_json::from_str(&call.function.arguments) { + Ok(SearchInIndexParameters { index_uid, q }) => process_search_request( + &index_scheduler, + auth_ctrl.clone(), + &search_queue, + &auth_token, + index_uid, + q, + ) + .await + .map_err(|e| e.to_string()), + Err(err) => Err(err.to_string()), + }; - let (_, text) = process_search_request( - &index_scheduler, - auth_ctrl.clone(), - &search_queue, - auth_token, - index_uid, - q, - ) - .await?; + let text = match result { + Ok((_, text)) => text, + Err(err) => err, + }; chat_completion.messages.push(ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { - tool_call_id: call.id, - content: ChatCompletionRequestToolMessageContent::Text(text), + tool_call_id: call.id.clone(), + content: ChatCompletionRequestToolMessageContent::Text(format!( + "{}\n\n{text}", + chat_settings.prompts.pre_query + )), }, )); } @@ -413,7 +422,7 @@ async fn streamed_chat( let is_error = result.is_err(); let text = match result { Ok((_, text)) => text, - Err(err) => err.to_string(), + Err(err) => err, }; let tool = ChatCompletionRequestToolMessage { From c6930c88193aae252bc83a25ce68525626880e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 21 May 2025 11:07:06 +0200 Subject: [PATCH 147/292] Introduce the new index chat settings --- crates/dump/src/reader/compat/v5_to_v6.rs | 1 + crates/meilisearch-types/src/error.rs | 3 +- crates/meilisearch-types/src/settings.rs | 50 +++++++++++++++-- crates/meilisearch/src/routes/chat.rs | 6 +- .../src/routes/indexes/settings.rs | 14 ++++- .../src/routes/indexes/settings_analytics.rs | 21 ++++++- .../meilisearch/src/routes/settings/chat.rs | 10 ++-- crates/milli/src/index.rs | 28 ++++++++++ crates/milli/src/update/chat.rs | 45 +++++++++++++++ crates/milli/src/update/mod.rs | 2 + crates/milli/src/update/settings.rs | 56 ++++++++++++++++++- crates/milli/src/vector/settings.rs | 12 ++++ 12 files changed, 227 insertions(+), 21 deletions(-) create mode 100644 crates/milli/src/update/chat.rs diff --git a/crates/dump/src/reader/compat/v5_to_v6.rs b/crates/dump/src/reader/compat/v5_to_v6.rs index 14570c258..f7bda81c6 100644 --- a/crates/dump/src/reader/compat/v5_to_v6.rs +++ b/crates/dump/src/reader/compat/v5_to_v6.rs @@ -405,6 +405,7 @@ impl From> for v6::Settings { search_cutoff_ms: v6::Setting::NotSet, facet_search: v6::Setting::NotSet, prefix_search: v6::Setting::NotSet, + chat: v6::Setting::NotSet, _kind: std::marker::PhantomData, } } diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 6c547d51e..172656237 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -387,7 +387,8 @@ VectorEmbeddingError , InvalidRequest , BAD_REQUEST ; NotFoundSimilarId , InvalidRequest , BAD_REQUEST ; InvalidDocumentEditionContext , InvalidRequest , BAD_REQUEST ; InvalidDocumentEditionFunctionFilter , InvalidRequest , BAD_REQUEST ; -EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST +EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST ; +InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST } impl ErrorCode for JoinError { diff --git a/crates/meilisearch-types/src/settings.rs b/crates/meilisearch-types/src/settings.rs index edb136567..b2f0c2f5b 100644 --- a/crates/meilisearch-types/src/settings.rs +++ b/crates/meilisearch-types/src/settings.rs @@ -11,6 +11,7 @@ use fst::IntoStreamer; use milli::disabled_typos_terms::DisabledTyposTerms; use milli::index::{IndexEmbeddingConfig, PrefixSearch}; use milli::proximity::ProximityPrecision; +pub use milli::update::ChatSettings; use milli::update::Setting; use milli::{Criterion, CriterionError, FilterableAttributesRule, Index, DEFAULT_VALUES_PER_FACET}; use serde::{Deserialize, Serialize, Serializer}; @@ -199,72 +200,86 @@ pub struct Settings { #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(["id", "title", "description", "url"]))] 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")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(["title", "description"]))] 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")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(["release_date", "genre"]))] pub filterable_attributes: Setting>, + /// Attributes to use when sorting search results. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(["release_date"]))] pub sortable_attributes: Setting>, + /// 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")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!([RankingRuleView::Words, RankingRuleView::Typo, RankingRuleView::Proximity, RankingRuleView::Attribute, RankingRuleView::Exactness]))] pub ranking_rules: Setting>, + /// List of words ignored when present in search queries. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(["the", "a", "them", "their"]))] pub stop_words: Setting>, + /// List of characters not delimiting where one term begins and ends. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!([" ", "\n"]))] pub non_separator_tokens: Setting>, + /// List of characters delimiting where one term begins and ends. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(["S"]))] pub separator_tokens: Setting>, + /// List of strings Meilisearch should parse as a single term. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(["iPhone pro"]))] pub dictionary: Setting>, + /// 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")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>>, example = json!({ "he": ["she", "they", "them"], "phone": ["iPhone", "android"]}))] pub synonyms: Setting>>, + /// Search returns documents with distinct (different) values of the given field. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!("sku"))] pub distinct_attribute: Setting, + /// Precision level when calculating the proximity ranking rule. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!(ProximityPrecisionView::ByAttribute))] pub proximity_precision: Setting, + /// Customize typo tolerance feature. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!({ "enabled": true, "disableOnAttributes": ["title"]}))] pub typo_tolerance: Setting, + /// Faceting settings. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!({ "maxValuesPerFacet": 10, "sortFacetValuesBy": { "genre": FacetValuesSort::Count }}))] pub faceting: Setting, + /// Pagination settings. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] @@ -276,24 +291,34 @@ pub struct Settings { #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>)] pub embedders: Setting>, + /// Maximum duration of a search query. #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!(50))] pub search_cutoff_ms: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option>, example = json!(50))] pub localized_attributes: Setting>, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!(true))] pub facet_search: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!("Hemlo"))] pub prefix_search: Setting, + /// Customize the chat prompting. + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option)] + pub chat: Setting, + #[serde(skip)] #[deserr(skip)] pub _kind: PhantomData, @@ -359,6 +384,7 @@ impl Settings { localized_attributes: Setting::Reset, facet_search: Setting::Reset, prefix_search: Setting::Reset, + chat: Setting::Reset, _kind: PhantomData, } } @@ -385,6 +411,7 @@ impl Settings { localized_attributes: localized_attributes_rules, facet_search, prefix_search, + chat, _kind, } = self; @@ -409,6 +436,7 @@ impl Settings { localized_attributes: localized_attributes_rules, facet_search, prefix_search, + chat, _kind: PhantomData, } } @@ -459,6 +487,7 @@ impl Settings { localized_attributes: self.localized_attributes, facet_search: self.facet_search, prefix_search: self.prefix_search, + chat: self.chat, _kind: PhantomData, } } @@ -533,8 +562,9 @@ impl Settings { Setting::Set(this) } }, - prefix_search: other.prefix_search.or(self.prefix_search), facet_search: other.facet_search.or(self.facet_search), + prefix_search: other.prefix_search.or(self.prefix_search), + chat: other.chat.clone().or(self.chat.clone()), _kind: PhantomData, } } @@ -573,6 +603,7 @@ pub fn apply_settings_to_builder( localized_attributes: localized_attributes_rules, facet_search, prefix_search, + chat, _kind, } = settings; @@ -783,6 +814,12 @@ pub fn apply_settings_to_builder( Setting::Reset => builder.reset_facet_search(), Setting::NotSet => (), } + + match chat { + Setting::Set(chat) => builder.set_chat(chat.clone()), + Setting::Reset => builder.reset_chat(), + Setting::NotSet => (), + } } pub enum SecretPolicy { @@ -880,14 +917,11 @@ pub fn settings( }) .collect(); let embedders = Setting::Set(embedders); - let search_cutoff_ms = index.search_cutoff(rtxn)?; - let localized_attributes_rules = index.localized_attributes_rules(rtxn)?; - let prefix_search = index.prefix_search(rtxn)?.map(PrefixSearchSettings::from); - let facet_search = index.facet_search(rtxn)?; + let chat = index.chat_config(rtxn).map(ChatSettings::from)?; let mut settings = Settings { displayed_attributes: match displayed_attributes { @@ -925,8 +959,9 @@ pub fn settings( Some(rules) => Setting::Set(rules.into_iter().map(|r| r.into()).collect()), None => Setting::Reset, }, - prefix_search: Setting::Set(prefix_search.unwrap_or_default()), facet_search: Setting::Set(facet_search), + prefix_search: Setting::Set(prefix_search.unwrap_or_default()), + chat: Setting::Set(chat), _kind: PhantomData, }; @@ -1154,6 +1189,7 @@ pub(crate) mod test { search_cutoff_ms: Setting::NotSet, facet_search: Setting::NotSet, prefix_search: Setting::NotSet, + chat: Setting::NotSet, _kind: PhantomData::, }; @@ -1185,6 +1221,8 @@ pub(crate) mod test { search_cutoff_ms: Setting::NotSet, facet_search: Setting::NotSet, prefix_search: Setting::NotSet, + chat: Setting::NotSet, + _kind: PhantomData::, }; diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index b3a67ff10..d85c14c36 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -30,7 +30,7 @@ use serde_json::json; use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; -use super::settings::chat::{ChatPrompts, ChatSettings}; +use super::settings::chat::{ChatPrompts, GlobalChatSettings}; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::{extract_token_from_request, GuardedData, Policy as _}; use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; @@ -216,7 +216,7 @@ async fn non_streamed_chat( let chat_settings = match index_scheduler.chat_settings().unwrap() { Some(value) => serde_json::from_value(value).unwrap(), - None => ChatSettings::default(), + None => GlobalChatSettings::default(), }; let mut config = OpenAIConfig::default(); @@ -307,7 +307,7 @@ async fn streamed_chat( let chat_settings = match index_scheduler.chat_settings().unwrap() { Some(value) => serde_json::from_value(value).unwrap(), - None => ChatSettings::default(), + None => GlobalChatSettings::default(), }; let mut config = OpenAIConfig::default(); diff --git a/crates/meilisearch/src/routes/indexes/settings.rs b/crates/meilisearch/src/routes/indexes/settings.rs index 92b018c8c..a35ae5136 100644 --- a/crates/meilisearch/src/routes/indexes/settings.rs +++ b/crates/meilisearch/src/routes/indexes/settings.rs @@ -6,7 +6,7 @@ use meilisearch_types::deserr::DeserrJsonError; use meilisearch_types::error::ResponseError; use meilisearch_types::index_uid::IndexUid; use meilisearch_types::settings::{ - settings, SecretPolicy, SettingEmbeddingSettings, Settings, Unchecked, + settings, ChatSettings, SecretPolicy, SettingEmbeddingSettings, Settings, Unchecked, }; use meilisearch_types::tasks::KindWithContent; use tracing::debug; @@ -508,6 +508,17 @@ make_setting_routes!( camelcase_attr: "prefixSearch", analytics: PrefixSearchAnalytics }, + { + route: "/chat", + update_verb: put, + value_type: ChatSettings, + err_type: meilisearch_types::deserr::DeserrJsonError< + meilisearch_types::error::deserr_codes::InvalidSettingsIndexChat, + >, + attr: chat, + camelcase_attr: "chat", + analytics: ChatAnalytics + }, ); #[utoipa::path( @@ -597,6 +608,7 @@ pub async fn update_all( ), facet_search: FacetSearchAnalytics::new(new_settings.facet_search.as_ref().set()), prefix_search: PrefixSearchAnalytics::new(new_settings.prefix_search.as_ref().set()), + chat: ChatAnalytics::new(new_settings.chat.as_ref().set()), }, &req, ); diff --git a/crates/meilisearch/src/routes/indexes/settings_analytics.rs b/crates/meilisearch/src/routes/indexes/settings_analytics.rs index 41df91966..1b8d0e244 100644 --- a/crates/meilisearch/src/routes/indexes/settings_analytics.rs +++ b/crates/meilisearch/src/routes/indexes/settings_analytics.rs @@ -10,8 +10,8 @@ use meilisearch_types::locales::{Locale, LocalizedAttributesRuleView}; use meilisearch_types::milli::update::Setting; use meilisearch_types::milli::FilterableAttributesRule; use meilisearch_types::settings::{ - FacetingSettings, PaginationSettings, PrefixSearchSettings, ProximityPrecisionView, - RankingRuleView, SettingEmbeddingSettings, TypoSettings, + ChatSettings, FacetingSettings, PaginationSettings, PrefixSearchSettings, + ProximityPrecisionView, RankingRuleView, SettingEmbeddingSettings, TypoSettings, }; use serde::Serialize; @@ -39,6 +39,7 @@ pub struct SettingsAnalytics { pub non_separator_tokens: NonSeparatorTokensAnalytics, pub facet_search: FacetSearchAnalytics, pub prefix_search: PrefixSearchAnalytics, + pub chat: ChatAnalytics, } impl Aggregate for SettingsAnalytics { @@ -198,6 +199,7 @@ impl Aggregate for SettingsAnalytics { set: new.prefix_search.set | self.prefix_search.set, value: new.prefix_search.value.or(self.prefix_search.value), }, + chat: ChatAnalytics { set: new.chat.set | self.chat.set }, }) } @@ -676,3 +678,18 @@ impl PrefixSearchAnalytics { SettingsAnalytics { prefix_search: self, ..Default::default() } } } + +#[derive(Serialize, Default)] +pub struct ChatAnalytics { + pub set: bool, +} + +impl ChatAnalytics { + pub fn new(settings: Option<&ChatSettings>) -> Self { + Self { set: settings.is_some() } + } + + pub fn into_settings(self) -> SettingsAnalytics { + SettingsAnalytics { chat: self, ..Default::default() } + } +} diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/settings/chat.rs index d8be27ab3..a971ad102 100644 --- a/crates/meilisearch/src/routes/settings/chat.rs +++ b/crates/meilisearch/src/routes/settings/chat.rs @@ -27,7 +27,7 @@ async fn get_settings( ) -> Result { let settings = match index_scheduler.chat_settings()? { Some(value) => serde_json::from_value(value).unwrap(), - None => ChatSettings::default(), + None => GlobalChatSettings::default(), }; Ok(HttpResponse::Ok().json(settings)) } @@ -37,7 +37,7 @@ async fn patch_settings( ActionPolicy<{ actions::CHAT_SETTINGS_UPDATE }>, Data, >, - web::Json(chat_settings): web::Json, + web::Json(chat_settings): web::Json, ) -> Result { let chat_settings = serde_json::to_value(chat_settings).unwrap(); index_scheduler.put_chat_settings(&chat_settings)?; @@ -46,7 +46,7 @@ async fn patch_settings( #[derive(Debug, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] -pub struct ChatSettings { +pub struct GlobalChatSettings { pub source: String, pub base_api: Option, pub api_key: Option, @@ -91,9 +91,9 @@ const DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION: &str = "The name of the index to search within. An index is a collection of documents organized for search. \ Selecting the right index ensures the most relevant results for the user query"; -impl Default for ChatSettings { +impl Default for GlobalChatSettings { fn default() -> Self { - ChatSettings { + GlobalChatSettings { source: "openai".to_string(), base_api: None, api_key: None, diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index d0cd5c862..a5145cb0b 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -23,6 +23,7 @@ use crate::heed_codec::facet::{ use crate::heed_codec::version::VersionCodec; use crate::heed_codec::{BEU16StrCodec, FstSetCodec, StrBEU16Codec, StrRefCodec}; use crate::order_by_map::OrderByMap; +use crate::prompt::PromptData; use crate::proximity::ProximityPrecision; use crate::vector::{ArroyStats, ArroyWrapper, Embedding, EmbeddingConfig}; use crate::{ @@ -79,6 +80,7 @@ pub mod main_key { pub const PREFIX_SEARCH: &str = "prefix_search"; pub const DOCUMENTS_STATS: &str = "documents_stats"; pub const DISABLED_TYPOS_TERMS: &str = "disabled_typos_terms"; + pub const CHAT: &str = "chat"; } pub mod db_name { @@ -1691,6 +1693,25 @@ impl Index { self.main.remap_key_type::().delete(txn, main_key::FACET_SEARCH) } + pub fn chat_config(&self, txn: &RoTxn<'_>) -> heed::Result { + self.main + .remap_types::>() + .get(txn, main_key::CHAT) + .map(|o| o.unwrap_or_default()) + } + + pub(crate) fn put_chat_config( + &self, + txn: &mut RwTxn<'_>, + val: &ChatConfig, + ) -> heed::Result<()> { + self.main.remap_types::>().put(txn, main_key::CHAT, &val) + } + + pub(crate) fn delete_chat_config(&self, txn: &mut RwTxn<'_>) -> heed::Result { + self.main.remap_key_type::().delete(txn, main_key::CHAT) + } + pub fn localized_attributes_rules( &self, rtxn: &RoTxn<'_>, @@ -1917,6 +1938,13 @@ pub struct IndexEmbeddingConfig { pub user_provided: RoaringBitmap, } +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct ChatConfig { + pub description: String, + /// Contains the document template and max template length. + pub prompt: PromptData, +} + #[derive(Debug, Deserialize, Serialize)] pub struct PrefixSettings { pub prefix_count_threshold: usize, diff --git a/crates/milli/src/update/chat.rs b/crates/milli/src/update/chat.rs new file mode 100644 index 000000000..44e646f6d --- /dev/null +++ b/crates/milli/src/update/chat.rs @@ -0,0 +1,45 @@ +use deserr::Deserr; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +use crate::index::ChatConfig; +use crate::prompt::{default_max_bytes, PromptData}; +use crate::update::Setting; + +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +#[deserr(deny_unknown_fields, rename_all = camelCase)] +pub struct ChatSettings { + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub description: Setting, + + /// A liquid template used to render documents to a text that can be embedded. + /// + /// Meillisearch interpolates the template for each document and sends the resulting text to the embedder. + /// The embedder then generates document vectors based on this text. + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub document_template: Setting, + + /// Rendered texts are truncated to this size. Defaults to 400. + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub document_template_max_bytes: Setting, +} + +impl From for ChatSettings { + fn from(config: ChatConfig) -> Self { + let ChatConfig { description, prompt: PromptData { template, max_bytes } } = config; + ChatSettings { + description: Setting::Set(description), + document_template: Setting::Set(template), + document_template_max_bytes: Setting::Set( + max_bytes.unwrap_or(default_max_bytes()).get(), + ), + } + } +} diff --git a/crates/milli/src/update/mod.rs b/crates/milli/src/update/mod.rs index 9a783ffd2..5acb00113 100644 --- a/crates/milli/src/update/mod.rs +++ b/crates/milli/src/update/mod.rs @@ -1,4 +1,5 @@ pub use self::available_ids::AvailableIds; +pub use self::chat::ChatSettings; pub use self::clear_documents::ClearDocuments; pub use self::concurrent_available_ids::ConcurrentAvailableIds; pub use self::facet::bulk::FacetsUpdateBulk; @@ -13,6 +14,7 @@ pub use self::words_prefix_integer_docids::WordPrefixIntegerDocids; pub use self::words_prefixes_fst::WordsPrefixesFst; mod available_ids; +mod chat; mod clear_documents; mod concurrent_available_ids; pub(crate) mod del_add; diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index fce2989b1..697bf8168 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -13,7 +13,7 @@ use time::OffsetDateTime; use super::del_add::{DelAdd, DelAddOperation}; use super::index_documents::{IndexDocumentsConfig, Transform}; -use super::IndexerConfig; +use super::{ChatSettings, IndexerConfig}; use crate::attribute_patterns::PatternMatch; use crate::constants::RESERVED_GEO_FIELD_NAME; use crate::criterion::Criterion; @@ -22,11 +22,11 @@ use crate::error::UserError; use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder}; use crate::filterable_attributes_rules::match_faceted_field; use crate::index::{ - IndexEmbeddingConfig, PrefixSearch, DEFAULT_MIN_WORD_LEN_ONE_TYPO, + ChatConfig, IndexEmbeddingConfig, PrefixSearch, DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS, }; use crate::order_by_map::OrderByMap; -use crate::prompt::default_max_bytes; +use crate::prompt::{default_max_bytes, PromptData}; use crate::proximity::ProximityPrecision; use crate::update::index_documents::IndexDocumentsMethod; use crate::update::{IndexDocuments, UpdateIndexingStep}; @@ -185,6 +185,7 @@ pub struct Settings<'a, 't, 'i> { localized_attributes_rules: Setting>, prefix_search: Setting, facet_search: Setting, + chat: Setting, } impl<'a, 't, 'i> Settings<'a, 't, 'i> { @@ -223,6 +224,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { localized_attributes_rules: Setting::NotSet, prefix_search: Setting::NotSet, facet_search: Setting::NotSet, + chat: Setting::NotSet, indexer_config, } } @@ -453,6 +455,14 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { self.facet_search = Setting::Reset; } + pub fn set_chat(&mut self, value: ChatSettings) { + self.chat = Setting::Set(value); + } + + pub fn reset_chat(&mut self) { + self.chat = Setting::Reset; + } + #[tracing::instrument( level = "trace" skip(self, progress_callback, should_abort, settings_diff), @@ -1238,6 +1248,45 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { Ok(()) } + fn update_chat_config(&mut self) -> heed::Result { + match &mut self.chat { + Setting::Set(ChatSettings { + description: new_description, + document_template: new_document_template, + document_template_max_bytes: new_document_template_max_bytes, + }) => { + let mut old = self.index.chat_config(self.wtxn)?; + let ChatConfig { + ref mut description, + prompt: PromptData { ref mut template, ref mut max_bytes }, + } = old; + + match new_description { + Setting::Set(d) => *description = d.clone(), + Setting::Reset => *description = Default::default(), + Setting::NotSet => (), + } + + match new_document_template { + Setting::Set(dt) => *template = dt.clone(), + Setting::Reset => *template = Default::default(), + Setting::NotSet => (), + } + + match new_document_template_max_bytes { + Setting::Set(m) => *max_bytes = NonZeroUsize::new(*m), + Setting::Reset => *max_bytes = Some(default_max_bytes()), + Setting::NotSet => (), + } + + self.index.put_chat_config(self.wtxn, &old)?; + Ok(true) + } + Setting::Reset => self.index.delete_chat_config(self.wtxn), + Setting::NotSet => Ok(false), + } + } + pub fn execute(mut self, progress_callback: FP, should_abort: FA) -> Result<()> where FP: Fn(UpdateIndexingStep) + Sync, @@ -1275,6 +1324,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { self.update_facet_search()?; self.update_localized_attributes_rules()?; self.update_disabled_typos_terms()?; + self.update_chat_config()?; let embedding_config_updates = self.update_embedding_configs()?; diff --git a/crates/milli/src/vector/settings.rs b/crates/milli/src/vector/settings.rs index 3948ad4d8..712c1faa5 100644 --- a/crates/milli/src/vector/settings.rs +++ b/crates/milli/src/vector/settings.rs @@ -33,6 +33,7 @@ pub struct EmbeddingSettings { /// /// - Defaults to `openAi` pub source: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -55,6 +56,7 @@ pub struct EmbeddingSettings { /// - For source `openAi`, defaults to `text-embedding-3-small` /// - For source `huggingFace`, defaults to `BAAI/bge-base-en-v1.5` pub model: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -75,6 +77,7 @@ pub struct EmbeddingSettings { /// - When `model` is set to default, defaults to `617ca489d9e86b49b8167676d8220688b99db36e` /// - Otherwise, defaults to `null` pub revision: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -96,6 +99,7 @@ pub struct EmbeddingSettings { /// /// - Embedders created before this parameter was available default to `forceMean` to preserve the existing behavior. pub pooling: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -118,6 +122,7 @@ pub struct EmbeddingSettings { /// /// - This setting is partially hidden when returned by the settings pub api_key: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -141,6 +146,7 @@ pub struct EmbeddingSettings { /// - For source `openAi`, the dimensions is the maximum allowed by the model. /// - For sources `ollama` and `rest`, the dimensions are inferred by embedding a sample text. pub dimensions: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -167,6 +173,7 @@ pub struct EmbeddingSettings { /// first enabling it. If you are unsure of whether the performance-relevancy tradeoff is right for you, /// we recommend to use this parameter on a test index first. pub binary_quantized: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -183,6 +190,7 @@ pub struct EmbeddingSettings { /// /// - 🏗️ When modified, embeddings are regenerated for documents whose rendering through the template produces a different text. pub document_template: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -201,6 +209,7 @@ pub struct EmbeddingSettings { /// /// - Defaults to 400 pub document_template_max_bytes: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -219,6 +228,7 @@ pub struct EmbeddingSettings { /// - 🌱 When modified for source `openAi`, embeddings are never regenerated /// - 🏗️ When modified for sources `ollama` and `rest`, embeddings are always regenerated pub url: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -236,6 +246,7 @@ pub struct EmbeddingSettings { /// /// - 🏗️ Changing the value of this parameter always regenerates embeddings pub request: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option)] @@ -253,6 +264,7 @@ pub struct EmbeddingSettings { /// /// - 🏗️ Changing the value of this parameter always regenerates embeddings pub response: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option>)] From 75c3f33478ca111243a7cb124e5dc91241d6d3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 21 May 2025 15:32:34 +0200 Subject: [PATCH 148/292] Correctly support document templates on the chat API --- Cargo.lock | 1 + crates/meilisearch/Cargo.toml | 1 + crates/meilisearch/src/routes/chat.rs | 100 +++++++++++------- .../meilisearch/src/routes/settings/chat.rs | 4 - crates/meilisearch/src/search/mod.rs | 2 +- crates/milli/src/external_documents_ids.rs | 4 +- crates/milli/src/fields_ids_map.rs | 1 + crates/milli/src/lib.rs | 11 +- 8 files changed, 72 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd47ee94c..4a21d2ab6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3684,6 +3684,7 @@ dependencies = [ "brotli 6.0.0", "bstr", "build-info", + "bumpalo", "byte-unit", "bytes", "cargo_toml", diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index 398b62dad..62f7cfa0a 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -32,6 +32,7 @@ async-trait = "0.1.85" bstr = "1.11.3" byte-unit = { version = "5.1.6", features = ["serde"] } bytes = "1.9.0" +bumpalo = "3.16.0" clap = { version = "4.5.24", features = ["derive", "env"] } crossbeam-channel = "0.5.15" deserr = { version = "0.6.3", features = ["actix-web"] } diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index d85c14c36..c34bbcaea 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -1,5 +1,7 @@ +use std::cell::RefCell; use std::collections::HashMap; use std::mem; +use std::sync::RwLock; use std::time::Duration; use actix_web::web::{self, Data}; @@ -16,27 +18,33 @@ use async_openai::types::{ FunctionObjectArgs, }; use async_openai::Client; +use bumpalo::Bump; use futures::StreamExt; use index_scheduler::IndexScheduler; use meilisearch_auth::AuthController; use meilisearch_types::error::ResponseError; +use meilisearch_types::heed::RoTxn; use meilisearch_types::keys::actions; -use meilisearch_types::milli::index::IndexEmbeddingConfig; -use meilisearch_types::milli::prompt::PromptData; -use meilisearch_types::milli::vector::EmbeddingConfig; -use meilisearch_types::{Document, Index}; -use serde::{Deserialize, Serialize}; +use meilisearch_types::milli::index::ChatConfig; +use meilisearch_types::milli::prompt::{Prompt, PromptData}; +use meilisearch_types::milli::update::new::document::DocumentFromDb; +use meilisearch_types::milli::{ + DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, MetadataBuilder, TimeBudget, +}; +use meilisearch_types::Index; +use serde::Deserialize; use serde_json::json; use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; use super::settings::chat::{ChatPrompts, GlobalChatSettings}; +use crate::error::MeilisearchHttpError; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::{extract_token_from_request, GuardedData, Policy as _}; use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; use crate::routes::indexes::search::search_kind; use crate::search::{ - add_search_rules, perform_search, HybridQuery, RetrieveVectors, SearchQuery, SemanticRatio, + add_search_rules, prepare_search, search_from_kind, HybridQuery, SearchQuery, SemanticRatio, }; use crate::search_queue::SearchQueue; @@ -175,15 +183,22 @@ async fn process_search_request( let permit = search_queue.try_get_search_permit().await?; let features = index_scheduler.features(); let index_cloned = index.clone(); - let search_result = tokio::task::spawn_blocking(move || { - perform_search( - index_uid.to_string(), - &index_cloned, - query, - search_kind, - RetrieveVectors::new(false), - features, - ) + let search_result = tokio::task::spawn_blocking(move || -> Result<_, ResponseError> { + let rtxn = index_cloned.read_txn()?; + let time_budget = match index_cloned + .search_cutoff(&rtxn) + .map_err(|e| MeilisearchHttpError::from_milli(e, Some(index_uid.clone())))? + { + Some(cutoff) => TimeBudget::new(Duration::from_millis(cutoff)), + None => TimeBudget::default(), + }; + + let (search, _is_finite_pagination, _max_total_hits, _offset) = + prepare_search(&index_cloned, &rtxn, &query, &search_kind, time_budget, features)?; + + search_from_kind(index_uid, search_kind, search) + .map(|(search_results, _)| search_results) + .map_err(ResponseError::from) }) .await; permit.drop().await; @@ -198,9 +213,11 @@ async fn process_search_request( // analytics.publish(aggregate, &req); let search_result = search_result?; - let formatted = - format_documents(&index, search_result.hits.into_iter().map(|doc| doc.document)); + let rtxn = index.read_txn()?; + let render_alloc = Bump::new(); + let formatted = format_documents(&rtxn, &index, &render_alloc, search_result.documents_ids)?; let text = formatted.join("\n"); + drop(rtxn); Ok((index, text)) } @@ -506,31 +523,36 @@ struct SearchInIndexParameters { q: Option, } -fn format_documents(index: &Index, documents: impl Iterator) -> Vec { - let rtxn = index.read_txn().unwrap(); - let IndexEmbeddingConfig { name: _, config, user_provided: _ } = index - .embedding_configs(&rtxn) - .unwrap() +fn format_documents<'t, 'doc>( + rtxn: &RoTxn<'t>, + index: &Index, + doc_alloc: &'doc Bump, + internal_docids: Vec, +) -> Result, ResponseError> { + let ChatConfig { prompt: PromptData { template, max_bytes }, .. } = index.chat_config(rtxn)?; + + let prompt = Prompt::new(template, max_bytes).unwrap(); + let fid_map = index.fields_ids_map(rtxn)?; + let metadata_builder = MetadataBuilder::from_index(index, rtxn)?; + let fid_map_with_meta = FieldIdMapWithMetadata::new(fid_map.clone(), metadata_builder); + let global = RwLock::new(fid_map_with_meta); + let gfid_map = RefCell::new(GlobalFieldsIdsMap::new(&global)); + + let external_ids: Vec = index + .external_id_of(rtxn, internal_docids.iter().copied())? .into_iter() - .find(|conf| conf.name == EMBEDDER_NAME) - .unwrap(); + .collect::>()?; - let EmbeddingConfig { - embedder_options: _, - prompt: PromptData { template, max_bytes: _ }, - quantized: _, - } = config; + let mut renders = Vec::new(); + for (docid, external_docid) in internal_docids.into_iter().zip(external_ids) { + let document = match DocumentFromDb::new(docid, rtxn, index, &fid_map)? { + Some(doc) => doc, + None => continue, + }; - #[derive(Serialize)] - struct Doc { - doc: T, + let text = prompt.render_document(&external_docid, document, &gfid_map, doc_alloc).unwrap(); + renders.push(text); } - let template = liquid::ParserBuilder::with_stdlib().build().unwrap().parse(&template).unwrap(); - documents - .map(|doc| { - let object = liquid::to_object(&Doc { doc }).unwrap(); - template.render(&object).unwrap() - }) - .collect() + Ok(renders) } diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/settings/chat.rs index a971ad102..586fa041e 100644 --- a/crates/meilisearch/src/routes/settings/chat.rs +++ b/crates/meilisearch/src/routes/settings/chat.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeMap; - use actix_web::web::{self, Data}; use actix_web::HttpResponse; use index_scheduler::IndexScheduler; @@ -51,7 +49,6 @@ pub struct GlobalChatSettings { pub base_api: Option, pub api_key: Option, pub prompts: ChatPrompts, - pub indexes: BTreeMap, } #[derive(Debug, Serialize, Deserialize)] @@ -105,7 +102,6 @@ impl Default for GlobalChatSettings { .to_string(), pre_query: "".to_string(), }, - indexes: BTreeMap::new(), } } } diff --git a/crates/meilisearch/src/search/mod.rs b/crates/meilisearch/src/search/mod.rs index 1dd16c474..16d04cd58 100644 --- a/crates/meilisearch/src/search/mod.rs +++ b/crates/meilisearch/src/search/mod.rs @@ -882,7 +882,7 @@ pub fn add_search_rules(filter: &mut Option, rules: IndexSearchRules) { } } -fn prepare_search<'t>( +pub fn prepare_search<'t>( index: &'t Index, rtxn: &'t RoTxn, query: &'t SearchQuery, diff --git a/crates/milli/src/external_documents_ids.rs b/crates/milli/src/external_documents_ids.rs index 755b801ec..598465e5f 100644 --- a/crates/milli/src/external_documents_ids.rs +++ b/crates/milli/src/external_documents_ids.rs @@ -32,13 +32,13 @@ impl ExternalDocumentsIds { &self, rtxn: &RoTxn<'_>, external_id: A, - ) -> heed::Result> { + ) -> heed::Result> { self.0.get(rtxn, external_id.as_ref()) } /// An helper function to debug this type, returns an `HashMap` of both, /// soft and hard fst maps, combined. - pub fn to_hash_map(&self, rtxn: &RoTxn<'_>) -> heed::Result> { + pub fn to_hash_map(&self, rtxn: &RoTxn<'_>) -> heed::Result> { let mut map = HashMap::default(); for result in self.0.iter(rtxn)? { let (external, internal) = result?; diff --git a/crates/milli/src/fields_ids_map.rs b/crates/milli/src/fields_ids_map.rs index 9a016e7bd..d2abd840c 100644 --- a/crates/milli/src/fields_ids_map.rs +++ b/crates/milli/src/fields_ids_map.rs @@ -7,6 +7,7 @@ use crate::FieldId; mod global; pub mod metadata; pub use global::GlobalFieldsIdsMap; +pub use metadata::{FieldIdMapWithMetadata, MetadataBuilder}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FieldsIdsMap { diff --git a/crates/milli/src/lib.rs b/crates/milli/src/lib.rs index 47d3dc75c..504b4c68d 100644 --- a/crates/milli/src/lib.rs +++ b/crates/milli/src/lib.rs @@ -52,18 +52,19 @@ pub use search::new::{ }; use serde_json::Value; pub use thread_pool_no_abort::{PanicCatched, ThreadPoolNoAbort, ThreadPoolNoAbortBuilder}; -pub use {charabia as tokenizer, heed, rhai}; +pub use {arroy, charabia as tokenizer, heed, rhai}; pub use self::asc_desc::{AscDesc, AscDescError, Member, SortError}; -pub use self::attribute_patterns::AttributePatterns; -pub use self::attribute_patterns::PatternMatch; +pub use self::attribute_patterns::{AttributePatterns, PatternMatch}; pub use self::criterion::{default_criteria, Criterion, CriterionError}; pub use self::error::{ Error, FieldIdMapMissingEntry, InternalError, SerializationError, UserError, }; pub use self::external_documents_ids::ExternalDocumentsIds; pub use self::fieldids_weights_map::FieldidsWeightsMap; -pub use self::fields_ids_map::{FieldsIdsMap, GlobalFieldsIdsMap}; +pub use self::fields_ids_map::{ + FieldIdMapWithMetadata, FieldsIdsMap, GlobalFieldsIdsMap, MetadataBuilder, +}; pub use self::filterable_attributes_rules::{ FilterFeatures, FilterableAttributesFeatures, FilterableAttributesPatterns, FilterableAttributesRule, @@ -84,8 +85,6 @@ pub use self::search::{ }; pub use self::update::ChannelCongestion; -pub use arroy; - pub type Result = std::result::Result; pub type Attribute = u32; From 05828ff2c7bc5f7237ab599cb2d6c32557fd842b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 21 May 2025 16:18:37 +0200 Subject: [PATCH 149/292] Always use the frequency matching strategy --- crates/meilisearch/src/routes/chat.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index c34bbcaea..2f434d706 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -44,7 +44,8 @@ use crate::extractors::authentication::{extract_token_from_request, GuardedData, use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; use crate::routes::indexes::search::search_kind; use crate::search::{ - add_search_rules, prepare_search, search_from_kind, HybridQuery, SearchQuery, SemanticRatio, + add_search_rules, prepare_search, search_from_kind, HybridQuery, MatchingStrategy, SearchQuery, + SemanticRatio, }; use crate::search_queue::SearchQueue; @@ -159,6 +160,7 @@ async fn process_search_request( embedder: EMBEDDER_NAME.to_string(), }), limit: 20, + matching_strategy: MatchingStrategy::Frequency, ..Default::default() }; From afb43d266e3a96d00ff91bd4544c024f73be9df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 21 May 2025 16:24:51 +0200 Subject: [PATCH 150/292] Correctly list the chat settings key actions --- crates/meilisearch-types/src/keys.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index dfa50aa1e..1c1ebad5b 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -326,6 +326,9 @@ pub enum Action { #[serde(rename = "chat.get")] #[deserr(rename = "chat.get")] Chat, + #[serde(rename = "chatSettings.*")] + #[deserr(rename = "chatSettings.*")] + ChatSettingsAll, #[serde(rename = "chatSettings.get")] #[deserr(rename = "chatSettings.get")] ChatSettingsGet, @@ -357,6 +360,9 @@ impl Action { SETTINGS_ALL => Some(Self::SettingsAll), SETTINGS_GET => Some(Self::SettingsGet), SETTINGS_UPDATE => Some(Self::SettingsUpdate), + CHAT_SETTINGS_ALL => Some(Self::ChatSettingsAll), + CHAT_SETTINGS_GET => Some(Self::ChatSettingsGet), + CHAT_SETTINGS_UPDATE => Some(Self::ChatSettingsUpdate), STATS_ALL => Some(Self::StatsAll), STATS_GET => Some(Self::StatsGet), METRICS_ALL => Some(Self::MetricsAll), @@ -424,6 +430,7 @@ pub mod actions { pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); pub const CHAT: u8 = Chat.repr(); + pub const CHAT_SETTINGS_ALL: u8 = ChatSettingsAll.repr(); pub const CHAT_SETTINGS_GET: u8 = ChatSettingsGet.repr(); pub const CHAT_SETTINGS_UPDATE: u8 = ChatSettingsUpdate.repr(); } From 79298720917f0d3293fedab781e404fa813f62f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 21 May 2025 21:06:11 +0200 Subject: [PATCH 151/292] Better chat settings management --- crates/meilisearch/src/routes/chat.rs | 31 +++--- .../meilisearch/src/routes/settings/chat.rs | 100 ++++++++++++------ crates/milli/src/update/settings.rs | 9 ++ 3 files changed, 95 insertions(+), 45 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 2f434d706..05512bff3 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -28,6 +28,7 @@ use meilisearch_types::keys::actions; use meilisearch_types::milli::index::ChatConfig; use meilisearch_types::milli::prompt::{Prompt, PromptData}; use meilisearch_types::milli::update::new::document::DocumentFromDb; +use meilisearch_types::milli::update::Setting; use meilisearch_types::milli::{ DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, MetadataBuilder, TimeBudget, }; @@ -107,20 +108,20 @@ fn setup_search_tool( .function( FunctionObjectArgs::default() .name(SEARCH_IN_INDEX_FUNCTION_NAME) - .description(&prompts.search_description) + .description(&prompts.search_description.clone().unwrap()) .parameters(json!({ "type": "object", "properties": { "index_uid": { "type": "string", "enum": index_uids, - "description": prompts.search_index_uid_param, + "description": prompts.search_index_uid_param.clone().unwrap(), }, "q": { // Unfortunately, Mistral does not support an array of types, here. // "type": ["string", "null"], "type": "string", - "description": prompts.search_q_param, + "description": prompts.search_q_param.clone().unwrap(), } }, "required": ["index_uid", "q"], @@ -136,7 +137,9 @@ fn setup_search_tool( chat_completion.messages.insert( 0, ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { - content: ChatCompletionRequestSystemMessageContent::Text(prompts.system.clone()), + content: ChatCompletionRequestSystemMessageContent::Text( + prompts.system.as_ref().unwrap().clone(), + ), name: None, }), ); @@ -239,16 +242,17 @@ async fn non_streamed_chat( }; let mut config = OpenAIConfig::default(); - if let Some(api_key) = chat_settings.api_key.as_ref() { + if let Setting::Set(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - if let Some(base_api) = chat_settings.base_api.as_ref() { + if let Setting::Set(base_api) = chat_settings.base_api.as_ref() { config = config.with_api_base(base_api); } let client = Client::with_config(config); let auth_token = extract_token_from_request(&req)?.unwrap(); - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; + let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; let mut response; loop { @@ -296,7 +300,7 @@ async fn non_streamed_chat( tool_call_id: call.id.clone(), content: ChatCompletionRequestToolMessageContent::Text(format!( "{}\n\n{text}", - chat_settings.prompts.pre_query + chat_settings.prompts.clone().unwrap().pre_query.unwrap() )), }, )); @@ -325,20 +329,21 @@ async fn streamed_chat( let filters = index_scheduler.filters(); let chat_settings = match index_scheduler.chat_settings().unwrap() { - Some(value) => serde_json::from_value(value).unwrap(), + Some(value) => serde_json::from_value(value.clone()).unwrap(), None => GlobalChatSettings::default(), }; let mut config = OpenAIConfig::default(); - if let Some(api_key) = chat_settings.api_key.as_ref() { + if let Setting::Set(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - if let Some(base_api) = chat_settings.base_api.as_ref() { + if let Setting::Set(base_api) = chat_settings.base_api.as_ref() { config = config.with_api_base(base_api); } let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; + let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; let (tx, rx) = tokio::sync::mpsc::channel(10); let _join_handle = Handle::current().spawn(async move { @@ -447,7 +452,7 @@ async fn streamed_chat( let tool = ChatCompletionRequestToolMessage { tool_call_id: call.id.clone(), content: ChatCompletionRequestToolMessageContent::Text( - format!("{}\n\n{text}", chat_settings.prompts.pre_query), + format!("{}\n\n{text}", chat_settings.prompts.as_ref().unwrap().pre_query.as_ref().unwrap()), ), }; diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/settings/chat.rs index 586fa041e..42fb456b8 100644 --- a/crates/meilisearch/src/routes/settings/chat.rs +++ b/crates/meilisearch/src/routes/settings/chat.rs @@ -3,6 +3,7 @@ use actix_web::HttpResponse; use index_scheduler::IndexScheduler; use meilisearch_types::error::ResponseError; use meilisearch_types::keys::actions; +use meilisearch_types::milli::update::Setting; use serde::{Deserialize, Serialize}; use crate::extractors::authentication::policies::ActionPolicy; @@ -35,37 +36,63 @@ async fn patch_settings( ActionPolicy<{ actions::CHAT_SETTINGS_UPDATE }>, Data, >, - web::Json(chat_settings): web::Json, + web::Json(new): web::Json, ) -> Result { - let chat_settings = serde_json::to_value(chat_settings).unwrap(); - index_scheduler.put_chat_settings(&chat_settings)?; + let old = match index_scheduler.chat_settings()? { + Some(value) => serde_json::from_value(value).unwrap(), + None => GlobalChatSettings::default(), + }; + + let settings = GlobalChatSettings { + source: new.source.or(old.source), + base_api: new.base_api.clone().or(old.base_api), + api_key: new.api_key.clone().or(old.api_key), + prompts: match (new.prompts, old.prompts) { + (Setting::NotSet, set) | (set, Setting::NotSet) => set, + (Setting::Set(_) | Setting::Reset, Setting::Reset) => Setting::Reset, + (Setting::Reset, Setting::Set(set)) => Setting::Set(set), + // If both are set we must merge the prompts settings + (Setting::Set(new), Setting::Set(old)) => Setting::Set(ChatPrompts { + system: new.system.or(old.system), + search_description: new.search_description.or(old.search_description), + search_q_param: new.search_q_param.or(old.search_q_param), + search_index_uid_param: new.search_index_uid_param.or(old.search_index_uid_param), + pre_query: new.pre_query.or(old.pre_query), + }), + }, + }; + + let value = serde_json::to_value(settings).unwrap(); + index_scheduler.put_chat_settings(&value)?; Ok(HttpResponse::Ok().finish()) } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct GlobalChatSettings { - pub source: String, - pub base_api: Option, - pub api_key: Option, - pub prompts: ChatPrompts, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub source: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub base_api: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub api_key: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub prompts: Setting, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct ChatPrompts { - pub system: String, - pub search_description: String, - pub search_q_param: String, - pub search_index_uid_param: String, - pub pre_query: String, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub struct ChatIndexSettings { - pub description: String, - pub document_template: String, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub system: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub search_description: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub search_q_param: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub search_index_uid_param: Setting, + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + pub pre_query: Setting, } const DEFAULT_SYSTEM_MESSAGE: &str = "You are a highly capable research assistant with access to powerful search tools. IMPORTANT INSTRUCTIONS:\ @@ -91,17 +118,26 @@ Selecting the right index ensures the most relevant results for the user query"; impl Default for GlobalChatSettings { fn default() -> Self { GlobalChatSettings { - source: "openai".to_string(), - base_api: None, - api_key: None, - prompts: ChatPrompts { - system: DEFAULT_SYSTEM_MESSAGE.to_string(), - search_description: DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION.to_string(), - search_q_param: DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION.to_string(), - search_index_uid_param: DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION - .to_string(), - pre_query: "".to_string(), - }, + source: Setting::Set("openAi".to_string()), + base_api: Setting::NotSet, + api_key: Setting::NotSet, + prompts: Setting::Set(ChatPrompts::default()), + } + } +} + +impl Default for ChatPrompts { + fn default() -> Self { + ChatPrompts { + system: Setting::Set(DEFAULT_SYSTEM_MESSAGE.to_string()), + search_description: Setting::Set(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION.to_string()), + search_q_param: Setting::Set( + DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION.to_string(), + ), + search_index_uid_param: Setting::Set( + DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION.to_string(), + ), + pre_query: Setting::Set(Default::default()), } } } diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index 697bf8168..bba8bc758 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -123,6 +123,15 @@ impl Setting { *self = new; true } + + #[track_caller] + pub fn unwrap(self) -> T { + match self { + Setting::Set(value) => value, + Setting::Reset => panic!("Setting::Reset unwrapped"), + Setting::NotSet => panic!("Setting::NotSet unwrapped"), + } + } } impl Serialize for Setting { From 3e53527bff022ab67c628b19c20adfccb3df2ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 21 May 2025 21:18:18 +0200 Subject: [PATCH 152/292] redact the chat settings API key --- .../meilisearch/src/routes/settings/chat.rs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/settings/chat.rs index 42fb456b8..09d476008 100644 --- a/crates/meilisearch/src/routes/settings/chat.rs +++ b/crates/meilisearch/src/routes/settings/chat.rs @@ -24,10 +24,11 @@ async fn get_settings( Data, >, ) -> Result { - let settings = match index_scheduler.chat_settings()? { + let mut settings = match index_scheduler.chat_settings()? { Some(value) => serde_json::from_value(value).unwrap(), None => GlobalChatSettings::default(), }; + settings.hide_secrets(); Ok(HttpResponse::Ok().json(settings)) } @@ -80,6 +81,33 @@ pub struct GlobalChatSettings { pub prompts: Setting, } +impl GlobalChatSettings { + pub fn hide_secrets(&mut self) { + match &mut self.api_key { + Setting::Set(key) => Self::hide_secret(key), + Setting::Reset => (), + Setting::NotSet => (), + } + } + + fn hide_secret(secret: &mut String) { + match secret.len() { + x if x < 10 => { + secret.replace_range(.., "XXX..."); + } + x if x < 20 => { + secret.replace_range(2.., "XXXX..."); + } + x if x < 30 => { + secret.replace_range(3.., "XXXXX..."); + } + _x => { + secret.replace_range(5.., "XXXXXX..."); + } + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct ChatPrompts { From 7b74810b03fd86f5179f4ef8b3d1e2e438608f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 22 May 2025 10:40:43 +0200 Subject: [PATCH 153/292] Add the index descriptions to the function description --- crates/meilisearch/src/routes/chat.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 05512bff3..0f50aafac 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::collections::HashMap; +use std::fmt::Write as _; use std::mem; use std::sync::RwLock; use std::time::Duration; @@ -97,18 +98,29 @@ fn setup_search_tool( panic!("{SEARCH_IN_INDEX_FUNCTION_NAME} function already set"); } - let index_uids: Vec<_> = index_scheduler - .index_names()? - .into_iter() - .filter(|index_uid| filters.is_index_authorized(&index_uid)) - .collect(); + let mut index_uids = Vec::new(); + let mut function_description = prompts.search_description.clone().unwrap(); + index_scheduler.try_for_each_index::<_, ()>(|name, index| { + // Make sure to skip unauthorized indexes + if !filters.is_index_authorized(&name) { + return Ok(()); + } + + let rtxn = index.read_txn()?; + let chat_config = index.chat_config(&rtxn)?; + let index_description = chat_config.description; + let _ = writeln!(&mut function_description, "\n\n - {name}: {index_description}\n"); + index_uids.push(name.to_string()); + + Ok(()) + })?; let tool = ChatCompletionToolArgs::default() .r#type(ChatCompletionToolType::Function) .function( FunctionObjectArgs::default() .name(SEARCH_IN_INDEX_FUNCTION_NAME) - .description(&prompts.search_description.clone().unwrap()) + .description(&function_description) .parameters(json!({ "type": "object", "properties": { From 036a9d5dbc27a5664d781634c677be70b320758c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 22 May 2025 10:42:36 +0200 Subject: [PATCH 154/292] Expose a well defined set of sources --- crates/meilisearch/src/routes/settings/chat.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/settings/chat.rs index 09d476008..60fd01ab6 100644 --- a/crates/meilisearch/src/routes/settings/chat.rs +++ b/crates/meilisearch/src/routes/settings/chat.rs @@ -68,11 +68,17 @@ async fn patch_settings( Ok(HttpResponse::Ok().finish()) } +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub enum ChatSource { + OpenAi, +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct GlobalChatSettings { #[serde(default, skip_serializing_if = "Setting::is_not_set")] - pub source: Setting, + pub source: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub base_api: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] @@ -146,7 +152,7 @@ Selecting the right index ensures the most relevant results for the user query"; impl Default for GlobalChatSettings { fn default() -> Self { GlobalChatSettings { - source: Setting::Set("openAi".to_string()), + source: Setting::NotSet, base_api: Setting::NotSet, api_key: Setting::NotSet, prompts: Setting::Set(ChatPrompts::default()), From 33dfd422dbe6f0822b3c768e771dabb347562922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 22 May 2025 15:34:49 +0200 Subject: [PATCH 155/292] Introduce a lot of search parameters and make Deserr happy --- crates/meilisearch-auth/src/lib.rs | 1 + crates/meilisearch-types/src/deserr/mod.rs | 18 +- crates/meilisearch-types/src/settings.rs | 2 +- crates/meilisearch-types/src/task_view.rs | 4 +- crates/meilisearch-types/src/tasks.rs | 2 +- crates/meilisearch/src/routes/chat.rs | 65 ++++-- crates/meilisearch/src/search/mod.rs | 5 +- crates/milli/src/index.rs | 43 +++- crates/milli/src/update/chat.rs | 222 ++++++++++++++++++++- crates/milli/src/update/settings.rs | 86 +++++++- 10 files changed, 411 insertions(+), 37 deletions(-) diff --git a/crates/meilisearch-auth/src/lib.rs b/crates/meilisearch-auth/src/lib.rs index d72ba386c..a19ad7b8c 100644 --- a/crates/meilisearch-auth/src/lib.rs +++ b/crates/meilisearch-auth/src/lib.rs @@ -165,6 +165,7 @@ impl AuthController { } } +#[derive(Debug)] pub struct AuthFilter { search_rules: Option, key_authorized_indexes: SearchRules, diff --git a/crates/meilisearch-types/src/deserr/mod.rs b/crates/meilisearch-types/src/deserr/mod.rs index f5ad18d5c..f1470c201 100644 --- a/crates/meilisearch-types/src/deserr/mod.rs +++ b/crates/meilisearch-types/src/deserr/mod.rs @@ -4,9 +4,12 @@ use std::marker::PhantomData; use std::ops::ControlFlow; use deserr::errors::{JsonError, QueryParamError}; -use deserr::{take_cf_content, DeserializeError, IntoValue, MergeWithError, ValuePointerRef}; +use deserr::{ + take_cf_content, DeserializeError, Deserr, IntoValue, MergeWithError, ValuePointerRef, +}; +use milli::update::ChatSettings; -use crate::error::deserr_codes::*; +use crate::error::deserr_codes::{self, *}; use crate::error::{ Code, DeserrParseBoolError, DeserrParseIntError, ErrorCode, InvalidTaskDateError, ParseOffsetDateTimeError, @@ -33,6 +36,7 @@ pub struct DeserrError { pub code: Code, _phantom: PhantomData<(Format, C)>, } + impl DeserrError { pub fn new(msg: String, code: Code) -> Self { Self { msg, code, _phantom: PhantomData } @@ -117,6 +121,16 @@ impl DeserializeError for DeserrQueryParamError { } } +impl Deserr> for ChatSettings { + fn deserialize_from_value( + value: deserr::Value, + location: ValuePointerRef, + ) -> Result> { + Deserr::::deserialize_from_value(value, location) + .map_err(|e| DeserrError::new(e.to_string(), InvalidSettingsIndexChat.error_code())) + } +} + pub fn immutable_field_error(field: &str, accepted: &[&str], code: Code) -> DeserrJsonError { let msg = format!( "Immutable field `{field}`: expected one of {}", diff --git a/crates/meilisearch-types/src/settings.rs b/crates/meilisearch-types/src/settings.rs index b2f0c2f5b..d26c575d6 100644 --- a/crates/meilisearch-types/src/settings.rs +++ b/crates/meilisearch-types/src/settings.rs @@ -186,7 +186,7 @@ impl Deserr for SettingEmbeddingSettings { /// 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 /// call to `check` will return a `Settings` from a `Settings`. -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)] +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Deserr, ToSchema)] #[serde( deny_unknown_fields, rename_all = "camelCase", diff --git a/crates/meilisearch-types/src/task_view.rs b/crates/meilisearch-types/src/task_view.rs index 7a6faee39..86a00426b 100644 --- a/crates/meilisearch-types/src/task_view.rs +++ b/crates/meilisearch-types/src/task_view.rs @@ -8,7 +8,7 @@ use crate::error::ResponseError; use crate::settings::{Settings, Unchecked}; use crate::tasks::{serialize_duration, Details, IndexSwap, Kind, Status, Task, TaskId}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[derive(Debug, Clone, PartialEq, Serialize, ToSchema)] #[serde(rename_all = "camelCase")] #[schema(rename_all = "camelCase")] pub struct TaskView { @@ -67,7 +67,7 @@ impl TaskView { } } -#[derive(Default, Debug, PartialEq, Eq, Clone, Serialize, Deserialize, ToSchema)] +#[derive(Default, Debug, PartialEq, Clone, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] #[schema(rename_all = "camelCase")] pub struct DetailsView { diff --git a/crates/meilisearch-types/src/tasks.rs b/crates/meilisearch-types/src/tasks.rs index 24254d36e..95c52d9a6 100644 --- a/crates/meilisearch-types/src/tasks.rs +++ b/crates/meilisearch-types/src/tasks.rs @@ -597,7 +597,7 @@ impl fmt::Display for ParseTaskKindError { } impl std::error::Error for ParseTaskKindError {} -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] pub enum Details { DocumentAdditionOrUpdate { received_documents: u64, diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 0f50aafac..b8c3eee29 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -26,7 +26,7 @@ use meilisearch_auth::AuthController; use meilisearch_types::error::ResponseError; use meilisearch_types::heed::RoTxn; use meilisearch_types::keys::actions; -use meilisearch_types::milli::index::ChatConfig; +use meilisearch_types::milli::index::{self, ChatConfig, SearchParameters}; use meilisearch_types::milli::prompt::{Prompt, PromptData}; use meilisearch_types::milli::update::new::document::DocumentFromDb; use meilisearch_types::milli::update::Setting; @@ -46,12 +46,12 @@ use crate::extractors::authentication::{extract_token_from_request, GuardedData, use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; use crate::routes::indexes::search::search_kind; use crate::search::{ - add_search_rules, prepare_search, search_from_kind, HybridQuery, MatchingStrategy, SearchQuery, - SemanticRatio, + add_search_rules, prepare_search, search_from_kind, HybridQuery, MatchingStrategy, + RankingScoreThreshold, SearchQuery, SemanticRatio, DEFAULT_SEARCH_LIMIT, + DEFAULT_SEMANTIC_RATIO, }; use crate::search_queue::SearchQueue; -const EMBEDDER_NAME: &str = "openai"; const SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; pub fn configure(cfg: &mut web::ServiceConfig) { @@ -168,14 +168,43 @@ async fn process_search_request( index_uid: String, q: Option, ) -> Result<(Index, String), ResponseError> { + // TBD + // let mut aggregate = SearchAggregator::::from_query(&query); + + let index = index_scheduler.index(&index_uid)?; + let rtxn = index.static_read_txn()?; + let ChatConfig { description: _, prompt: _, search_parameters } = index.chat_config(&rtxn)?; + let SearchParameters { + hybrid, + limit, + sort, + distinct, + matching_strategy, + attributes_to_search_on, + ranking_score_threshold, + } = search_parameters; + let mut query = SearchQuery { q, - hybrid: Some(HybridQuery { - semantic_ratio: SemanticRatio::default(), - embedder: EMBEDDER_NAME.to_string(), + hybrid: hybrid.map(|index::HybridQuery { semantic_ratio, embedder }| HybridQuery { + semantic_ratio: SemanticRatio::try_from(semantic_ratio) + .ok() + .unwrap_or_else(DEFAULT_SEMANTIC_RATIO), + embedder, }), - limit: 20, - matching_strategy: MatchingStrategy::Frequency, + limit: limit.unwrap_or_else(DEFAULT_SEARCH_LIMIT), + sort: sort, + distinct: distinct, + matching_strategy: matching_strategy + .map(|ms| match ms { + index::MatchingStrategy::Last => MatchingStrategy::Last, + index::MatchingStrategy::All => MatchingStrategy::All, + index::MatchingStrategy::Frequency => MatchingStrategy::Frequency, + }) + .unwrap_or(MatchingStrategy::Frequency), + attributes_to_search_on: attributes_to_search_on, + ranking_score_threshold: ranking_score_threshold + .and_then(|rst| RankingScoreThreshold::try_from(rst).ok()), ..Default::default() }; @@ -189,19 +218,13 @@ async fn process_search_request( if let Some(search_rules) = auth_filter.get_index_search_rules(&index_uid) { add_search_rules(&mut query.filter, search_rules); } - - // TBD - // let mut aggregate = SearchAggregator::::from_query(&query); - - let index = index_scheduler.index(&index_uid)?; let search_kind = search_kind(&query, index_scheduler.get_ref(), index_uid.to_string(), &index)?; let permit = search_queue.try_get_search_permit().await?; let features = index_scheduler.features(); let index_cloned = index.clone(); - let search_result = tokio::task::spawn_blocking(move || -> Result<_, ResponseError> { - let rtxn = index_cloned.read_txn()?; + let output = tokio::task::spawn_blocking(move || -> Result<_, ResponseError> { let time_budget = match index_cloned .search_cutoff(&rtxn) .map_err(|e| MeilisearchHttpError::from_milli(e, Some(index_uid.clone())))? @@ -214,14 +237,14 @@ async fn process_search_request( prepare_search(&index_cloned, &rtxn, &query, &search_kind, time_budget, features)?; search_from_kind(index_uid, search_kind, search) - .map(|(search_results, _)| search_results) + .map(|(search_results, _)| (rtxn, search_results)) .map_err(ResponseError::from) }) .await; permit.drop().await; - let search_result = search_result?; - if let Ok(ref search_result) = search_result { + let output = output?; + if let Ok((_, ref search_result)) = output { // aggregate.succeed(search_result); if search_result.degraded { MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); @@ -229,8 +252,8 @@ async fn process_search_request( } // analytics.publish(aggregate, &req); - let search_result = search_result?; - let rtxn = index.read_txn()?; + let (rtxn, search_result) = output?; + // let rtxn = index.read_txn()?; let render_alloc = Bump::new(); let formatted = format_documents(&rtxn, &index, &render_alloc, search_result.documents_ids)?; let text = formatted.join("\n"); diff --git a/crates/meilisearch/src/search/mod.rs b/crates/meilisearch/src/search/mod.rs index 16d04cd58..848591a4f 100644 --- a/crates/meilisearch/src/search/mod.rs +++ b/crates/meilisearch/src/search/mod.rs @@ -122,6 +122,7 @@ pub struct SearchQuery { #[derive(Debug, Clone, Copy, PartialEq, Deserr, ToSchema, Serialize)] #[deserr(try_from(f64) = TryFrom::try_from -> InvalidSearchRankingScoreThreshold)] pub struct RankingScoreThreshold(f64); + impl std::convert::TryFrom for RankingScoreThreshold { type Error = InvalidSearchRankingScoreThreshold; @@ -279,8 +280,8 @@ impl fmt::Debug for SearchQuery { #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] #[serde(rename_all = "camelCase")] pub struct HybridQuery { - #[deserr(default, error = DeserrJsonError, default)] - #[schema(value_type = f32, default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(default, value_type = f32)] #[serde(default)] pub semantic_ratio: SemanticRatio, #[deserr(error = DeserrJsonError)] diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index a5145cb0b..e6f28d02e 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -1695,7 +1695,7 @@ impl Index { pub fn chat_config(&self, txn: &RoTxn<'_>) -> heed::Result { self.main - .remap_types::>() + .remap_types::>() .get(txn, main_key::CHAT) .map(|o| o.unwrap_or_default()) } @@ -1705,7 +1705,7 @@ impl Index { txn: &mut RwTxn<'_>, val: &ChatConfig, ) -> heed::Result<()> { - self.main.remap_types::>().put(txn, main_key::CHAT, &val) + self.main.remap_types::>().put(txn, main_key::CHAT, &val) } pub(crate) fn delete_chat_config(&self, txn: &mut RwTxn<'_>) -> heed::Result { @@ -1943,15 +1943,54 @@ pub struct ChatConfig { pub description: String, /// Contains the document template and max template length. pub prompt: PromptData, + pub search_parameters: SearchParameters, +} + +#[derive(Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SearchParameters { + #[serde(skip_serializing_if = "Option::is_none")] + pub hybrid: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub sort: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub distinct: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub matching_strategy: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub attributes_to_search_on: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub ranking_score_threshold: Option, +} + +#[derive(Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HybridQuery { + pub semantic_ratio: f32, + pub embedder: String, } #[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] pub struct PrefixSettings { pub prefix_count_threshold: usize, pub max_prefix_length: usize, pub compute_prefixes: PrefixSearch, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum MatchingStrategy { + /// Remove query words from last to first + Last, + /// All query words are mandatory + All, + /// Remove query words from the most frequent to the least + Frequency, +} + #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] #[serde(rename_all = "camelCase")] pub enum PrefixSearch { diff --git a/crates/milli/src/update/chat.rs b/crates/milli/src/update/chat.rs index 44e646f6d..b8fbc582d 100644 --- a/crates/milli/src/update/chat.rs +++ b/crates/milli/src/update/chat.rs @@ -1,14 +1,19 @@ +use std::error::Error; +use std::fmt; + +use deserr::errors::JsonError; use deserr::Deserr; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; -use crate::index::ChatConfig; +use crate::index::{self, ChatConfig, SearchParameters}; use crate::prompt::{default_max_bytes, PromptData}; use crate::update::Setting; +use crate::TermsMatchingStrategy; -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, Deserr, ToSchema)] +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Deserr, ToSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] -#[deserr(deny_unknown_fields, rename_all = camelCase)] +#[deserr(error = JsonError, deny_unknown_fields, rename_all = camelCase)] pub struct ChatSettings { #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] @@ -29,17 +34,226 @@ pub struct ChatSettings { #[deserr(default)] #[schema(value_type = Option)] pub document_template_max_bytes: Setting, + + /// The search parameters to use for the LLM. + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub search_parameters: Setting, } impl From for ChatSettings { fn from(config: ChatConfig) -> Self { - let ChatConfig { description, prompt: PromptData { template, max_bytes } } = config; + let ChatConfig { + description, + prompt: PromptData { template, max_bytes }, + search_parameters, + } = config; ChatSettings { description: Setting::Set(description), document_template: Setting::Set(template), document_template_max_bytes: Setting::Set( max_bytes.unwrap_or(default_max_bytes()).get(), ), + search_parameters: Setting::Set({ + let SearchParameters { + hybrid, + limit, + sort, + distinct, + matching_strategy, + attributes_to_search_on, + ranking_score_threshold, + } = search_parameters; + + let hybrid = hybrid.map(|index::HybridQuery { semantic_ratio, embedder }| { + HybridQuery { semantic_ratio: SemanticRatio(semantic_ratio), embedder } + }); + + let matching_strategy = matching_strategy.map(|ms| match ms { + index::MatchingStrategy::Last => MatchingStrategy::Last, + index::MatchingStrategy::All => MatchingStrategy::All, + index::MatchingStrategy::Frequency => MatchingStrategy::Frequency, + }); + + let ranking_score_threshold = ranking_score_threshold.map(RankingScoreThreshold); + + ChatSearchParams { + hybrid: Setting::some_or_not_set(hybrid), + limit: Setting::some_or_not_set(limit), + sort: Setting::some_or_not_set(sort), + distinct: Setting::some_or_not_set(distinct), + matching_strategy: Setting::some_or_not_set(matching_strategy), + attributes_to_search_on: Setting::some_or_not_set(attributes_to_search_on), + ranking_score_threshold: Setting::some_or_not_set(ranking_score_threshold), + } + }), } } } + +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Deserr, ToSchema)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +#[deserr(error = JsonError, deny_unknown_fields, rename_all = camelCase)] +pub struct ChatSearchParams { + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub hybrid: Setting, + + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default = Setting::Set(20))] + #[schema(value_type = Option)] + pub limit: Setting, + + // #[serde(default, skip_serializing_if = "Setting::is_not_set")] + // #[deserr(default)] + // pub attributes_to_retrieve: Option>, + + // #[serde(default, skip_serializing_if = "Setting::is_not_set")] + // #[deserr(default)] + // pub filter: Option, + // + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option>)] + pub sort: Setting>, + + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub distinct: Setting, + + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub matching_strategy: Setting, + + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option>)] + pub attributes_to_search_on: Setting>, + + #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[deserr(default)] + #[schema(value_type = Option)] + pub ranking_score_threshold: Setting, +} + +#[derive(Debug, Clone, Default, Deserr, ToSchema, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[deserr(error = JsonError, rename_all = camelCase, deny_unknown_fields)] +pub struct HybridQuery { + #[deserr(default)] + #[serde(default)] + #[schema(default, value_type = f32)] + pub semantic_ratio: SemanticRatio, + #[schema(value_type = String)] + pub embedder: String, +} + +#[derive(Debug, Clone, Copy, Deserr, ToSchema, PartialEq, Serialize, Deserialize)] +#[deserr(try_from(f32) = TryFrom::try_from -> InvalidSearchSemanticRatio)] +pub struct SemanticRatio(f32); + +impl Default for SemanticRatio { + fn default() -> Self { + SemanticRatio(0.5) + } +} + +impl std::convert::TryFrom for SemanticRatio { + type Error = InvalidSearchSemanticRatio; + + fn try_from(f: f32) -> Result { + // the suggested "fix" is: `!(0.0..=1.0).contains(&f)`` which is allegedly less readable + #[allow(clippy::manual_range_contains)] + if f > 1.0 || f < 0.0 { + Err(InvalidSearchSemanticRatio) + } else { + Ok(SemanticRatio(f)) + } + } +} + +#[derive(Debug)] +pub struct InvalidSearchSemanticRatio; + +impl Error for InvalidSearchSemanticRatio {} + +impl fmt::Display for InvalidSearchSemanticRatio { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "the value of `semanticRatio` is invalid, expected a float between `0.0` and `1.0`." + ) + } +} + +impl std::ops::Deref for SemanticRatio { + type Target = f32; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserr, ToSchema, Serialize, Deserialize)] +#[deserr(rename_all = camelCase)] +#[serde(rename_all = "camelCase")] +pub enum MatchingStrategy { + /// Remove query words from last to first + Last, + /// All query words are mandatory + All, + /// Remove query words from the most frequent to the least + Frequency, +} + +impl Default for MatchingStrategy { + fn default() -> Self { + Self::Last + } +} + +impl From for TermsMatchingStrategy { + fn from(other: MatchingStrategy) -> Self { + match other { + MatchingStrategy::Last => Self::Last, + MatchingStrategy::All => Self::All, + MatchingStrategy::Frequency => Self::Frequency, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserr, ToSchema, Serialize, Deserialize)] +#[deserr(try_from(f64) = TryFrom::try_from -> InvalidSearchRankingScoreThreshold)] +pub struct RankingScoreThreshold(pub f64); + +impl std::convert::TryFrom for RankingScoreThreshold { + type Error = InvalidSearchRankingScoreThreshold; + + fn try_from(f: f64) -> Result { + // the suggested "fix" is: `!(0.0..=1.0).contains(&f)`` which is allegedly less readable + #[allow(clippy::manual_range_contains)] + if f > 1.0 || f < 0.0 { + Err(InvalidSearchRankingScoreThreshold) + } else { + Ok(RankingScoreThreshold(f)) + } + } +} + +#[derive(Debug)] +pub struct InvalidSearchRankingScoreThreshold; + +impl Error for InvalidSearchRankingScoreThreshold {} + +impl fmt::Display for InvalidSearchRankingScoreThreshold { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "the value of `rankingScoreThreshold` is invalid, expected a float between `0.0` and `1.0`." + ) + } +} diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index bba8bc758..bb589c5ee 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -11,6 +11,7 @@ use roaring::RoaringBitmap; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use time::OffsetDateTime; +use super::chat::{ChatSearchParams, RankingScoreThreshold}; use super::del_add::{DelAdd, DelAddOperation}; use super::index_documents::{IndexDocumentsConfig, Transform}; use super::{ChatSettings, IndexerConfig}; @@ -22,8 +23,8 @@ use crate::error::UserError; use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder}; use crate::filterable_attributes_rules::match_faceted_field; use crate::index::{ - ChatConfig, IndexEmbeddingConfig, PrefixSearch, DEFAULT_MIN_WORD_LEN_ONE_TYPO, - DEFAULT_MIN_WORD_LEN_TWO_TYPOS, + ChatConfig, IndexEmbeddingConfig, MatchingStrategy, PrefixSearch, + DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS, }; use crate::order_by_map::OrderByMap; use crate::prompt::{default_max_bytes, PromptData}; @@ -1263,11 +1264,13 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { description: new_description, document_template: new_document_template, document_template_max_bytes: new_document_template_max_bytes, + search_parameters: new_search_parameters, }) => { let mut old = self.index.chat_config(self.wtxn)?; let ChatConfig { ref mut description, prompt: PromptData { ref mut template, ref mut max_bytes }, + ref mut search_parameters, } = old; match new_description { @@ -1288,6 +1291,85 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { Setting::NotSet => (), } + match new_search_parameters { + Setting::Set(sp) => { + let ChatSearchParams { + hybrid, + limit, + sort, + distinct, + matching_strategy, + attributes_to_search_on, + ranking_score_threshold, + } = sp; + + match hybrid { + Setting::Set(hybrid) => { + search_parameters.hybrid = Some(crate::index::HybridQuery { + semantic_ratio: *hybrid.semantic_ratio, + embedder: hybrid.embedder.clone(), + }) + } + Setting::Reset => search_parameters.hybrid = None, + Setting::NotSet => (), + } + + match limit { + Setting::Set(limit) => search_parameters.limit = Some(*limit), + Setting::Reset => search_parameters.limit = None, + Setting::NotSet => (), + } + + match sort { + Setting::Set(sort) => search_parameters.sort = Some(sort.clone()), + Setting::Reset => search_parameters.sort = None, + Setting::NotSet => (), + } + + match distinct { + Setting::Set(distinct) => { + search_parameters.distinct = Some(distinct.clone()) + } + Setting::Reset => search_parameters.distinct = None, + Setting::NotSet => (), + } + + match matching_strategy { + Setting::Set(matching_strategy) => { + let strategy = match matching_strategy { + super::chat::MatchingStrategy::Last => MatchingStrategy::Last, + super::chat::MatchingStrategy::All => MatchingStrategy::All, + super::chat::MatchingStrategy::Frequency => { + MatchingStrategy::Frequency + } + }; + search_parameters.matching_strategy = Some(strategy) + } + Setting::Reset => search_parameters.matching_strategy = None, + Setting::NotSet => (), + } + + match attributes_to_search_on { + Setting::Set(attributes_to_search_on) => { + search_parameters.attributes_to_search_on = + Some(attributes_to_search_on.clone()) + } + Setting::Reset => search_parameters.attributes_to_search_on = None, + Setting::NotSet => (), + } + + match ranking_score_threshold { + Setting::Set(RankingScoreThreshold(score)) => { + search_parameters.ranking_score_threshold = Some(*score) + } + Setting::Reset => search_parameters.ranking_score_threshold = None, + Setting::NotSet => (), + } + } + Setting::Reset => *search_parameters = Default::default(), + Setting::NotSet => (), + } + self.index.put_chat_config(self.wtxn, &old)?; Ok(true) } From 564cad116380b273662173d6dd2f80a9a08e0df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Fri, 23 May 2025 17:25:09 +0200 Subject: [PATCH 156/292] Call specific tools to show progression and results. --- crates/meilisearch/src/routes/chat.rs | 458 ++++++++++++++++++-------- 1 file changed, 327 insertions(+), 131 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index b8c3eee29..3db948eb8 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -10,13 +10,14 @@ use actix_web::{Either, HttpRequest, HttpResponse, Responder}; use actix_web_lab::sse::{self, Event, Sse}; use async_openai::config::OpenAIConfig; use async_openai::types::{ - ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, - ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, - ChatCompletionRequestSystemMessage, ChatCompletionRequestSystemMessageContent, - ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, - ChatCompletionStreamResponseDelta, ChatCompletionToolArgs, ChatCompletionToolType, - CreateChatCompletionRequest, FinishReason, FunctionCall, FunctionCallStream, - FunctionObjectArgs, + ChatChoiceStream, ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, + ChatCompletionRequestAssistantMessage, ChatCompletionRequestAssistantMessageArgs, + ChatCompletionRequestMessage, ChatCompletionRequestSystemMessage, + ChatCompletionRequestSystemMessageContent, ChatCompletionRequestToolMessage, + ChatCompletionRequestToolMessageContent, ChatCompletionStreamResponseDelta, + ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, + CreateChatCompletionStreamResponse, FinishReason, FunctionCall, FunctionCallStream, + FunctionObjectArgs, Role, }; use async_openai::Client; use bumpalo::Bump; @@ -34,7 +35,7 @@ use meilisearch_types::milli::{ DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, MetadataBuilder, TimeBudget, }; use meilisearch_types::Index; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use serde_json::json; use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; @@ -52,7 +53,9 @@ use crate::search::{ }; use crate::search_queue::SearchQueue; -const SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; +const MEILI_SEARCH_PROGRESS_NAME: &str = "_meiliSearchProgress"; +const MEILI_APPEND_CONVERSATION_MESSAGE_NAME: &str = "_meiliAppendConversationMessage"; +const MEILI_SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("/completions").route(web::post().to(chat))); @@ -86,18 +89,45 @@ async fn chat( } } +#[derive(Default, Debug, Clone, Copy)] +pub struct FunctionSupport { + /// Defines if we can call the _meiliSearchProgress function + /// to inform the front-end about what we are searching for. + progress: bool, + /// Defines if we can call the _meiliAppendConversationMessage + /// function to provide the messages to append into the conversation. + append_to_conversation: bool, +} + /// Setup search tool in chat completion request fn setup_search_tool( index_scheduler: &Data, filters: &meilisearch_auth::AuthFilter, chat_completion: &mut CreateChatCompletionRequest, prompts: &ChatPrompts, -) -> Result<(), ResponseError> { +) -> Result { let tools = chat_completion.tools.get_or_insert_default(); - if tools.iter().find(|t| t.function.name == SEARCH_IN_INDEX_FUNCTION_NAME).is_some() { - panic!("{SEARCH_IN_INDEX_FUNCTION_NAME} function already set"); + if tools.iter().find(|t| t.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME).is_some() { + panic!("{MEILI_SEARCH_IN_INDEX_FUNCTION_NAME} function already set"); } + // Remove internal tools used for front-end notifications as they should be hidden from the LLM. + let mut progress = false; + let mut append_to_conversation = false; + tools.retain(|tool| { + match tool.function.name.as_str() { + MEILI_SEARCH_PROGRESS_NAME => { + progress = true; + false + } + MEILI_APPEND_CONVERSATION_MESSAGE_NAME => { + append_to_conversation = true; + false + } + _ => true, // keep other tools + } + }); + let mut index_uids = Vec::new(); let mut function_description = prompts.search_description.clone().unwrap(); index_scheduler.try_for_each_index::<_, ()>(|name, index| { @@ -119,7 +149,7 @@ fn setup_search_tool( .r#type(ChatCompletionToolType::Function) .function( FunctionObjectArgs::default() - .name(SEARCH_IN_INDEX_FUNCTION_NAME) + .name(MEILI_SEARCH_IN_INDEX_FUNCTION_NAME) .description(&function_description) .parameters(json!({ "type": "object", @@ -145,7 +175,9 @@ fn setup_search_tool( ) .build() .unwrap(); + tools.push(tool); + chat_completion.messages.insert( 0, ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { @@ -156,7 +188,7 @@ fn setup_search_tool( }), ); - Ok(()) + Ok(FunctionSupport { progress, append_to_conversation }) } /// Process search request and return formatted results @@ -287,7 +319,8 @@ async fn non_streamed_chat( let auth_token = extract_token_from_request(&req)?.unwrap(); let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; + let FunctionSupport { progress, append_to_conversation } = + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; let mut response; loop { @@ -300,7 +333,7 @@ async fn non_streamed_chat( let (meili_calls, other_calls): (Vec<_>, Vec<_>) = tool_calls .into_iter() - .partition(|call| call.function.name == SEARCH_IN_INDEX_FUNCTION_NAME); + .partition(|call| call.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME); chat_completion.messages.push( ChatCompletionRequestAssistantMessageArgs::default() @@ -378,7 +411,8 @@ async fn streamed_chat( let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; + let FunctionSupport { progress, append_to_conversation } = + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; let (tx, rx) = tokio::sync::mpsc::channel(10); let _join_handle = Handle::current().spawn(async move { @@ -395,21 +429,8 @@ async fn streamed_chat( let choice = &resp.choices[0]; finish_reason = choice.finish_reason; - #[allow(deprecated)] - let ChatCompletionStreamResponseDelta { - content, - // Using deprecated field but keeping for compatibility - function_call: _, - ref tool_calls, - role: _, - refusal: _, - } = &choice.delta; - - if content.is_some() { - if let Err(SendError(_)) = tx.send(Event::Data(sse::Data::new_json(&resp).unwrap())).await { - return; - } - } + let ChatCompletionStreamResponseDelta { ref tool_calls, .. } = + &choice.delta; match tool_calls { Some(tool_calls) => { @@ -422,109 +443,195 @@ async fn streamed_chat( } = chunk; let FunctionCallStream { name, arguments } = function.as_ref().unwrap(); + global_tool_calls .entry(*index) - .and_modify(|call| call.append(arguments.as_ref().unwrap())) - .or_insert_with(|| Call { - id: id.as_ref().unwrap().clone(), - function_name: name.as_ref().unwrap().clone(), - arguments: arguments.as_ref().unwrap().clone(), - }); - } - } - None if !global_tool_calls.is_empty() => { - let (meili_calls, _other_calls): (Vec<_>, Vec<_>) = - mem::take(&mut global_tool_calls) - .into_values() - .map(|call| ChatCompletionMessageToolCall { - id: call.id, - r#type: Some(ChatCompletionToolType::Function), - function: FunctionCall { - name: call.function_name, - arguments: call.arguments, - }, + .and_modify(|call| { + if call.is_internal() { + call.append(arguments.as_ref().unwrap()) + } }) - .partition(|call| call.function.name == SEARCH_IN_INDEX_FUNCTION_NAME); - - chat_completion.messages.push( - ChatCompletionRequestAssistantMessageArgs::default() - .tool_calls(meili_calls.clone()) - .build() - .unwrap() - .into(), - ); - - for call in meili_calls { - if let Err(SendError(_)) = tx.send(Event::Data( - sse::Data::new_json(json!({ - "object": "chat.completion.tool.call", - "tool": call, - })) - .unwrap(), - )) - .await { - return; - } - - let result = match serde_json::from_str(&call.function.arguments) { - Ok(SearchInIndexParameters { index_uid, q }) => process_search_request( - &index_scheduler, - auth_ctrl.clone(), - &search_queue, - &auth_token, - index_uid, - q, - ).await.map_err(|e| e.to_string()), - Err(err) => Err(err.to_string()), - }; - - let is_error = result.is_err(); - let text = match result { - Ok((_, text)) => text, - Err(err) => err, - }; - - let tool = ChatCompletionRequestToolMessage { - tool_call_id: call.id.clone(), - content: ChatCompletionRequestToolMessageContent::Text( - format!("{}\n\n{text}", chat_settings.prompts.as_ref().unwrap().pre_query.as_ref().unwrap()), - ), - }; - - if let Err(SendError(_)) = tx.send(Event::Data( - sse::Data::new_json(json!({ - "object": if is_error { - "chat.completion.tool.error" + .or_insert_with(|| { + if name.as_ref().map_or(false, |n| { + n == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME + }) { + Call::Internal { + id: id.as_ref().unwrap().clone(), + function_name: name.as_ref().unwrap().clone(), + arguments: arguments.as_ref().unwrap().clone(), + } } else { - "chat.completion.tool.output" - }, - "tool": ChatCompletionRequestToolMessage { - tool_call_id: call.id, - content: ChatCompletionRequestToolMessageContent::Text( - text, - ), - }, - })) - .unwrap(), - )) - .await { - return; - } + Call::External { _id: id.as_ref().unwrap().clone() } + } + }); - chat_completion.messages.push(ChatCompletionRequestMessage::Tool(tool)); + if global_tool_calls.get(index).map_or(false, Call::is_external) + { + todo!("Support forwarding external tool calls"); + } + } + } + None => { + if !global_tool_calls.is_empty() { + let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + mem::take(&mut global_tool_calls) + .into_values() + .flat_map(|call| match call { + Call::Internal { + id, + function_name: name, + arguments, + } => Some(ChatCompletionMessageToolCall { + id, + r#type: Some(ChatCompletionToolType::Function), + function: FunctionCall { name, arguments }, + }), + Call::External { _id: _ } => None, + }) + .partition(|call| { + call.function.name + == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME + }); + + chat_completion.messages.push( + ChatCompletionRequestAssistantMessageArgs::default() + .tool_calls(meili_calls.clone()) + .build() + .unwrap() + .into(), + ); + + assert!( + other_calls.is_empty(), + "We do not support external tool forwarding for now" + ); + + for call in meili_calls { + if progress { + let call = MeiliSearchProgress { + function_name: call.function.name.clone(), + function_arguments: call + .function + .arguments + .clone(), + }; + let resp = call.create_response(resp.clone()); + // Send the event of "we are doing a search" + if let Err(SendError(_)) = tx + .send(Event::Data(sse::Data::new_json(&resp).unwrap())) + .await + { + return; + } + } + + if append_to_conversation { + // Ask the front-end user to append this tool *call* to the conversation + let call = MeiliAppendConversationMessage(ChatCompletionRequestMessage::Assistant( + ChatCompletionRequestAssistantMessage { + content: None, + refusal: None, + name: None, + audio: None, + tool_calls: Some(vec![ + ChatCompletionMessageToolCall { + id: call.id.clone(), + r#type: Some(ChatCompletionToolType::Function), + function: FunctionCall { + name: call.function.name.clone(), + arguments: call.function.arguments.clone(), + }, + }, + ]), + function_call: None, + } + )); + let resp = call.create_response(resp.clone()); + if let Err(SendError(_)) = tx + .send(Event::Data(sse::Data::new_json(&resp).unwrap())) + .await + { + return; + } + } + + let result = + match serde_json::from_str(&call.function.arguments) { + Ok(SearchInIndexParameters { index_uid, q }) => { + process_search_request( + &index_scheduler, + auth_ctrl.clone(), + &search_queue, + &auth_token, + index_uid, + q, + ) + .await + .map_err(|e| e.to_string()) + } + Err(err) => Err(err.to_string()), + }; + + let text = match result { + Ok((_, text)) => text, + Err(err) => err, + }; + + let tool = ChatCompletionRequestMessage::Tool(ChatCompletionRequestToolMessage { + tool_call_id: call.id.clone(), + content: ChatCompletionRequestToolMessageContent::Text( + format!( + "{}\n\n{text}", + chat_settings + .prompts + .as_ref() + .unwrap() + .pre_query + .as_ref() + .unwrap() + ), + ), + }); + + if append_to_conversation { + // Ask the front-end user to append this tool *output* to the conversation + let tool = MeiliAppendConversationMessage(tool.clone()); + let resp = tool.create_response(resp.clone()); + if let Err(SendError(_)) = tx + .send(Event::Data(sse::Data::new_json(&resp).unwrap())) + .await + { + return; + } + } + + chat_completion.messages.push(tool); + } + } else { + if let Err(SendError(_)) = tx + .send(Event::Data(sse::Data::new_json(&resp).unwrap())) + .await + { + return; + } } } - None => (), } } Err(err) => { - tracing::error!("{err:?}"); - if let Err(SendError(_)) = tx.send(Event::Data(sse::Data::new_json(&json!({ - "object": "chat.completion.error", - "tool": err.to_string(), - })).unwrap())).await { - return; - } + // tracing::error!("{err:?}"); + // if let Err(SendError(_)) = tx + // .send(Event::Data( + // sse::Data::new_json(&json!({ + // "object": "chat.completion.error", + // "tool": err.to_string(), + // })) + // .unwrap(), + // )) + // .await + // { + // return; + // } break 'main; } @@ -543,17 +650,106 @@ async fn streamed_chat( Ok(Sse::from_infallible_receiver(rx).with_retry_duration(Duration::from_secs(10))) } +#[derive(Debug, Clone, Serialize)] +/// Give context about what Meilisearch is doing. +struct MeiliSearchProgress { + /// The name of the function we are executing. + pub function_name: String, + /// The arguments of the function we are executing, encoded in JSON. + pub function_arguments: String, +} + +impl MeiliSearchProgress { + fn create_response( + &self, + mut resp: CreateChatCompletionStreamResponse, + ) -> CreateChatCompletionStreamResponse { + let call_text = serde_json::to_string(self).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_SEARCH_PROGRESS_NAME.to_string()), + arguments: Some(call_text), + }), + }; + resp.choices[0] = ChatChoiceStream { + index: 0, + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + resp + } +} + +struct MeiliAppendConversationMessage(pub ChatCompletionRequestMessage); + +impl MeiliAppendConversationMessage { + fn create_response( + &self, + mut resp: CreateChatCompletionStreamResponse, + ) -> CreateChatCompletionStreamResponse { + let call_text = serde_json::to_string(&self.0).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_APPEND_CONVERSATION_MESSAGE_NAME.to_string()), + arguments: Some(call_text), + }), + }; + resp.choices[0] = ChatChoiceStream { + index: 0, + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + resp + } +} + /// The structure used to aggregate the function calls to make. #[derive(Debug)] -struct Call { - id: String, - function_name: String, - arguments: String, +enum Call { + /// Tool calls to tools that must be managed by Meilisearch internally. + /// Typically the search functions. + Internal { id: String, function_name: String, arguments: String }, + /// Tool calls that we track but only to know that its not our functions. + /// We return the function calls as-is to the end-user. + External { _id: String }, } impl Call { - fn append(&mut self, arguments: &str) { - self.arguments.push_str(arguments); + fn is_internal(&self) -> bool { + matches!(self, Call::Internal { .. }) + } + + fn is_external(&self) -> bool { + matches!(self, Call::External { .. }) + } + + fn append(&mut self, more: &str) { + match self { + Call::Internal { arguments, .. } => arguments.push_str(more), + Call::External { .. } => { + panic!("Cannot append argument chunks to an external function") + } + } } } From 2a067d3327482061718684cda51e2cdb72fa626e Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Mon, 26 May 2025 14:04:53 +0200 Subject: [PATCH 157/292] Fix compilation error in test --- crates/dump/src/lib.rs | 1 + crates/index-scheduler/src/insta_snapshot.rs | 1 + crates/milli/src/update/test_settings.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index 95d75700e..285818a87 100644 --- a/crates/dump/src/lib.rs +++ b/crates/dump/src/lib.rs @@ -305,6 +305,7 @@ pub(crate) mod test { localized_attributes: Setting::NotSet, facet_search: Setting::NotSet, prefix_search: Setting::NotSet, + chat: Setting::NotSet, _kind: std::marker::PhantomData, }; settings.check() diff --git a/crates/index-scheduler/src/insta_snapshot.rs b/crates/index-scheduler/src/insta_snapshot.rs index 89e615132..d01548319 100644 --- a/crates/index-scheduler/src/insta_snapshot.rs +++ b/crates/index-scheduler/src/insta_snapshot.rs @@ -34,6 +34,7 @@ pub fn snapshot_index_scheduler(scheduler: &IndexScheduler) -> String { planned_failures: _, run_loop_iteration: _, embedders: _, + chat_settings: _, } = scheduler; let rtxn = env.read_txn().unwrap(); diff --git a/crates/milli/src/update/test_settings.rs b/crates/milli/src/update/test_settings.rs index 2b9ee3a5e..e775c226f 100644 --- a/crates/milli/src/update/test_settings.rs +++ b/crates/milli/src/update/test_settings.rs @@ -897,6 +897,7 @@ fn test_correct_settings_init() { prefix_search, facet_search, disable_on_numbers, + chat, } = settings; assert!(matches!(searchable_fields, Setting::NotSet)); assert!(matches!(displayed_fields, Setting::NotSet)); From 420c6e1932876ef3c59a2e26bc46766f96600a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 27 May 2025 11:48:12 +0200 Subject: [PATCH 158/292] Report the sources --- crates/meilisearch/src/routes/chat.rs | 123 ++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 16 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 3db948eb8..5de5a9367 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -32,9 +32,10 @@ use meilisearch_types::milli::prompt::{Prompt, PromptData}; use meilisearch_types::milli::update::new::document::DocumentFromDb; use meilisearch_types::milli::update::Setting; use meilisearch_types::milli::{ - DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, MetadataBuilder, TimeBudget, + all_obkv_to_json, obkv_to_json, DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, + MetadataBuilder, TimeBudget, }; -use meilisearch_types::Index; +use meilisearch_types::{Document, Index}; use serde::{Deserialize, Serialize}; use serde_json::json; use tokio::runtime::Handle; @@ -55,6 +56,8 @@ use crate::search_queue::SearchQueue; const MEILI_SEARCH_PROGRESS_NAME: &str = "_meiliSearchProgress"; const MEILI_APPEND_CONVERSATION_MESSAGE_NAME: &str = "_meiliAppendConversationMessage"; +const MEILI_SEARCH_SOURCES_NAME: &str = "_meiliSearchSources"; +const MEILI_REPORT_ERRORS_NAME: &str = "_meiliReportErrors"; const MEILI_SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; pub fn configure(cfg: &mut web::ServiceConfig) { @@ -93,10 +96,16 @@ async fn chat( pub struct FunctionSupport { /// Defines if we can call the _meiliSearchProgress function /// to inform the front-end about what we are searching for. - progress: bool, + report_progress: bool, + /// Defines if we can call the _meiliSearchSources function + /// to inform the front-end about the sources of the search. + report_sources: bool, /// Defines if we can call the _meiliAppendConversationMessage /// function to provide the messages to append into the conversation. append_to_conversation: bool, + /// Defines if we can call the _meiliReportErrors function + /// to inform the front-end about potential errors. + report_errors: bool, } /// Setup search tool in chat completion request @@ -112,18 +121,28 @@ fn setup_search_tool( } // Remove internal tools used for front-end notifications as they should be hidden from the LLM. - let mut progress = false; + let mut report_progress = false; + let mut report_sources = false; let mut append_to_conversation = false; + let mut report_errors = false; tools.retain(|tool| { match tool.function.name.as_str() { MEILI_SEARCH_PROGRESS_NAME => { - progress = true; + report_progress = true; + false + } + MEILI_SEARCH_SOURCES_NAME => { + report_sources = true; false } MEILI_APPEND_CONVERSATION_MESSAGE_NAME => { append_to_conversation = true; false } + MEILI_REPORT_ERRORS_NAME => { + report_errors = true; + false + } _ => true, // keep other tools } }); @@ -188,7 +207,7 @@ fn setup_search_tool( }), ); - Ok(FunctionSupport { progress, append_to_conversation }) + Ok(FunctionSupport { report_progress, report_sources, append_to_conversation, report_errors }) } /// Process search request and return formatted results @@ -199,7 +218,7 @@ async fn process_search_request( auth_token: &str, index_uid: String, q: Option, -) -> Result<(Index, String), ResponseError> { +) -> Result<(Index, Vec, String), ResponseError> { // TBD // let mut aggregate = SearchAggregator::::from_query(&query); @@ -276,22 +295,33 @@ async fn process_search_request( permit.drop().await; let output = output?; - if let Ok((_, ref search_result)) = output { + let mut documents = Vec::new(); + if let Ok((ref rtxn, ref search_result)) = output { // aggregate.succeed(search_result); if search_result.degraded { MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); } + + let fields_ids_map = index.fields_ids_map(rtxn)?; + let displayed_fields = index.displayed_fields_ids(rtxn)?; + for &document_id in &search_result.documents_ids { + let obkv = index.document(rtxn, document_id)?; + let document = match displayed_fields { + Some(ref fields) => obkv_to_json(fields, &fields_ids_map, obkv)?, + None => all_obkv_to_json(obkv, &fields_ids_map)?, + }; + documents.push(document); + } } // analytics.publish(aggregate, &req); let (rtxn, search_result) = output?; - // let rtxn = index.read_txn()?; let render_alloc = Bump::new(); let formatted = format_documents(&rtxn, &index, &render_alloc, search_result.documents_ids)?; let text = formatted.join("\n"); drop(rtxn); - Ok((index, text)) + Ok((index, documents, text)) } async fn non_streamed_chat( @@ -319,7 +349,7 @@ async fn non_streamed_chat( let auth_token = extract_token_from_request(&req)?.unwrap(); let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); - let FunctionSupport { progress, append_to_conversation } = + let FunctionSupport { report_progress, report_sources, append_to_conversation, report_errors } = setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; let mut response; @@ -359,7 +389,7 @@ async fn non_streamed_chat( }; let text = match result { - Ok((_, text)) => text, + Ok((_, documents, text)) => text, Err(err) => err, }; @@ -411,7 +441,7 @@ async fn streamed_chat( let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); - let FunctionSupport { progress, append_to_conversation } = + let FunctionSupport { report_progress, report_sources, append_to_conversation, report_errors } = setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; let (tx, rx) = tokio::sync::mpsc::channel(10); @@ -507,8 +537,9 @@ async fn streamed_chat( ); for call in meili_calls { - if progress { + if report_progress { let call = MeiliSearchProgress { + call_id: call.id.to_string(), function_name: call.function.name.clone(), function_arguments: call .function @@ -573,7 +604,24 @@ async fn streamed_chat( }; let text = match result { - Ok((_, text)) => text, + Ok((_index, documents, text)) => { + if report_sources { + let call = MeiliSearchSources { + call_id: call.id.to_string(), + sources: documents, + }; + let resp = call.create_response(resp.clone()); + // Send the event of "we are doing a search" + if let Err(SendError(_)) = tx + .send(Event::Data(sse::Data::new_json(&resp).unwrap())) + .await + { + return; + } + } + + text + }, Err(err) => err, }; @@ -651,8 +699,10 @@ async fn streamed_chat( } #[derive(Debug, Clone, Serialize)] -/// Give context about what Meilisearch is doing. +/// Provides information about the current Meilisearch search operation. struct MeiliSearchProgress { + /// The call ID to track the sources of the search. + pub call_id: String, /// The name of the function we are executing. pub function_name: String, /// The arguments of the function we are executing, encoded in JSON. @@ -690,6 +740,47 @@ impl MeiliSearchProgress { } } +#[derive(Debug, Clone, Serialize)] +/// Provides sources of the search. +struct MeiliSearchSources { + /// The call ID to track the original search associated to those sources. + pub call_id: String, + /// The documents associated with the search (call_id). + /// Only the displayed attributes of the documents are returned. + pub sources: Vec, +} + +impl MeiliSearchSources { + fn create_response( + &self, + mut resp: CreateChatCompletionStreamResponse, + ) -> CreateChatCompletionStreamResponse { + let call_text = serde_json::to_string(self).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_SEARCH_SOURCES_NAME.to_string()), + arguments: Some(call_text), + }), + }; + resp.choices[0] = ChatChoiceStream { + index: 0, + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + resp + } +} + struct MeiliAppendConversationMessage(pub ChatCompletionRequestMessage); impl MeiliAppendConversationMessage { From 2da64e835e524a2e94dd7f15311a56f451fc44a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 27 May 2025 18:07:29 +0200 Subject: [PATCH 159/292] Factorize the code a bit more and support reporting errors --- crates/meilisearch/src/routes/chat.rs | 710 ++++++++++++++------------ 1 file changed, 385 insertions(+), 325 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 5de5a9367..9de15f751 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -2,13 +2,15 @@ use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Write as _; use std::mem; +use std::ops::ControlFlow; use std::sync::RwLock; use std::time::Duration; use actix_web::web::{self, Data}; use actix_web::{Either, HttpRequest, HttpResponse, Responder}; use actix_web_lab::sse::{self, Event, Sse}; -use async_openai::config::OpenAIConfig; +use async_openai::config::{Config, OpenAIConfig}; +use async_openai::error::OpenAIError; use async_openai::types::{ ChatChoiceStream, ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, ChatCompletionRequestAssistantMessage, ChatCompletionRequestAssistantMessageArgs, @@ -40,6 +42,7 @@ use serde::{Deserialize, Serialize}; use serde_json::json; use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; +use tokio::sync::mpsc::Sender; use super::settings::chat::{ChatPrompts, GlobalChatSettings}; use crate::error::MeilisearchHttpError; @@ -83,11 +86,11 @@ async fn chat( if chat_completion.stream.unwrap_or(false) { Either::Right( - streamed_chat(index_scheduler, auth_ctrl, req, search_queue, chat_completion).await, + streamed_chat(index_scheduler, auth_ctrl, search_queue, req, chat_completion).await, ) } else { Either::Left( - non_streamed_chat(index_scheduler, auth_ctrl, req, search_queue, chat_completion).await, + non_streamed_chat(index_scheduler, auth_ctrl, search_queue, req, chat_completion).await, ) } } @@ -327,8 +330,8 @@ async fn process_search_request( async fn non_streamed_chat( index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, - req: HttpRequest, search_queue: web::Data, + req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { let filters = index_scheduler.filters(); @@ -420,8 +423,8 @@ async fn non_streamed_chat( async fn streamed_chat( index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, - req: HttpRequest, search_queue: web::Data, + req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { let filters = index_scheduler.filters(); @@ -441,354 +444,285 @@ async fn streamed_chat( let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); - let FunctionSupport { report_progress, report_sources, append_to_conversation, report_errors } = + let function_support = setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; let (tx, rx) = tokio::sync::mpsc::channel(10); + let tx = SseEventSender(tx); let _join_handle = Handle::current().spawn(async move { let client = Client::with_config(config.clone()); let mut global_tool_calls = HashMap::::new(); - let mut finish_reason = None; // Limit the number of internal calls to satisfy the search requests of the LLM - 'main: for _ in 0..20 { - let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); - while let Some(result) = response.next().await { - match result { - Ok(resp) => { - let choice = &resp.choices[0]; - finish_reason = choice.finish_reason; + for _ in 0..20 { + let output = run_conversation( + &index_scheduler, + &auth_ctrl, + &search_queue, + &auth_token, + &client, + &chat_settings, + &mut chat_completion, + &tx, + &mut global_tool_calls, + function_support, + ); - let ChatCompletionStreamResponseDelta { ref tool_calls, .. } = - &choice.delta; - - match tool_calls { - Some(tool_calls) => { - for chunk in tool_calls { - let ChatCompletionMessageToolCallChunk { - index, - id, - r#type: _, - function, - } = chunk; - let FunctionCallStream { name, arguments } = - function.as_ref().unwrap(); - - global_tool_calls - .entry(*index) - .and_modify(|call| { - if call.is_internal() { - call.append(arguments.as_ref().unwrap()) - } - }) - .or_insert_with(|| { - if name.as_ref().map_or(false, |n| { - n == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME - }) { - Call::Internal { - id: id.as_ref().unwrap().clone(), - function_name: name.as_ref().unwrap().clone(), - arguments: arguments.as_ref().unwrap().clone(), - } - } else { - Call::External { _id: id.as_ref().unwrap().clone() } - } - }); - - if global_tool_calls.get(index).map_or(false, Call::is_external) - { - todo!("Support forwarding external tool calls"); - } - } - } - None => { - if !global_tool_calls.is_empty() { - let (meili_calls, other_calls): (Vec<_>, Vec<_>) = - mem::take(&mut global_tool_calls) - .into_values() - .flat_map(|call| match call { - Call::Internal { - id, - function_name: name, - arguments, - } => Some(ChatCompletionMessageToolCall { - id, - r#type: Some(ChatCompletionToolType::Function), - function: FunctionCall { name, arguments }, - }), - Call::External { _id: _ } => None, - }) - .partition(|call| { - call.function.name - == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME - }); - - chat_completion.messages.push( - ChatCompletionRequestAssistantMessageArgs::default() - .tool_calls(meili_calls.clone()) - .build() - .unwrap() - .into(), - ); - - assert!( - other_calls.is_empty(), - "We do not support external tool forwarding for now" - ); - - for call in meili_calls { - if report_progress { - let call = MeiliSearchProgress { - call_id: call.id.to_string(), - function_name: call.function.name.clone(), - function_arguments: call - .function - .arguments - .clone(), - }; - let resp = call.create_response(resp.clone()); - // Send the event of "we are doing a search" - if let Err(SendError(_)) = tx - .send(Event::Data(sse::Data::new_json(&resp).unwrap())) - .await - { - return; - } - } - - if append_to_conversation { - // Ask the front-end user to append this tool *call* to the conversation - let call = MeiliAppendConversationMessage(ChatCompletionRequestMessage::Assistant( - ChatCompletionRequestAssistantMessage { - content: None, - refusal: None, - name: None, - audio: None, - tool_calls: Some(vec![ - ChatCompletionMessageToolCall { - id: call.id.clone(), - r#type: Some(ChatCompletionToolType::Function), - function: FunctionCall { - name: call.function.name.clone(), - arguments: call.function.arguments.clone(), - }, - }, - ]), - function_call: None, - } - )); - let resp = call.create_response(resp.clone()); - if let Err(SendError(_)) = tx - .send(Event::Data(sse::Data::new_json(&resp).unwrap())) - .await - { - return; - } - } - - let result = - match serde_json::from_str(&call.function.arguments) { - Ok(SearchInIndexParameters { index_uid, q }) => { - process_search_request( - &index_scheduler, - auth_ctrl.clone(), - &search_queue, - &auth_token, - index_uid, - q, - ) - .await - .map_err(|e| e.to_string()) - } - Err(err) => Err(err.to_string()), - }; - - let text = match result { - Ok((_index, documents, text)) => { - if report_sources { - let call = MeiliSearchSources { - call_id: call.id.to_string(), - sources: documents, - }; - let resp = call.create_response(resp.clone()); - // Send the event of "we are doing a search" - if let Err(SendError(_)) = tx - .send(Event::Data(sse::Data::new_json(&resp).unwrap())) - .await - { - return; - } - } - - text - }, - Err(err) => err, - }; - - let tool = ChatCompletionRequestMessage::Tool(ChatCompletionRequestToolMessage { - tool_call_id: call.id.clone(), - content: ChatCompletionRequestToolMessageContent::Text( - format!( - "{}\n\n{text}", - chat_settings - .prompts - .as_ref() - .unwrap() - .pre_query - .as_ref() - .unwrap() - ), - ), - }); - - if append_to_conversation { - // Ask the front-end user to append this tool *output* to the conversation - let tool = MeiliAppendConversationMessage(tool.clone()); - let resp = tool.create_response(resp.clone()); - if let Err(SendError(_)) = tx - .send(Event::Data(sse::Data::new_json(&resp).unwrap())) - .await - { - return; - } - } - - chat_completion.messages.push(tool); - } - } else { - if let Err(SendError(_)) = tx - .send(Event::Data(sse::Data::new_json(&resp).unwrap())) - .await - { - return; - } - } - } - } - } - Err(err) => { - // tracing::error!("{err:?}"); - // if let Err(SendError(_)) = tx - // .send(Event::Data( - // sse::Data::new_json(&json!({ - // "object": "chat.completion.error", - // "tool": err.to_string(), - // })) - // .unwrap(), - // )) - // .await - // { - // return; - // } - - break 'main; - } - } - } - - // We must stop if the finish reason is not something we can solve with Meilisearch - if finish_reason.map_or(true, |fr| fr != FinishReason::ToolCalls) { - break; + match output.await { + Ok(ControlFlow::Continue(())) => (), + Ok(ControlFlow::Break(_finish_reason)) => break, + // If the connection is closed we must stop + Err(SendError(_)) => return, } } - let _ = tx.send(Event::Data(sse::Data::new("[DONE]"))); + let _ = tx.stop().await; }); Ok(Sse::from_infallible_receiver(rx).with_retry_duration(Duration::from_secs(10))) } -#[derive(Debug, Clone, Serialize)] -/// Provides information about the current Meilisearch search operation. -struct MeiliSearchProgress { - /// The call ID to track the sources of the search. - pub call_id: String, - /// The name of the function we are executing. - pub function_name: String, - /// The arguments of the function we are executing, encoded in JSON. - pub function_arguments: String, -} +/// Updates the chat completion with the new messages, streams the LLM tokens, +/// and report progress and errors. +async fn run_conversation( + index_scheduler: &GuardedData, Data>, + auth_ctrl: &web::Data, + search_queue: &web::Data, + auth_token: &str, + client: &Client, + chat_settings: &GlobalChatSettings, + chat_completion: &mut CreateChatCompletionRequest, + tx: &SseEventSender, + global_tool_calls: &mut HashMap, + function_support: FunctionSupport, +) -> Result, ()>, SendError> { + let mut finish_reason = None; -impl MeiliSearchProgress { - fn create_response( - &self, - mut resp: CreateChatCompletionStreamResponse, - ) -> CreateChatCompletionStreamResponse { - let call_text = serde_json::to_string(self).unwrap(); - let tool_call = ChatCompletionMessageToolCallChunk { - index: 0, - id: Some(uuid::Uuid::new_v4().to_string()), - r#type: Some(ChatCompletionToolType::Function), - function: Some(FunctionCallStream { - name: Some(MEILI_SEARCH_PROGRESS_NAME.to_string()), - arguments: Some(call_text), - }), - }; - resp.choices[0] = ChatChoiceStream { - index: 0, - delta: ChatCompletionStreamResponseDelta { - content: None, - function_call: None, - tool_calls: Some(vec![tool_call]), - role: Some(Role::Assistant), - refusal: None, - }, - finish_reason: None, - logprobs: None, - }; - resp + let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); + while let Some(result) = response.next().await { + match result { + Ok(resp) => { + let choice = &resp.choices[0]; + finish_reason = choice.finish_reason; + + let ChatCompletionStreamResponseDelta { ref tool_calls, .. } = &choice.delta; + + match tool_calls { + Some(tool_calls) => { + for chunk in tool_calls { + let ChatCompletionMessageToolCallChunk { + index, + id, + r#type: _, + function, + } = chunk; + let FunctionCallStream { name, arguments } = function.as_ref().unwrap(); + + global_tool_calls + .entry(*index) + .and_modify(|call| { + if call.is_internal() { + call.append(arguments.as_ref().unwrap()) + } + }) + .or_insert_with(|| { + if name + .as_ref() + .map_or(false, |n| n == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME) + { + Call::Internal { + id: id.as_ref().unwrap().clone(), + function_name: name.as_ref().unwrap().clone(), + arguments: arguments.as_ref().unwrap().clone(), + } + } else { + Call::External + } + }); + + if global_tool_calls.get(index).map_or(false, Call::is_external) { + todo!("Support forwarding external tool calls"); + } + } + } + None => { + if !global_tool_calls.is_empty() { + let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + mem::take(global_tool_calls) + .into_values() + .flat_map(|call| match call { + Call::Internal { id, function_name: name, arguments } => { + Some(ChatCompletionMessageToolCall { + id, + r#type: Some(ChatCompletionToolType::Function), + function: FunctionCall { name, arguments }, + }) + } + Call::External => None, + }) + .partition(|call| { + call.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME + }); + + chat_completion.messages.push( + ChatCompletionRequestAssistantMessageArgs::default() + .tool_calls(meili_calls.clone()) + .build() + .unwrap() + .into(), + ); + + assert!( + other_calls.is_empty(), + "We do not support external tool forwarding for now" + ); + + handle_meili_tools( + &index_scheduler, + &auth_ctrl, + &search_queue, + &auth_token, + chat_settings, + tx, + meili_calls, + chat_completion, + &resp, + function_support, + ) + .await?; + } else { + tx.forward_response(&resp).await?; + } + } + } + } + Err(err) => { + if function_support.report_errors { + tx.report_error(err).await?; + } + return Ok(ControlFlow::Break(None)); + } + } + } + + // We must stop if the finish reason is not something we can solve with Meilisearch + match finish_reason { + Some(FinishReason::ToolCalls) => Ok(ControlFlow::Continue(())), + otherwise => Ok(ControlFlow::Break(otherwise)), } } -#[derive(Debug, Clone, Serialize)] -/// Provides sources of the search. -struct MeiliSearchSources { - /// The call ID to track the original search associated to those sources. - pub call_id: String, - /// The documents associated with the search (call_id). - /// Only the displayed attributes of the documents are returned. - pub sources: Vec, -} +async fn handle_meili_tools( + index_scheduler: &GuardedData, Data>, + auth_ctrl: &web::Data, + search_queue: &web::Data, + auth_token: &str, + chat_settings: &GlobalChatSettings, + tx: &SseEventSender, + meili_calls: Vec, + chat_completion: &mut CreateChatCompletionRequest, + resp: &CreateChatCompletionStreamResponse, + FunctionSupport { report_progress, report_sources, append_to_conversation, .. }: FunctionSupport, +) -> Result<(), SendError> { + for call in meili_calls { + if report_progress { + tx.report_search_progress( + resp.clone(), + &call.id, + &call.function.name, + &call.function.arguments, + ) + .await?; + } -impl MeiliSearchSources { - fn create_response( - &self, - mut resp: CreateChatCompletionStreamResponse, - ) -> CreateChatCompletionStreamResponse { - let call_text = serde_json::to_string(self).unwrap(); - let tool_call = ChatCompletionMessageToolCallChunk { - index: 0, - id: Some(uuid::Uuid::new_v4().to_string()), - r#type: Some(ChatCompletionToolType::Function), - function: Some(FunctionCallStream { - name: Some(MEILI_SEARCH_SOURCES_NAME.to_string()), - arguments: Some(call_text), - }), + if append_to_conversation { + tx.append_tool_call_conversation_message( + resp.clone(), + call.id.clone(), + call.function.name.clone(), + call.function.arguments.clone(), + ) + .await?; + } + + let result = match serde_json::from_str(&call.function.arguments) { + Ok(SearchInIndexParameters { index_uid, q }) => process_search_request( + &index_scheduler, + auth_ctrl.clone(), + &search_queue, + &auth_token, + index_uid, + q, + ) + .await + .map_err(|e| e.to_string()), + Err(err) => Err(err.to_string()), }; - resp.choices[0] = ChatChoiceStream { - index: 0, - delta: ChatCompletionStreamResponseDelta { - content: None, - function_call: None, - tool_calls: Some(vec![tool_call]), - role: Some(Role::Assistant), - refusal: None, - }, - finish_reason: None, - logprobs: None, + + let text = match result { + Ok((_index, documents, text)) => { + if report_sources { + tx.report_sources(resp.clone(), &call.id, &documents).await?; + } + + text + } + Err(err) => err, }; - resp + + let tool = ChatCompletionRequestMessage::Tool(ChatCompletionRequestToolMessage { + tool_call_id: call.id.clone(), + content: ChatCompletionRequestToolMessageContent::Text(format!( + "{}\n\n{text}", + chat_settings.prompts.as_ref().unwrap().pre_query.as_ref().unwrap() + )), + }); + + if append_to_conversation { + tx.append_conversation_message(resp.clone(), &tool).await?; + } + + chat_completion.messages.push(tool); } + + Ok(()) } -struct MeiliAppendConversationMessage(pub ChatCompletionRequestMessage); +pub struct SseEventSender(Sender); -impl MeiliAppendConversationMessage { - fn create_response( +impl SseEventSender { + /// Ask the front-end user to append this tool *call* to the conversation + pub async fn append_tool_call_conversation_message( + &self, + resp: CreateChatCompletionStreamResponse, + call_id: String, + function_name: String, + function_arguments: String, + ) -> Result<(), SendError> { + let message = + ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { + content: None, + refusal: None, + name: None, + audio: None, + tool_calls: Some(vec![ChatCompletionMessageToolCall { + id: call_id, + r#type: Some(ChatCompletionToolType::Function), + function: FunctionCall { name: function_name, arguments: function_arguments }, + }]), + function_call: None, + }); + + self.append_conversation_message(resp, &message).await + } + + /// Ask the front-end user to append this tool to the conversation + pub async fn append_conversation_message( &self, mut resp: CreateChatCompletionStreamResponse, - ) -> CreateChatCompletionStreamResponse { - let call_text = serde_json::to_string(&self.0).unwrap(); + message: &ChatCompletionRequestMessage, + ) -> Result<(), SendError> { + let call_text = serde_json::to_string(message).unwrap(); let tool_call = ChatCompletionMessageToolCallChunk { index: 0, id: Some(uuid::Uuid::new_v4().to_string()), @@ -798,6 +732,7 @@ impl MeiliAppendConversationMessage { arguments: Some(call_text), }), }; + resp.choices[0] = ChatChoiceStream { index: 0, delta: ChatCompletionStreamResponseDelta { @@ -810,7 +745,132 @@ impl MeiliAppendConversationMessage { finish_reason: None, logprobs: None, }; - resp + + self.send_json(&resp).await + } + + pub async fn report_search_progress( + &self, + mut resp: CreateChatCompletionStreamResponse, + call_id: &str, + function_name: &str, + function_arguments: &str, + ) -> Result<(), SendError> { + #[derive(Debug, Clone, Serialize)] + /// Provides information about the current Meilisearch search operation. + struct MeiliSearchProgress<'a> { + /// The call ID to track the sources of the search. + call_id: &'a str, + /// The name of the function we are executing. + function_name: &'a str, + /// The arguments of the function we are executing, encoded in JSON. + function_arguments: &'a str, + } + + let progress = MeiliSearchProgress { call_id, function_name, function_arguments }; + let call_text = serde_json::to_string(&progress).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_SEARCH_PROGRESS_NAME.to_string()), + arguments: Some(call_text), + }), + }; + + resp.choices[0] = ChatChoiceStream { + index: 0, + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + + self.send_json(&resp).await + } + + pub async fn report_sources( + &self, + mut resp: CreateChatCompletionStreamResponse, + call_id: &str, + documents: &[Document], + ) -> Result<(), SendError> { + #[derive(Debug, Clone, Serialize)] + /// Provides sources of the search. + struct MeiliSearchSources<'a> { + /// The call ID to track the original search associated to those sources. + call_id: &'a str, + /// The documents associated with the search (call_id). + /// Only the displayed attributes of the documents are returned. + sources: &'a [Document], + } + + let sources = MeiliSearchSources { call_id, sources: documents }; + let call_text = serde_json::to_string(&sources).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_SEARCH_SOURCES_NAME.to_string()), + arguments: Some(call_text), + }), + }; + + resp.choices[0] = ChatChoiceStream { + index: 0, + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + + self.send_json(&resp).await + } + + pub async fn report_error(&self, error: OpenAIError) -> Result<(), SendError> { + tracing::error!("OpenAI Error: {}", error); + + let (error_code, message) = match error { + OpenAIError::Reqwest(e) => ("internal_reqwest_error", e.to_string()), + OpenAIError::ApiError(api_error) => ("llm_api_issue", api_error.to_string()), + OpenAIError::JSONDeserialize(error) => ("internal_json_deserialize", error.to_string()), + OpenAIError::FileSaveError(_) | OpenAIError::FileReadError(_) => unreachable!(), + OpenAIError::StreamError(error) => ("llm_api_stream_error", error.to_string()), + OpenAIError::InvalidArgument(error) => ("internal_invalid_argument", error.to_string()), + }; + + self.send_json(&json!({ + "error_code": error_code, + "message": message, + })) + .await + } + + pub async fn forward_response( + &self, + resp: &CreateChatCompletionStreamResponse, + ) -> Result<(), SendError> { + self.send_json(resp).await + } + + pub async fn stop(self) -> Result<(), SendError> { + self.0.send(Event::Data(sse::Data::new("[DONE]"))).await + } + + async fn send_json(&self, data: &S) -> Result<(), SendError> { + self.0.send(Event::Data(sse::Data::new_json(data).unwrap())).await } } @@ -822,7 +882,7 @@ enum Call { Internal { id: String, function_name: String, arguments: String }, /// Tool calls that we track but only to know that its not our functions. /// We return the function calls as-is to the end-user. - External { _id: String }, + External, } impl Call { From 2821163b9557a01113cb0b0c1565d9e90ac33e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 28 May 2025 14:22:53 +0200 Subject: [PATCH 160/292] Clean up the code a bit --- crates/meilisearch/src/routes/chat.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 9de15f751..d2fe4ee3a 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -247,8 +247,8 @@ async fn process_search_request( embedder, }), limit: limit.unwrap_or_else(DEFAULT_SEARCH_LIMIT), - sort: sort, - distinct: distinct, + sort, + distinct, matching_strategy: matching_strategy .map(|ms| match ms { index::MatchingStrategy::Last => MatchingStrategy::Last, @@ -256,7 +256,7 @@ async fn process_search_request( index::MatchingStrategy::Frequency => MatchingStrategy::Frequency, }) .unwrap_or(MatchingStrategy::Frequency), - attributes_to_search_on: attributes_to_search_on, + attributes_to_search_on, ranking_score_threshold: ranking_score_threshold .and_then(|rst| RankingScoreThreshold::try_from(rst).ok()), ..Default::default() From 50fafbbc8ba3caaee150957b3bdcaddf2d2cb22e Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Fri, 30 May 2025 10:54:32 +0200 Subject: [PATCH 161/292] Implement useful conversion strategies and clean up the code --- crates/meilisearch/src/routes/chat.rs | 43 +----- crates/meilisearch/src/search/mod.rs | 86 +++++++++++- crates/milli/src/index.rs | 49 ++++++- crates/milli/src/prompt/mod.rs | 2 +- crates/milli/src/search/mod.rs | 11 ++ crates/milli/src/update/chat.rs | 72 +--------- crates/milli/src/update/settings.rs | 163 ++++++++++------------- crates/milli/src/update/test_settings.rs | 1 + 8 files changed, 224 insertions(+), 203 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index d2fe4ee3a..1cc5f1012 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -29,7 +29,7 @@ use meilisearch_auth::AuthController; use meilisearch_types::error::ResponseError; use meilisearch_types::heed::RoTxn; use meilisearch_types::keys::actions; -use meilisearch_types::milli::index::{self, ChatConfig, SearchParameters}; +use meilisearch_types::milli::index::ChatConfig; use meilisearch_types::milli::prompt::{Prompt, PromptData}; use meilisearch_types::milli::update::new::document::DocumentFromDb; use meilisearch_types::milli::update::Setting; @@ -50,11 +50,7 @@ use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::{extract_token_from_request, GuardedData, Policy as _}; use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; use crate::routes::indexes::search::search_kind; -use crate::search::{ - add_search_rules, prepare_search, search_from_kind, HybridQuery, MatchingStrategy, - RankingScoreThreshold, SearchQuery, SemanticRatio, DEFAULT_SEARCH_LIMIT, - DEFAULT_SEMANTIC_RATIO, -}; +use crate::search::{add_search_rules, prepare_search, search_from_kind, SearchQuery}; use crate::search_queue::SearchQueue; const MEILI_SEARCH_PROGRESS_NAME: &str = "_meiliSearchProgress"; @@ -228,40 +224,7 @@ async fn process_search_request( let index = index_scheduler.index(&index_uid)?; let rtxn = index.static_read_txn()?; let ChatConfig { description: _, prompt: _, search_parameters } = index.chat_config(&rtxn)?; - let SearchParameters { - hybrid, - limit, - sort, - distinct, - matching_strategy, - attributes_to_search_on, - ranking_score_threshold, - } = search_parameters; - - let mut query = SearchQuery { - q, - hybrid: hybrid.map(|index::HybridQuery { semantic_ratio, embedder }| HybridQuery { - semantic_ratio: SemanticRatio::try_from(semantic_ratio) - .ok() - .unwrap_or_else(DEFAULT_SEMANTIC_RATIO), - embedder, - }), - limit: limit.unwrap_or_else(DEFAULT_SEARCH_LIMIT), - sort, - distinct, - matching_strategy: matching_strategy - .map(|ms| match ms { - index::MatchingStrategy::Last => MatchingStrategy::Last, - index::MatchingStrategy::All => MatchingStrategy::All, - index::MatchingStrategy::Frequency => MatchingStrategy::Frequency, - }) - .unwrap_or(MatchingStrategy::Frequency), - attributes_to_search_on, - ranking_score_threshold: ranking_score_threshold - .and_then(|rst| RankingScoreThreshold::try_from(rst).ok()), - ..Default::default() - }; - + let mut query = SearchQuery { q, ..SearchQuery::from(search_parameters) }; let auth_filter = ActionPolicy::<{ actions::SEARCH }>::authenticate( auth_ctrl, auth_token, diff --git a/crates/meilisearch/src/search/mod.rs b/crates/meilisearch/src/search/mod.rs index 848591a4f..037083b2d 100644 --- a/crates/meilisearch/src/search/mod.rs +++ b/crates/meilisearch/src/search/mod.rs @@ -16,6 +16,7 @@ use meilisearch_types::error::{Code, ResponseError}; use meilisearch_types::heed::RoTxn; use meilisearch_types::index_uid::IndexUid; use meilisearch_types::locales::Locale; +use meilisearch_types::milli::index::{self, SearchParameters}; use meilisearch_types::milli::score_details::{ScoreDetails, ScoringStrategy}; use meilisearch_types::milli::vector::parsed_vectors::ExplicitVectors; use meilisearch_types::milli::vector::Embedder; @@ -56,7 +57,7 @@ pub const DEFAULT_HIGHLIGHT_PRE_TAG: fn() -> String = || "".to_string(); pub const DEFAULT_HIGHLIGHT_POST_TAG: fn() -> String = || "".to_string(); pub const DEFAULT_SEMANTIC_RATIO: fn() -> SemanticRatio = || SemanticRatio(0.5); -#[derive(Clone, Default, PartialEq, Deserr, ToSchema)] +#[derive(Clone, PartialEq, Deserr, ToSchema)] #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct SearchQuery { #[deserr(default, error = DeserrJsonError)] @@ -119,6 +120,69 @@ pub struct SearchQuery { pub locales: Option>, } +impl From for SearchQuery { + fn from(parameters: SearchParameters) -> Self { + let SearchParameters { + hybrid, + limit, + sort, + distinct, + matching_strategy, + attributes_to_search_on, + ranking_score_threshold, + } = parameters; + + SearchQuery { + hybrid: hybrid.map(|index::HybridQuery { semantic_ratio, embedder }| HybridQuery { + semantic_ratio: SemanticRatio::try_from(semantic_ratio) + .ok() + .unwrap_or_else(DEFAULT_SEMANTIC_RATIO), + embedder, + }), + limit: limit.unwrap_or_else(DEFAULT_SEARCH_LIMIT), + sort, + distinct, + matching_strategy: matching_strategy.map(MatchingStrategy::from).unwrap_or_default(), + attributes_to_search_on, + ranking_score_threshold: ranking_score_threshold.map(RankingScoreThreshold::from), + ..Default::default() + } + } +} + +impl Default for SearchQuery { + fn default() -> Self { + SearchQuery { + q: None, + vector: None, + hybrid: None, + offset: DEFAULT_SEARCH_OFFSET(), + limit: DEFAULT_SEARCH_LIMIT(), + page: None, + hits_per_page: None, + attributes_to_retrieve: None, + retrieve_vectors: false, + attributes_to_crop: None, + crop_length: DEFAULT_CROP_LENGTH(), + attributes_to_highlight: None, + show_matches_position: false, + show_ranking_score: false, + show_ranking_score_details: false, + filter: None, + sort: None, + distinct: None, + facets: None, + highlight_pre_tag: DEFAULT_HIGHLIGHT_PRE_TAG(), + highlight_post_tag: DEFAULT_HIGHLIGHT_POST_TAG(), + crop_marker: DEFAULT_CROP_MARKER(), + matching_strategy: Default::default(), + attributes_to_search_on: None, + ranking_score_threshold: None, + locales: None, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Deserr, ToSchema, Serialize)] #[deserr(try_from(f64) = TryFrom::try_from -> InvalidSearchRankingScoreThreshold)] pub struct RankingScoreThreshold(f64); @@ -137,6 +201,14 @@ impl std::convert::TryFrom for RankingScoreThreshold { } } +impl From for RankingScoreThreshold { + fn from(threshold: index::RankingScoreThreshold) -> Self { + let threshold = threshold.as_f64(); + assert!(threshold >= 0.0 && threshold <= 1.0); + RankingScoreThreshold(threshold) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Deserr)] #[deserr(try_from(f64) = TryFrom::try_from -> InvalidSimilarRankingScoreThreshold)] pub struct RankingScoreThresholdSimilar(f64); @@ -718,6 +790,16 @@ impl From for TermsMatchingStrategy { } } +impl From for MatchingStrategy { + fn from(other: index::MatchingStrategy) -> Self { + match other { + index::MatchingStrategy::Last => Self::Last, + index::MatchingStrategy::All => Self::All, + index::MatchingStrategy::Frequency => Self::Frequency, + } + } +} + #[derive(Debug, Default, Clone, PartialEq, Eq, Deserr)] #[deserr(rename_all = camelCase)] pub enum FacetValuesSort { @@ -1261,7 +1343,7 @@ struct HitMaker<'a> { vectors_fid: Option, retrieve_vectors: RetrieveVectors, to_retrieve_ids: BTreeSet, - embedding_configs: Vec, + embedding_configs: Vec, formatter_builder: MatcherBuilder<'a>, formatted_options: BTreeMap, show_ranking_score: bool, diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index e6f28d02e..b2df46af3 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -1,14 +1,18 @@ use std::borrow::Cow; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::error::Error; +use std::fmt; use std::fs::File; use std::path::Path; +use deserr::Deserr; use heed::types::*; use heed::{CompactionOption, Database, DatabaseStat, RoTxn, RwTxn, Unspecified, WithoutTls}; use indexmap::IndexMap; use roaring::RoaringBitmap; use rstar::RTree; use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; use crate::constants::{self, RESERVED_GEO_FIELD_NAME, RESERVED_VECTORS_FIELD_NAME}; use crate::database_stats::DatabaseStats; @@ -25,6 +29,7 @@ use crate::heed_codec::{BEU16StrCodec, FstSetCodec, StrBEU16Codec, StrRefCodec}; use crate::order_by_map::OrderByMap; use crate::prompt::PromptData; use crate::proximity::ProximityPrecision; +use crate::update::new::StdResult; use crate::vector::{ArroyStats, ArroyWrapper, Embedding, EmbeddingConfig}; use crate::{ default_criteria, CboRoaringBitmapCodec, Criterion, DocumentId, ExternalDocumentsIds, @@ -1962,10 +1967,46 @@ pub struct SearchParameters { #[serde(skip_serializing_if = "Option::is_none")] pub attributes_to_search_on: Option>, #[serde(skip_serializing_if = "Option::is_none")] - pub ranking_score_threshold: Option, + pub ranking_score_threshold: Option, } -#[derive(Debug, Default, Deserialize, Serialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Deserr, ToSchema)] +#[deserr(try_from(f64) = TryFrom::try_from -> InvalidSearchRankingScoreThreshold)] +pub struct RankingScoreThreshold(f64); + +impl RankingScoreThreshold { + pub fn as_f64(&self) -> f64 { + self.0 + } +} + +impl TryFrom for RankingScoreThreshold { + type Error = InvalidSearchRankingScoreThreshold; + + fn try_from(value: f64) -> StdResult { + if value < 0.0 || value > 1.0 { + Err(InvalidSearchRankingScoreThreshold) + } else { + Ok(RankingScoreThreshold(value)) + } + } +} + +#[derive(Debug)] +pub struct InvalidSearchRankingScoreThreshold; + +impl Error for InvalidSearchRankingScoreThreshold {} + +impl fmt::Display for InvalidSearchRankingScoreThreshold { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "the value of `rankingScoreThreshold` is invalid, expected a float between `0.0` and `1.0`." + ) + } +} + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct HybridQuery { pub semantic_ratio: f32, @@ -1980,10 +2021,12 @@ pub struct PrefixSettings { pub compute_prefixes: PrefixSearch, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Deserr, ToSchema, Serialize, Deserialize)] +#[deserr(rename_all = camelCase)] #[serde(rename_all = "camelCase")] pub enum MatchingStrategy { /// Remove query words from last to first + #[default] Last, /// All query words are mandatory All, diff --git a/crates/milli/src/prompt/mod.rs b/crates/milli/src/prompt/mod.rs index d40fcd27f..a8288f83d 100644 --- a/crates/milli/src/prompt/mod.rs +++ b/crates/milli/src/prompt/mod.rs @@ -64,7 +64,7 @@ fn default_template() -> liquid::Template { new_template(default_template_text()).unwrap() } -fn default_template_text() -> &'static str { +pub fn default_template_text() -> &'static str { "{% for field in fields %}\ {% if field.is_searchable and field.value != nil %}\ {{ field.name }}: {{ field.value }}\n\ diff --git a/crates/milli/src/search/mod.rs b/crates/milli/src/search/mod.rs index 37b1aaf09..62183afc3 100644 --- a/crates/milli/src/search/mod.rs +++ b/crates/milli/src/search/mod.rs @@ -10,6 +10,7 @@ pub use self::facet::{FacetDistribution, Filter, OrderBy, DEFAULT_VALUES_PER_FAC pub use self::new::matches::{FormatOptions, MatchBounds, MatcherBuilder, MatchingWords}; use self::new::{execute_vector_search, PartialSearchResult, VectorStoreStats}; use crate::filterable_attributes_rules::{filtered_matching_patterns, matching_features}; +use crate::index::MatchingStrategy; use crate::score_details::{ScoreDetails, ScoringStrategy}; use crate::vector::Embedder; use crate::{ @@ -364,6 +365,16 @@ impl Default for TermsMatchingStrategy { } } +impl From for TermsMatchingStrategy { + fn from(other: MatchingStrategy) -> Self { + match other { + MatchingStrategy::Last => Self::Last, + MatchingStrategy::All => Self::All, + MatchingStrategy::Frequency => Self::Frequency, + } + } +} + fn get_first(s: &str) -> &str { match s.chars().next() { Some(c) => &s[..c.len_utf8()], diff --git a/crates/milli/src/update/chat.rs b/crates/milli/src/update/chat.rs index b8fbc582d..ae95ddfd9 100644 --- a/crates/milli/src/update/chat.rs +++ b/crates/milli/src/update/chat.rs @@ -6,10 +6,9 @@ use deserr::Deserr; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; -use crate::index::{self, ChatConfig, SearchParameters}; +use crate::index::{self, ChatConfig, MatchingStrategy, RankingScoreThreshold, SearchParameters}; use crate::prompt::{default_max_bytes, PromptData}; use crate::update::Setting; -use crate::TermsMatchingStrategy; #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Deserr, ToSchema)] #[serde(deny_unknown_fields, rename_all = "camelCase")] @@ -70,13 +69,10 @@ impl From for ChatSettings { HybridQuery { semantic_ratio: SemanticRatio(semantic_ratio), embedder } }); - let matching_strategy = matching_strategy.map(|ms| match ms { - index::MatchingStrategy::Last => MatchingStrategy::Last, - index::MatchingStrategy::All => MatchingStrategy::All, - index::MatchingStrategy::Frequency => MatchingStrategy::Frequency, - }); + let matching_strategy = matching_strategy.map(MatchingStrategy::from); - let ranking_score_threshold = ranking_score_threshold.map(RankingScoreThreshold); + let ranking_score_threshold = + ranking_score_threshold.map(RankingScoreThreshold::from); ChatSearchParams { hybrid: Setting::some_or_not_set(hybrid), @@ -197,63 +193,3 @@ impl std::ops::Deref for SemanticRatio { &self.0 } } - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserr, ToSchema, Serialize, Deserialize)] -#[deserr(rename_all = camelCase)] -#[serde(rename_all = "camelCase")] -pub enum MatchingStrategy { - /// Remove query words from last to first - Last, - /// All query words are mandatory - All, - /// Remove query words from the most frequent to the least - Frequency, -} - -impl Default for MatchingStrategy { - fn default() -> Self { - Self::Last - } -} - -impl From for TermsMatchingStrategy { - fn from(other: MatchingStrategy) -> Self { - match other { - MatchingStrategy::Last => Self::Last, - MatchingStrategy::All => Self::All, - MatchingStrategy::Frequency => Self::Frequency, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserr, ToSchema, Serialize, Deserialize)] -#[deserr(try_from(f64) = TryFrom::try_from -> InvalidSearchRankingScoreThreshold)] -pub struct RankingScoreThreshold(pub f64); - -impl std::convert::TryFrom for RankingScoreThreshold { - type Error = InvalidSearchRankingScoreThreshold; - - fn try_from(f: f64) -> Result { - // the suggested "fix" is: `!(0.0..=1.0).contains(&f)`` which is allegedly less readable - #[allow(clippy::manual_range_contains)] - if f > 1.0 || f < 0.0 { - Err(InvalidSearchRankingScoreThreshold) - } else { - Ok(RankingScoreThreshold(f)) - } - } -} - -#[derive(Debug)] -pub struct InvalidSearchRankingScoreThreshold; - -impl Error for InvalidSearchRankingScoreThreshold {} - -impl fmt::Display for InvalidSearchRankingScoreThreshold { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "the value of `rankingScoreThreshold` is invalid, expected a float between `0.0` and `1.0`." - ) - } -} diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index bb589c5ee..9f152710a 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -11,7 +11,7 @@ use roaring::RoaringBitmap; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use time::OffsetDateTime; -use super::chat::{ChatSearchParams, RankingScoreThreshold}; +use super::chat::ChatSearchParams; use super::del_add::{DelAdd, DelAddOperation}; use super::index_documents::{IndexDocumentsConfig, Transform}; use super::{ChatSettings, IndexerConfig}; @@ -23,11 +23,11 @@ use crate::error::UserError; use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder}; use crate::filterable_attributes_rules::match_faceted_field; use crate::index::{ - ChatConfig, IndexEmbeddingConfig, MatchingStrategy, PrefixSearch, - DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS, + ChatConfig, IndexEmbeddingConfig, MatchingStrategy, PrefixSearch, RankingScoreThreshold, + SearchParameters, DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS, }; use crate::order_by_map::OrderByMap; -use crate::prompt::{default_max_bytes, PromptData}; +use crate::prompt::{default_max_bytes, default_template_text, PromptData}; use crate::proximity::ProximityPrecision; use crate::update::index_documents::IndexDocumentsMethod; use crate::update::{IndexDocuments, UpdateIndexingStep}; @@ -1266,32 +1266,29 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { document_template_max_bytes: new_document_template_max_bytes, search_parameters: new_search_parameters, }) => { - let mut old = self.index.chat_config(self.wtxn)?; - let ChatConfig { - ref mut description, - prompt: PromptData { ref mut template, ref mut max_bytes }, - ref mut search_parameters, - } = old; + let ChatConfig { description, prompt, search_parameters } = + self.index.chat_config(self.wtxn)?; - match new_description { - Setting::Set(d) => *description = d.clone(), - Setting::Reset => *description = Default::default(), - Setting::NotSet => (), - } + let description = match new_description { + Setting::Set(new) => new.clone(), + Setting::Reset => Default::default(), + Setting::NotSet => description, + }; - match new_document_template { - Setting::Set(dt) => *template = dt.clone(), - Setting::Reset => *template = Default::default(), - Setting::NotSet => (), - } + let prompt = PromptData { + template: match new_document_template { + Setting::Set(new) => new.clone(), + Setting::Reset => default_template_text().to_string(), + Setting::NotSet => prompt.template.clone(), + }, + max_bytes: match new_document_template_max_bytes { + Setting::Set(m) => NonZeroUsize::new(*m), + Setting::Reset => Some(default_max_bytes()), + Setting::NotSet => prompt.max_bytes, + }, + }; - match new_document_template_max_bytes { - Setting::Set(m) => *max_bytes = NonZeroUsize::new(*m), - Setting::Reset => *max_bytes = Some(default_max_bytes()), - Setting::NotSet => (), - } - - match new_search_parameters { + let search_parameters = match new_search_parameters { Setting::Set(sp) => { let ChatSearchParams { hybrid, @@ -1303,74 +1300,62 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { ranking_score_threshold, } = sp; - match hybrid { - Setting::Set(hybrid) => { - search_parameters.hybrid = Some(crate::index::HybridQuery { + SearchParameters { + hybrid: match hybrid { + Setting::Set(hybrid) => Some(crate::index::HybridQuery { semantic_ratio: *hybrid.semantic_ratio, embedder: hybrid.embedder.clone(), - }) - } - Setting::Reset => search_parameters.hybrid = None, - Setting::NotSet => (), - } - - match limit { - Setting::Set(limit) => search_parameters.limit = Some(*limit), - Setting::Reset => search_parameters.limit = None, - Setting::NotSet => (), - } - - match sort { - Setting::Set(sort) => search_parameters.sort = Some(sort.clone()), - Setting::Reset => search_parameters.sort = None, - Setting::NotSet => (), - } - - match distinct { - Setting::Set(distinct) => { - search_parameters.distinct = Some(distinct.clone()) - } - Setting::Reset => search_parameters.distinct = None, - Setting::NotSet => (), - } - - match matching_strategy { - Setting::Set(matching_strategy) => { - let strategy = match matching_strategy { - super::chat::MatchingStrategy::Last => MatchingStrategy::Last, - super::chat::MatchingStrategy::All => MatchingStrategy::All, - super::chat::MatchingStrategy::Frequency => { - MatchingStrategy::Frequency - } - }; - search_parameters.matching_strategy = Some(strategy) - } - Setting::Reset => search_parameters.matching_strategy = None, - Setting::NotSet => (), - } - - match attributes_to_search_on { - Setting::Set(attributes_to_search_on) => { - search_parameters.attributes_to_search_on = + }), + Setting::Reset => None, + Setting::NotSet => search_parameters.hybrid.clone(), + }, + limit: match limit { + Setting::Set(limit) => Some(*limit), + Setting::Reset => None, + Setting::NotSet => search_parameters.limit, + }, + sort: match sort { + Setting::Set(sort) => Some(sort.clone()), + Setting::Reset => None, + Setting::NotSet => search_parameters.sort.clone(), + }, + distinct: match distinct { + Setting::Set(distinct) => Some(distinct.clone()), + Setting::Reset => None, + Setting::NotSet => search_parameters.distinct.clone(), + }, + matching_strategy: match matching_strategy { + Setting::Set(matching_strategy) => { + Some(MatchingStrategy::from(*matching_strategy)) + } + Setting::Reset => None, + Setting::NotSet => search_parameters.matching_strategy, + }, + attributes_to_search_on: match attributes_to_search_on { + Setting::Set(attributes_to_search_on) => { Some(attributes_to_search_on.clone()) - } - Setting::Reset => search_parameters.attributes_to_search_on = None, - Setting::NotSet => (), - } - - match ranking_score_threshold { - Setting::Set(RankingScoreThreshold(score)) => { - search_parameters.ranking_score_threshold = Some(*score) - } - Setting::Reset => search_parameters.ranking_score_threshold = None, - Setting::NotSet => (), + } + Setting::Reset => None, + Setting::NotSet => { + search_parameters.attributes_to_search_on.clone() + } + }, + ranking_score_threshold: match ranking_score_threshold { + Setting::Set(rst) => Some(RankingScoreThreshold::from(*rst)), + Setting::Reset => None, + Setting::NotSet => search_parameters.ranking_score_threshold, + }, } } - Setting::Reset => *search_parameters = Default::default(), - Setting::NotSet => (), - } + Setting::Reset => Default::default(), + Setting::NotSet => search_parameters, + }; + + self.index.put_chat_config( + self.wtxn, + &ChatConfig { description, prompt, search_parameters }, + )?; - self.index.put_chat_config(self.wtxn, &old)?; Ok(true) } Setting::Reset => self.index.delete_chat_config(self.wtxn), diff --git a/crates/milli/src/update/test_settings.rs b/crates/milli/src/update/test_settings.rs index e775c226f..e78765cfb 100644 --- a/crates/milli/src/update/test_settings.rs +++ b/crates/milli/src/update/test_settings.rs @@ -926,6 +926,7 @@ fn test_correct_settings_init() { assert!(matches!(prefix_search, Setting::NotSet)); assert!(matches!(facet_search, Setting::NotSet)); assert!(matches!(disable_on_numbers, Setting::NotSet)); + assert!(matches!(chat, Setting::NotSet)); }) .unwrap(); } From 0f7f5fa10495a7463818b9fb46139871b5e95bf2 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Fri, 30 May 2025 12:12:47 +0200 Subject: [PATCH 162/292] Introduce listing/getting/deleting/updating chat workspace settings --- crates/index-scheduler/src/lib.rs | 58 +++++++++---- crates/index-scheduler/src/scheduler/test.rs | 4 +- crates/meilisearch-types/src/keys.rs | 43 +++++---- .../{chat.rs => chats/chat_completions.rs} | 41 +++++++-- crates/meilisearch/src/routes/chats/mod.rs | 87 +++++++++++++++++++ .../{settings/chat.rs => chats/settings.rs} | 50 +++++++++-- crates/meilisearch/src/routes/indexes/mod.rs | 2 +- crates/meilisearch/src/routes/mod.rs | 6 +- crates/meilisearch/src/routes/settings/mod.rs | 1 - 9 files changed, 241 insertions(+), 51 deletions(-) rename crates/meilisearch/src/routes/{chat.rs => chats/chat_completions.rs} (96%) create mode 100644 crates/meilisearch/src/routes/chats/mod.rs rename crates/meilisearch/src/routes/{settings/chat.rs => chats/settings.rs} (80%) delete mode 100644 crates/meilisearch/src/routes/settings/mod.rs diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 9fb92f041..261fe030c 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -54,7 +54,7 @@ use meilisearch_types::batches::Batch; use meilisearch_types::features::{InstanceTogglableFeatures, Network, RuntimeTogglableFeatures}; use meilisearch_types::heed::byteorder::BE; use meilisearch_types::heed::types::{SerdeJson, Str, I128}; -use meilisearch_types::heed::{self, Database, Env, RoTxn, WithoutTls}; +use meilisearch_types::heed::{self, Database, Env, RoTxn, RwTxn, WithoutTls}; use meilisearch_types::milli::index::IndexEmbeddingConfig; use meilisearch_types::milli::update::IndexerConfig; use meilisearch_types::milli::vector::{Embedder, EmbedderOptions, EmbeddingConfigs}; @@ -154,7 +154,7 @@ pub struct IndexScheduler { features: features::FeatureData, /// Stores the custom chat prompts and other settings of the indexes. - chat_settings: Database>, + pub(crate) chat_settings: Database>, /// Everything related to the processing of the tasks pub scheduler: scheduler::Scheduler, @@ -308,6 +308,14 @@ impl IndexScheduler { Ok(this) } + pub fn write_txn(&self) -> Result { + self.env.write_txn().map_err(|e| e.into()) + } + + pub fn read_txn(&self) -> Result> { + self.env.read_txn().map_err(|e| e.into()) + } + /// Return `Ok(())` if the index scheduler is able to access one of its database. pub fn health(&self) -> Result<()> { let rtxn = self.env.read_txn()?; @@ -384,10 +392,6 @@ impl IndexScheduler { } } - pub fn read_txn(&self) -> Result> { - self.env.read_txn().map_err(|e| e.into()) - } - /// Start the run loop for the given index scheduler. /// /// This function will execute in a different thread and must be called @@ -505,7 +509,7 @@ impl IndexScheduler { /// Returns the total number of indexes available for the specified filter. /// And a `Vec` of the index_uid + its stats - pub fn get_paginated_indexes_stats( + pub fn paginated_indexes_stats( &self, filters: &meilisearch_auth::AuthFilter, from: usize, @@ -546,6 +550,25 @@ impl IndexScheduler { ret.map(|ret| (total, ret)) } + /// Returns the total number of chat workspaces available ~~for the specified filter~~. + /// And a `Vec` of the workspace_uids + pub fn paginated_chat_workspace_uids( + &self, + _filters: &meilisearch_auth::AuthFilter, + from: usize, + limit: usize, + ) -> Result<(usize, Vec)> { + let rtxn = self.read_txn()?; + let total = self.chat_settings.len(&rtxn)?; + let mut iter = self.chat_settings.iter(&rtxn)?.skip(from); + iter.by_ref() + .take(limit) + .map(|ret| ret.map_err(Error::from)) + .map(|ret| ret.map(|(uid, _)| uid.to_string())) + .collect::, Error>>() + .map(|ret| (total as usize, ret)) + } + /// The returned structure contains: /// 1. The name of the property being observed can be `statuses`, `types`, or `indexes`. /// 2. The name of the specific data related to the property can be `enqueued` for the `statuses`, `settingsUpdate` for the `types`, or the name of the index for the `indexes`, for example. @@ -875,16 +898,21 @@ impl IndexScheduler { res.map(EmbeddingConfigs::new) } - pub fn chat_settings(&self) -> Result> { - let rtxn = self.env.read_txn().map_err(Error::HeedTransaction)?; - self.chat_settings.get(&rtxn, "main").map_err(Into::into) + pub fn chat_settings(&self, rtxn: &RoTxn, uid: &str) -> Result> { + self.chat_settings.get(rtxn, uid).map_err(Into::into) } - pub fn put_chat_settings(&self, settings: &serde_json::Value) -> Result<()> { - let mut wtxn = self.env.write_txn().map_err(Error::HeedTransaction)?; - self.chat_settings.put(&mut wtxn, "main", settings)?; - wtxn.commit().map_err(Error::HeedTransaction)?; - Ok(()) + pub fn put_chat_settings( + &self, + wtxn: &mut RwTxn, + uid: &str, + settings: &serde_json::Value, + ) -> Result<()> { + self.chat_settings.put(wtxn, uid, settings).map_err(Into::into) + } + + pub fn delete_chat_settings(&self, wtxn: &mut RwTxn, uid: &str) -> Result { + self.chat_settings.delete(wtxn, uid).map_err(Into::into) } } diff --git a/crates/index-scheduler/src/scheduler/test.rs b/crates/index-scheduler/src/scheduler/test.rs index f13af9f87..06bc14051 100644 --- a/crates/index-scheduler/src/scheduler/test.rs +++ b/crates/index-scheduler/src/scheduler/test.rs @@ -894,7 +894,7 @@ fn create_and_list_index() { let err = index_scheduler.index("kefir").map(|_| ()).unwrap_err(); snapshot!(err, @"Index `kefir` not found."); - let empty = index_scheduler.get_paginated_indexes_stats(&AuthFilter::default(), 0, 20).unwrap(); + let empty = index_scheduler.paginated_indexes_stats(&AuthFilter::default(), 0, 20).unwrap(); snapshot!(format!("{empty:?}"), @"(0, [])"); // After advancing just once the index should've been created, the wtxn has been released and commited @@ -902,7 +902,7 @@ fn create_and_list_index() { handle.advance_till([InsideProcessBatch]); index_scheduler.index("kefir").unwrap(); - let list = index_scheduler.get_paginated_indexes_stats(&AuthFilter::default(), 0, 20).unwrap(); + let list = index_scheduler.paginated_indexes_stats(&AuthFilter::default(), 0, 20).unwrap(); snapshot!(json_string!(list, { "[1][0][1].created_at" => "[date]", "[1][0][1].updated_at" => "[date]", "[1][0][1].used_database_size" => "[bytes]", "[1][0][1].database_size" => "[bytes]" }), @r###" [ 1, diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 1c1ebad5b..e30ef1008 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -323,18 +323,25 @@ pub enum Action { #[serde(rename = "network.update")] #[deserr(rename = "network.update")] NetworkUpdate, + // TODO should we rename it chatCompletions.get ? #[serde(rename = "chat.get")] #[deserr(rename = "chat.get")] Chat, - #[serde(rename = "chatSettings.*")] - #[deserr(rename = "chatSettings.*")] - ChatSettingsAll, - #[serde(rename = "chatSettings.get")] - #[deserr(rename = "chatSettings.get")] - ChatSettingsGet, - #[serde(rename = "chatSettings.update")] - #[deserr(rename = "chatSettings.update")] - ChatSettingsUpdate, + #[serde(rename = "chats.get")] + #[deserr(rename = "chats.get")] + Chats, + #[serde(rename = "chatsSettings.*")] + #[deserr(rename = "chatsSettings.*")] + ChatsSettingsAll, + #[serde(rename = "chatsSettings.get")] + #[deserr(rename = "chatsSettings.get")] + ChatsSettingsGet, + #[serde(rename = "chatsSettings.update")] + #[deserr(rename = "chatsSettings.update")] + ChatsSettingsUpdate, + #[serde(rename = "chatsSettings.delete")] + #[deserr(rename = "chatsSettings.delete")] + ChatsSettingsDelete, } impl Action { @@ -360,9 +367,12 @@ impl Action { SETTINGS_ALL => Some(Self::SettingsAll), SETTINGS_GET => Some(Self::SettingsGet), SETTINGS_UPDATE => Some(Self::SettingsUpdate), - CHAT_SETTINGS_ALL => Some(Self::ChatSettingsAll), - CHAT_SETTINGS_GET => Some(Self::ChatSettingsGet), - CHAT_SETTINGS_UPDATE => Some(Self::ChatSettingsUpdate), + CHAT => Some(Self::Chat), + CHATS_GET => Some(Self::Chats), + CHATS_SETTINGS_ALL => Some(Self::ChatsSettingsAll), + CHATS_SETTINGS_GET => Some(Self::ChatsSettingsGet), + CHATS_SETTINGS_UPDATE => Some(Self::ChatsSettingsUpdate), + CHATS_SETTINGS_DELETE => Some(Self::ChatsSettingsDelete), STATS_ALL => Some(Self::StatsAll), STATS_GET => Some(Self::StatsGet), METRICS_ALL => Some(Self::MetricsAll), @@ -379,7 +389,6 @@ impl Action { EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), NETWORK_GET => Some(Self::NetworkGet), NETWORK_UPDATE => Some(Self::NetworkUpdate), - CHAT => Some(Self::Chat), _otherwise => None, } } @@ -430,7 +439,9 @@ pub mod actions { pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); pub const CHAT: u8 = Chat.repr(); - pub const CHAT_SETTINGS_ALL: u8 = ChatSettingsAll.repr(); - pub const CHAT_SETTINGS_GET: u8 = ChatSettingsGet.repr(); - pub const CHAT_SETTINGS_UPDATE: u8 = ChatSettingsUpdate.repr(); + pub const CHATS_GET: u8 = Chats.repr(); + pub const CHATS_SETTINGS_ALL: u8 = ChatsSettingsAll.repr(); + pub const CHATS_SETTINGS_GET: u8 = ChatsSettingsGet.repr(); + pub const CHATS_SETTINGS_UPDATE: u8 = ChatsSettingsUpdate.repr(); + pub const CHATS_SETTINGS_DELETE: u8 = ChatsSettingsDelete.repr(); } diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs similarity index 96% rename from crates/meilisearch/src/routes/chat.rs rename to crates/meilisearch/src/routes/chats/chat_completions.rs index 1cc5f1012..ee16a33cd 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -44,7 +44,8 @@ use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; use tokio::sync::mpsc::Sender; -use super::settings::chat::{ChatPrompts, GlobalChatSettings}; +use super::settings::{ChatPrompts, GlobalChatSettings}; +use super::ChatsParam; use crate::error::MeilisearchHttpError; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::{extract_token_from_request, GuardedData, Policy as _}; @@ -60,13 +61,14 @@ const MEILI_REPORT_ERRORS_NAME: &str = "_meiliReportErrors"; const MEILI_SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; pub fn configure(cfg: &mut web::ServiceConfig) { - cfg.service(web::resource("/completions").route(web::post().to(chat))); + cfg.service(web::resource("").route(web::post().to(chat))); } /// Get a chat completion async fn chat( index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, + chats_param: web::Path, req: HttpRequest, search_queue: web::Data, web::Json(chat_completion): web::Json, @@ -74,6 +76,8 @@ async fn chat( // To enable later on, when the feature will be experimental // index_scheduler.features().check_chat("Using the /chat route")?; + let ChatsParam { workspace_uid } = chats_param.into_inner(); + assert_eq!( chat_completion.n.unwrap_or(1), 1, @@ -82,11 +86,27 @@ async fn chat( if chat_completion.stream.unwrap_or(false) { Either::Right( - streamed_chat(index_scheduler, auth_ctrl, search_queue, req, chat_completion).await, + streamed_chat( + index_scheduler, + auth_ctrl, + search_queue, + &workspace_uid, + req, + chat_completion, + ) + .await, ) } else { Either::Left( - non_streamed_chat(index_scheduler, auth_ctrl, search_queue, req, chat_completion).await, + non_streamed_chat( + index_scheduler, + auth_ctrl, + search_queue, + &workspace_uid, + req, + chat_completion, + ) + .await, ) } } @@ -294,12 +314,14 @@ async fn non_streamed_chat( index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, search_queue: web::Data, + workspace_uid: &str, req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { let filters = index_scheduler.filters(); - let chat_settings = match index_scheduler.chat_settings().unwrap() { + let rtxn = index_scheduler.read_txn()?; + let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid).unwrap() { Some(value) => serde_json::from_value(value).unwrap(), None => GlobalChatSettings::default(), }; @@ -387,15 +409,18 @@ async fn streamed_chat( index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, search_queue: web::Data, + workspace_uid: &str, req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { let filters = index_scheduler.filters(); - let chat_settings = match index_scheduler.chat_settings().unwrap() { + let rtxn = index_scheduler.read_txn()?; + let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid).unwrap() { Some(value) => serde_json::from_value(value.clone()).unwrap(), None => GlobalChatSettings::default(), }; + drop(rtxn); let mut config = OpenAIConfig::default(); if let Setting::Set(api_key) = chat_settings.api_key.as_ref() { @@ -662,6 +687,7 @@ impl SseEventSender { function_name: String, function_arguments: String, ) -> Result<(), SendError> { + #[allow(deprecated)] let message = ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { content: None, @@ -698,6 +724,7 @@ impl SseEventSender { resp.choices[0] = ChatChoiceStream { index: 0, + #[allow(deprecated)] delta: ChatCompletionStreamResponseDelta { content: None, function_call: None, @@ -744,6 +771,7 @@ impl SseEventSender { resp.choices[0] = ChatChoiceStream { index: 0, + #[allow(deprecated)] delta: ChatCompletionStreamResponseDelta { content: None, function_call: None, @@ -788,6 +816,7 @@ impl SseEventSender { resp.choices[0] = ChatChoiceStream { index: 0, + #[allow(deprecated)] delta: ChatCompletionStreamResponseDelta { content: None, function_call: None, diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs new file mode 100644 index 000000000..00e3b28b5 --- /dev/null +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -0,0 +1,87 @@ +use actix_web::{ + web::{self, Data}, + HttpResponse, +}; +use deserr::{actix_web::AwebQueryParameter, Deserr}; +use index_scheduler::IndexScheduler; +use meilisearch_types::{ + deserr::{query_params::Param, DeserrQueryParamError}, + error::{ + deserr_codes::{InvalidIndexLimit, InvalidIndexOffset}, + ResponseError, + }, + keys::actions, +}; +use serde::{Deserialize, Serialize}; +use tracing::debug; +use utoipa::{IntoParams, ToSchema}; + +use crate::{ + extractors::authentication::{policies::ActionPolicy, GuardedData}, + routes::PAGINATION_DEFAULT_LIMIT, +}; + +use super::Pagination; + +// TODO supports chats/$workspace/settings + /chats/$workspace/chat/completions +pub mod chat_completions; +pub mod settings; + +#[derive(Deserialize)] +pub struct ChatsParam { + workspace_uid: String, +} + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.service(web::resource("").route(web::get().to(list_workspaces))).service( + web::scope("/{workspace_uid}") + .service(web::scope("/chat/completions").configure(chat_completions::configure)) + .service(web::scope("/settings").configure(settings::configure)), + ); +} + +#[derive(Deserr, Debug, Clone, Copy, IntoParams)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] +#[into_params(rename_all = "camelCase", parameter_in = Query)] +pub struct ListChats { + /// The number of chat workspaces to skip before starting to retrieve anything + #[param(value_type = Option, default, example = 100)] + #[deserr(default, error = DeserrQueryParamError)] + pub offset: Param, + /// The number of chat workspaces to retrieve + #[param(value_type = Option, default = 20, example = 1)] + #[deserr(default = Param(PAGINATION_DEFAULT_LIMIT), error = DeserrQueryParamError)] + pub limit: Param, +} + +impl ListChats { + fn as_pagination(self) -> Pagination { + Pagination { offset: self.offset.0, limit: self.limit.0 } + } +} + +#[derive(Debug, Serialize, Clone, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct ChatWorkspaceView { + /// Unique identifier for the index + pub uid: String, +} + +pub async fn list_workspaces( + index_scheduler: GuardedData, Data>, + paginate: AwebQueryParameter, +) -> Result { + debug!(parameters = ?paginate, "List chat workspaces"); + let filters = index_scheduler.filters(); + let (total, workspaces) = index_scheduler.paginated_chat_workspace_uids( + filters, + *paginate.offset, + *paginate.limit, + )?; + let workspaces = + workspaces.into_iter().map(|uid| ChatWorkspaceView { uid }).collect::>(); + let ret = paginate.as_pagination().format_with(total, workspaces); + + debug!(returns = ?ret, "List chat workspaces"); + Ok(HttpResponse::Ok().json(ret)) +} diff --git a/crates/meilisearch/src/routes/settings/chat.rs b/crates/meilisearch/src/routes/chats/settings.rs similarity index 80% rename from crates/meilisearch/src/routes/settings/chat.rs rename to crates/meilisearch/src/routes/chats/settings.rs index 60fd01ab6..0d3f88938 100644 --- a/crates/meilisearch/src/routes/settings/chat.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -10,21 +10,29 @@ use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; use crate::extractors::sequential_extractor::SeqHandler; +use super::ChatsParam; + pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service( web::resource("") .route(web::get().to(get_settings)) - .route(web::patch().to(SeqHandler(patch_settings))), + .route(web::patch().to(SeqHandler(patch_settings))) + .route(web::delete().to(SeqHandler(delete_settings))), ); } async fn get_settings( index_scheduler: GuardedData< - ActionPolicy<{ actions::CHAT_SETTINGS_GET }>, + ActionPolicy<{ actions::CHATS_SETTINGS_GET }>, Data, >, + chats_param: web::Path, ) -> Result { - let mut settings = match index_scheduler.chat_settings()? { + let ChatsParam { workspace_uid } = chats_param.into_inner(); + + // TODO do a spawn_blocking here ??? + let rtxn = index_scheduler.read_txn()?; + let mut settings = match index_scheduler.chat_settings(&rtxn, &workspace_uid)? { Some(value) => serde_json::from_value(value).unwrap(), None => GlobalChatSettings::default(), }; @@ -34,12 +42,17 @@ async fn get_settings( async fn patch_settings( index_scheduler: GuardedData< - ActionPolicy<{ actions::CHAT_SETTINGS_UPDATE }>, + ActionPolicy<{ actions::CHATS_SETTINGS_UPDATE }>, Data, >, + chats_param: web::Path, web::Json(new): web::Json, ) -> Result { - let old = match index_scheduler.chat_settings()? { + let ChatsParam { workspace_uid } = chats_param.into_inner(); + + // TODO do a spawn_blocking here + let mut wtxn = index_scheduler.write_txn()?; + let old = match index_scheduler.chat_settings(&mut wtxn, &workspace_uid)? { Some(value) => serde_json::from_value(value).unwrap(), None => GlobalChatSettings::default(), }; @@ -64,16 +77,39 @@ async fn patch_settings( }; let value = serde_json::to_value(settings).unwrap(); - index_scheduler.put_chat_settings(&value)?; + index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &value)?; + wtxn.commit()?; + Ok(HttpResponse::Ok().finish()) } +async fn delete_settings( + index_scheduler: GuardedData< + ActionPolicy<{ actions::CHATS_SETTINGS_DELETE }>, + Data, + >, + chats_param: web::Path, +) -> Result { + let ChatsParam { workspace_uid } = chats_param.into_inner(); + + // TODO do a spawn_blocking here + let mut wtxn = index_scheduler.write_txn()?; + if index_scheduler.delete_chat_settings(&mut wtxn, &workspace_uid)? { + wtxn.commit()?; + Ok(HttpResponse::Ok().finish()) + } else { + Ok(HttpResponse::NotFound().finish()) + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub enum ChatSource { OpenAi, } +// TODO Implement Deserr on that. +// TODO Declare DbGlobalChatSettings (alias it). #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct GlobalChatSettings { @@ -114,6 +150,8 @@ impl GlobalChatSettings { } } +// TODO Implement Deserr on that. +// TODO Declare DbChatPrompts (alias it). #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct ChatPrompts { diff --git a/crates/meilisearch/src/routes/indexes/mod.rs b/crates/meilisearch/src/routes/indexes/mod.rs index 48ed1cfb1..04b3e12c4 100644 --- a/crates/meilisearch/src/routes/indexes/mod.rs +++ b/crates/meilisearch/src/routes/indexes/mod.rs @@ -172,7 +172,7 @@ pub async fn list_indexes( debug!(parameters = ?paginate, "List indexes"); let filters = index_scheduler.filters(); let (total, indexes) = - index_scheduler.get_paginated_indexes_stats(filters, *paginate.offset, *paginate.limit)?; + index_scheduler.paginated_indexes_stats(filters, *paginate.offset, *paginate.limit)?; let indexes = indexes .into_iter() .map(|(name, stats)| IndexView { diff --git a/crates/meilisearch/src/routes/mod.rs b/crates/meilisearch/src/routes/mod.rs index 3d56ce8e8..572092fea 100644 --- a/crates/meilisearch/src/routes/mod.rs +++ b/crates/meilisearch/src/routes/mod.rs @@ -52,7 +52,7 @@ const PAGINATION_DEFAULT_LIMIT_FN: fn() -> usize = || 20; mod api_key; pub mod batches; -pub mod chat; +pub mod chats; mod dump; pub mod features; pub mod indexes; @@ -62,7 +62,6 @@ mod multi_search; mod multi_search_analytics; pub mod network; mod open_api_utils; -pub mod settings; mod snapshot; mod swap_indexes; pub mod tasks; @@ -116,8 +115,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service(web::scope("/metrics").configure(metrics::configure)) .service(web::scope("/experimental-features").configure(features::configure)) .service(web::scope("/network").configure(network::configure)) - .service(web::scope("/chat").configure(chat::configure)) - .service(web::scope("/settings/chat").configure(settings::chat::configure)); + .service(web::scope("/chats").configure(chats::settings::configure)); #[cfg(feature = "swagger")] { diff --git a/crates/meilisearch/src/routes/settings/mod.rs b/crates/meilisearch/src/routes/settings/mod.rs deleted file mode 100644 index 30a62fc50..000000000 --- a/crates/meilisearch/src/routes/settings/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod chat; From 02cbcea3db2507136960e55e5fcc38854f0dfa6e Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Fri, 30 May 2025 15:02:24 +0200 Subject: [PATCH 163/292] Better chat completions settings management --- crates/index-scheduler/src/lib.rs | 10 +- crates/meilisearch-types/src/error.rs | 1 + crates/meilisearch-types/src/features.rs | 73 ++++++++ .../src/routes/chats/chat_completions.rs | 69 +++---- .../meilisearch/src/routes/chats/settings.rs | 171 +++++++++++------- crates/meilisearch/src/routes/mod.rs | 2 +- 6 files changed, 219 insertions(+), 107 deletions(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 261fe030c..3860ef5cb 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -51,7 +51,9 @@ pub use features::RoFeatures; use flate2::bufread::GzEncoder; use flate2::Compression; use meilisearch_types::batches::Batch; -use meilisearch_types::features::{InstanceTogglableFeatures, Network, RuntimeTogglableFeatures}; +use meilisearch_types::features::{ + ChatCompletionSettings, InstanceTogglableFeatures, Network, RuntimeTogglableFeatures, +}; use meilisearch_types::heed::byteorder::BE; use meilisearch_types::heed::types::{SerdeJson, Str, I128}; use meilisearch_types::heed::{self, Database, Env, RoTxn, RwTxn, WithoutTls}; @@ -154,7 +156,7 @@ pub struct IndexScheduler { features: features::FeatureData, /// Stores the custom chat prompts and other settings of the indexes. - pub(crate) chat_settings: Database>, + pub(crate) chat_settings: Database>, /// Everything related to the processing of the tasks pub scheduler: scheduler::Scheduler, @@ -898,7 +900,7 @@ impl IndexScheduler { res.map(EmbeddingConfigs::new) } - pub fn chat_settings(&self, rtxn: &RoTxn, uid: &str) -> Result> { + pub fn chat_settings(&self, rtxn: &RoTxn, uid: &str) -> Result> { self.chat_settings.get(rtxn, uid).map_err(Into::into) } @@ -906,7 +908,7 @@ impl IndexScheduler { &self, wtxn: &mut RwTxn, uid: &str, - settings: &serde_json::Value, + settings: &ChatCompletionSettings, ) -> Result<()> { self.chat_settings.put(wtxn, uid, settings).map_err(Into::into) } diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 172656237..d7b6f56d4 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -217,6 +217,7 @@ ImmutableIndexUpdatedAt , InvalidRequest , BAD_REQUEST; IndexAlreadyExists , InvalidRequest , CONFLICT ; IndexCreationFailed , Internal , INTERNAL_SERVER_ERROR; IndexNotFound , InvalidRequest , NOT_FOUND; +ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND; IndexPrimaryKeyAlreadyExists , InvalidRequest , BAD_REQUEST ; IndexPrimaryKeyMultipleCandidatesFound, InvalidRequest , BAD_REQUEST; IndexPrimaryKeyNoCandidateFound , InvalidRequest , BAD_REQUEST ; diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 5db8775b6..f12cbcfc9 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -2,6 +2,13 @@ use std::collections::BTreeMap; use serde::{Deserialize, Serialize}; +pub const DEFAULT_CHAT_SYSTEM_PROMPT: &str = "You are a highly capable research assistant with access to powerful search tools. IMPORTANT INSTRUCTIONS:1. When answering questions, you MUST make multiple tool calls (at least 2-3) to gather comprehensive information.2. Use different search queries for each tool call - vary keywords, rephrase questions, and explore different semantic angles to ensure broad coverage.3. Always explicitly announce BEFORE making each tool call by saying: \"I'll search for [specific information] now.\"4. Combine information from ALL tool calls to provide complete, nuanced answers rather than relying on a single source.5. For complex topics, break down your research into multiple targeted queries rather than using a single generic search."; +pub const DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT: &str = + "Search the database for relevant JSON documents using an optional query."; +pub const DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT: &str = "The search query string used to find relevant documents in the index. This should contain keywords or phrases that best represent what the user is looking for. More specific queries will yield more precise results."; +pub const DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT: &str = "The name of the index to search within. An index is a collection of documents organized for search. Selecting the right index ensures the most relevant results for the user query. You can access to two indexes: movies, steam. The movies index contains movies with overviews. The steam index contains steam games from the Steam platform with their prices"; +pub const DEFAULT_CHAT_PRE_QUERY_PROMPT: &str = ""; + #[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)] #[serde(rename_all = "camelCase", default)] pub struct RuntimeTogglableFeatures { @@ -37,3 +44,69 @@ pub struct Network { #[serde(default)] pub remotes: BTreeMap, } + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] +#[serde(rename_all = "camelCase")] +pub struct ChatCompletionSettings { + pub source: ChatCompletionSource, + #[serde(default)] + pub base_api: Option, + #[serde(default)] + pub api_key: Option, + #[serde(default)] + pub prompts: ChatCompletionPrompts, +} + +impl ChatCompletionSettings { + pub fn hide_secrets(&mut self) { + if let Some(api_key) = &mut self.api_key { + Self::hide_secret(api_key); + } + } + + fn hide_secret(secret: &mut String) { + match secret.len() { + x if x < 10 => { + secret.replace_range(.., "XXX..."); + } + x if x < 20 => { + secret.replace_range(2.., "XXXX..."); + } + x if x < 30 => { + secret.replace_range(3.., "XXXXX..."); + } + _x => { + secret.replace_range(5.., "XXXXXX..."); + } + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] +#[serde(rename_all = "camelCase")] +pub enum ChatCompletionSource { + #[default] + OpenAi, +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct ChatCompletionPrompts { + pub system: String, + pub search_description: String, + pub search_q_param: String, + pub search_index_uid_param: String, + pub pre_query: String, +} + +impl Default for ChatCompletionPrompts { + fn default() -> Self { + Self { + system: DEFAULT_CHAT_SYSTEM_PROMPT.to_string(), + search_description: DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT.to_string(), + search_q_param: DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT.to_string(), + search_index_uid_param: DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT.to_string(), + pre_query: DEFAULT_CHAT_PRE_QUERY_PROMPT.to_string(), + } + } +} diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index ee16a33cd..a923d2ff9 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -26,13 +26,15 @@ use bumpalo::Bump; use futures::StreamExt; use index_scheduler::IndexScheduler; use meilisearch_auth::AuthController; -use meilisearch_types::error::ResponseError; +use meilisearch_types::error::{Code, ResponseError}; +use meilisearch_types::features::{ + ChatCompletionPrompts as DbChatCompletionPrompts, ChatCompletionSettings as DbChatSettings, +}; use meilisearch_types::heed::RoTxn; use meilisearch_types::keys::actions; use meilisearch_types::milli::index::ChatConfig; use meilisearch_types::milli::prompt::{Prompt, PromptData}; use meilisearch_types::milli::update::new::document::DocumentFromDb; -use meilisearch_types::milli::update::Setting; use meilisearch_types::milli::{ all_obkv_to_json, obkv_to_json, DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, MetadataBuilder, TimeBudget, @@ -44,7 +46,6 @@ use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; use tokio::sync::mpsc::Sender; -use super::settings::{ChatPrompts, GlobalChatSettings}; use super::ChatsParam; use crate::error::MeilisearchHttpError; use crate::extractors::authentication::policies::ActionPolicy; @@ -132,7 +133,7 @@ fn setup_search_tool( index_scheduler: &Data, filters: &meilisearch_auth::AuthFilter, chat_completion: &mut CreateChatCompletionRequest, - prompts: &ChatPrompts, + prompts: &DbChatCompletionPrompts, ) -> Result { let tools = chat_completion.tools.get_or_insert_default(); if tools.iter().find(|t| t.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME).is_some() { @@ -167,7 +168,7 @@ fn setup_search_tool( }); let mut index_uids = Vec::new(); - let mut function_description = prompts.search_description.clone().unwrap(); + let mut function_description = prompts.search_description.clone(); index_scheduler.try_for_each_index::<_, ()>(|name, index| { // Make sure to skip unauthorized indexes if !filters.is_index_authorized(&name) { @@ -195,13 +196,13 @@ fn setup_search_tool( "index_uid": { "type": "string", "enum": index_uids, - "description": prompts.search_index_uid_param.clone().unwrap(), + "description": prompts.search_index_uid_param, }, "q": { // Unfortunately, Mistral does not support an array of types, here. // "type": ["string", "null"], "type": "string", - "description": prompts.search_q_param.clone().unwrap(), + "description": prompts.search_q_param, } }, "required": ["index_uid", "q"], @@ -219,9 +220,7 @@ fn setup_search_tool( chat_completion.messages.insert( 0, ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { - content: ChatCompletionRequestSystemMessageContent::Text( - prompts.system.as_ref().unwrap().clone(), - ), + content: ChatCompletionRequestSystemMessageContent::Text(prompts.system.clone()), name: None, }), ); @@ -322,23 +321,27 @@ async fn non_streamed_chat( let rtxn = index_scheduler.read_txn()?; let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid).unwrap() { - Some(value) => serde_json::from_value(value).unwrap(), - None => GlobalChatSettings::default(), + Some(settings) => settings, + None => { + return Err(ResponseError::from_msg( + format!("Chat `{workspace_uid}` not found"), + Code::ChatWorkspaceNotFound, + )) + } }; let mut config = OpenAIConfig::default(); - if let Setting::Set(api_key) = chat_settings.api_key.as_ref() { + if let Some(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - if let Setting::Set(base_api) = chat_settings.base_api.as_ref() { + if let Some(base_api) = chat_settings.base_api.as_ref() { config = config.with_api_base(base_api); } let client = Client::with_config(config); let auth_token = extract_token_from_request(&req)?.unwrap(); - let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); let FunctionSupport { report_progress, report_sources, append_to_conversation, report_errors } = - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; let mut response; loop { @@ -381,13 +384,11 @@ async fn non_streamed_chat( Err(err) => err, }; + let answer = format!("{}\n\n{text}", chat_settings.prompts.pre_query); chat_completion.messages.push(ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { tool_call_id: call.id.clone(), - content: ChatCompletionRequestToolMessageContent::Text(format!( - "{}\n\n{text}", - chat_settings.prompts.clone().unwrap().pre_query.unwrap() - )), + content: ChatCompletionRequestToolMessageContent::Text(answer), }, )); } @@ -416,24 +417,28 @@ async fn streamed_chat( let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; - let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid).unwrap() { - Some(value) => serde_json::from_value(value.clone()).unwrap(), - None => GlobalChatSettings::default(), + let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid)? { + Some(settings) => settings, + None => { + return Err(ResponseError::from_msg( + format!("Chat `{workspace_uid}` not found"), + Code::ChatWorkspaceNotFound, + )) + } }; drop(rtxn); let mut config = OpenAIConfig::default(); - if let Setting::Set(api_key) = chat_settings.api_key.as_ref() { + if let Some(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - if let Setting::Set(base_api) = chat_settings.base_api.as_ref() { + if let Some(base_api) = chat_settings.base_api.as_ref() { config = config.with_api_base(base_api); } let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); - let prompts = chat_settings.prompts.clone().or(Setting::Set(ChatPrompts::default())).unwrap(); let function_support = - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &prompts)?; + setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; let (tx, rx) = tokio::sync::mpsc::channel(10); let tx = SseEventSender(tx); @@ -478,7 +483,7 @@ async fn run_conversation( search_queue: &web::Data, auth_token: &str, client: &Client, - chat_settings: &GlobalChatSettings, + chat_settings: &DbChatSettings, chat_completion: &mut CreateChatCompletionRequest, tx: &SseEventSender, global_tool_calls: &mut HashMap, @@ -605,7 +610,7 @@ async fn handle_meili_tools( auth_ctrl: &web::Data, search_queue: &web::Data, auth_token: &str, - chat_settings: &GlobalChatSettings, + chat_settings: &DbChatSettings, tx: &SseEventSender, meili_calls: Vec, chat_completion: &mut CreateChatCompletionRequest, @@ -658,12 +663,10 @@ async fn handle_meili_tools( Err(err) => err, }; + let answer = format!("{}\n\n{text}", chat_settings.prompts.pre_query); let tool = ChatCompletionRequestMessage::Tool(ChatCompletionRequestToolMessage { tool_call_id: call.id.clone(), - content: ChatCompletionRequestToolMessageContent::Text(format!( - "{}\n\n{text}", - chat_settings.prompts.as_ref().unwrap().pre_query.as_ref().unwrap() - )), + content: ChatCompletionRequestToolMessageContent::Text(answer), }); if append_to_conversation { diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 0d3f88938..6354066be 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -1,7 +1,13 @@ use actix_web::web::{self, Data}; use actix_web::HttpResponse; use index_scheduler::IndexScheduler; -use meilisearch_types::error::ResponseError; +use meilisearch_types::error::{Code, ResponseError}; +use meilisearch_types::features::{ + ChatCompletionPrompts as DbChatCompletionPrompts, ChatCompletionSettings, + ChatCompletionSource as DbChatCompletionSource, DEFAULT_CHAT_PRE_QUERY_PROMPT, + DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT, DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT, + DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT, DEFAULT_CHAT_SYSTEM_PROMPT, +}; use meilisearch_types::keys::actions; use meilisearch_types::milli::update::Setting; use serde::{Deserialize, Serialize}; @@ -15,7 +21,7 @@ use super::ChatsParam; pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service( web::resource("") - .route(web::get().to(get_settings)) + .route(web::get().to(SeqHandler(get_settings))) .route(web::patch().to(SeqHandler(patch_settings))) .route(web::delete().to(SeqHandler(delete_settings))), ); @@ -33,8 +39,13 @@ async fn get_settings( // TODO do a spawn_blocking here ??? let rtxn = index_scheduler.read_txn()?; let mut settings = match index_scheduler.chat_settings(&rtxn, &workspace_uid)? { - Some(value) => serde_json::from_value(value).unwrap(), - None => GlobalChatSettings::default(), + Some(settings) => settings, + None => { + return Err(ResponseError::from_msg( + format!("Chat `{workspace_uid}` not found"), + Code::ChatWorkspaceNotFound, + )) + } }; settings.hide_secrets(); Ok(HttpResponse::Ok().json(settings)) @@ -52,35 +63,73 @@ async fn patch_settings( // TODO do a spawn_blocking here let mut wtxn = index_scheduler.write_txn()?; - let old = match index_scheduler.chat_settings(&mut wtxn, &workspace_uid)? { - Some(value) => serde_json::from_value(value).unwrap(), - None => GlobalChatSettings::default(), - }; + let old_settings = + index_scheduler.chat_settings(&mut wtxn, &workspace_uid)?.unwrap_or_default(); - let settings = GlobalChatSettings { - source: new.source.or(old.source), - base_api: new.base_api.clone().or(old.base_api), - api_key: new.api_key.clone().or(old.api_key), - prompts: match (new.prompts, old.prompts) { - (Setting::NotSet, set) | (set, Setting::NotSet) => set, - (Setting::Set(_) | Setting::Reset, Setting::Reset) => Setting::Reset, - (Setting::Reset, Setting::Set(set)) => Setting::Set(set), - // If both are set we must merge the prompts settings - (Setting::Set(new), Setting::Set(old)) => Setting::Set(ChatPrompts { - system: new.system.or(old.system), - search_description: new.search_description.or(old.search_description), - search_q_param: new.search_q_param.or(old.search_q_param), - search_index_uid_param: new.search_index_uid_param.or(old.search_index_uid_param), - pre_query: new.pre_query.or(old.pre_query), - }), + let prompts = match new.prompts { + Setting::Set(new_prompts) => DbChatCompletionPrompts { + system: match new_prompts.system { + Setting::Set(new_system) => new_system, + Setting::Reset => DEFAULT_CHAT_SYSTEM_PROMPT.to_string(), + Setting::NotSet => old_settings.prompts.system, + }, + search_description: match new_prompts.search_description { + Setting::Set(new_description) => new_description, + Setting::Reset => DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT.to_string(), + Setting::NotSet => old_settings.prompts.search_description, + }, + search_q_param: match new_prompts.search_q_param { + Setting::Set(new_description) => new_description, + Setting::Reset => DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT.to_string(), + Setting::NotSet => old_settings.prompts.search_q_param, + }, + search_index_uid_param: match new_prompts.search_index_uid_param { + Setting::Set(new_description) => new_description, + Setting::Reset => DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT.to_string(), + Setting::NotSet => old_settings.prompts.search_index_uid_param, + }, + pre_query: match new_prompts.pre_query { + Setting::Set(new_description) => new_description, + Setting::Reset => DEFAULT_CHAT_PRE_QUERY_PROMPT.to_string(), + Setting::NotSet => old_settings.prompts.pre_query, + }, }, + Setting::Reset => DbChatCompletionPrompts::default(), + Setting::NotSet => old_settings.prompts, }; - let value = serde_json::to_value(settings).unwrap(); - index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &value)?; + let settings = ChatCompletionSettings { + source: match new.source { + Setting::Set(new_source) => new_source.into(), + Setting::Reset => DbChatCompletionSource::default(), + Setting::NotSet => old_settings.source, + }, + base_api: match new.base_api { + Setting::Set(new_base_api) => Some(new_base_api), + Setting::Reset => None, + Setting::NotSet => old_settings.base_api, + }, + api_key: match new.api_key { + Setting::Set(new_api_key) => Some(new_api_key), + Setting::Reset => None, + Setting::NotSet => old_settings.api_key, + }, + prompts, + }; + + // TODO send analytics + // analytics.publish( + // PatchNetworkAnalytics { + // network_size: merged_remotes.len(), + // network_has_self: merged_self.is_some(), + // }, + // &req, + // ); + + index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &settings)?; wtxn.commit()?; - Ok(HttpResponse::Ok().finish()) + Ok(HttpResponse::Ok().json(settings)) } async fn delete_settings( @@ -96,58 +145,42 @@ async fn delete_settings( let mut wtxn = index_scheduler.write_txn()?; if index_scheduler.delete_chat_settings(&mut wtxn, &workspace_uid)? { wtxn.commit()?; - Ok(HttpResponse::Ok().finish()) + Ok(HttpResponse::NoContent().finish()) } else { - Ok(HttpResponse::NotFound().finish()) + Err(ResponseError::from_msg( + format!("Chat `{workspace_uid}` not found"), + Code::ChatWorkspaceNotFound, + )) } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] #[serde(deny_unknown_fields, rename_all = "camelCase")] -pub enum ChatSource { +pub enum ChatCompletionSource { + #[default] OpenAi, } -// TODO Implement Deserr on that. -// TODO Declare DbGlobalChatSettings (alias it). -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub struct GlobalChatSettings { - #[serde(default, skip_serializing_if = "Setting::is_not_set")] - pub source: Setting, - #[serde(default, skip_serializing_if = "Setting::is_not_set")] - pub base_api: Setting, - #[serde(default, skip_serializing_if = "Setting::is_not_set")] - pub api_key: Setting, - #[serde(default, skip_serializing_if = "Setting::is_not_set")] - pub prompts: Setting, +impl From for DbChatCompletionSource { + fn from(source: ChatCompletionSource) -> Self { + match source { + ChatCompletionSource::OpenAi => DbChatCompletionSource::OpenAi, + } + } } -impl GlobalChatSettings { - pub fn hide_secrets(&mut self) { - match &mut self.api_key { - Setting::Set(key) => Self::hide_secret(key), - Setting::Reset => (), - Setting::NotSet => (), - } - } - - fn hide_secret(secret: &mut String) { - match secret.len() { - x if x < 10 => { - secret.replace_range(.., "XXX..."); - } - x if x < 20 => { - secret.replace_range(2.., "XXXX..."); - } - x if x < 30 => { - secret.replace_range(3.., "XXXXX..."); - } - _x => { - secret.replace_range(5.., "XXXXXX..."); - } - } - } +// TODO Implement Deserr on that. +#[derive(Debug, Clone, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct GlobalChatSettings { + #[serde(default)] + pub source: Setting, + #[serde(default)] + pub base_api: Setting, + #[serde(default)] + pub api_key: Setting, + #[serde(default)] + pub prompts: Setting, } // TODO Implement Deserr on that. diff --git a/crates/meilisearch/src/routes/mod.rs b/crates/meilisearch/src/routes/mod.rs index 572092fea..cc62e43c3 100644 --- a/crates/meilisearch/src/routes/mod.rs +++ b/crates/meilisearch/src/routes/mod.rs @@ -115,7 +115,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service(web::scope("/metrics").configure(metrics::configure)) .service(web::scope("/experimental-features").configure(features::configure)) .service(web::scope("/network").configure(network::configure)) - .service(web::scope("/chats").configure(chats::settings::configure)); + .service(web::scope("/chats").configure(chats::configure)); #[cfg(feature = "swagger")] { From 496685fa265407d2eca6cbdaa0e83bd1bb469c52 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Fri, 30 May 2025 15:30:16 +0200 Subject: [PATCH 164/292] Implement deserr on ChatCompletions settings structs --- crates/meilisearch-types/src/error.rs | 398 +++++++++--------- crates/meilisearch/src/routes/chats/mod.rs | 1 - .../meilisearch/src/routes/chats/settings.rs | 117 +++-- 3 files changed, 251 insertions(+), 265 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index d7b6f56d4..11bad977d 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -194,202 +194,212 @@ macro_rules! make_error_codes { // An exhaustive list of all the error codes used by meilisearch. make_error_codes! { -ApiKeyAlreadyExists , InvalidRequest , CONFLICT ; -ApiKeyNotFound , InvalidRequest , NOT_FOUND ; -BadParameter , InvalidRequest , BAD_REQUEST; -BadRequest , InvalidRequest , BAD_REQUEST; -DatabaseSizeLimitReached , Internal , INTERNAL_SERVER_ERROR; -DocumentNotFound , InvalidRequest , NOT_FOUND; -DumpAlreadyProcessing , InvalidRequest , CONFLICT; -DumpNotFound , InvalidRequest , NOT_FOUND; -DumpProcessFailed , Internal , INTERNAL_SERVER_ERROR; -DuplicateIndexFound , InvalidRequest , BAD_REQUEST; -ImmutableApiKeyActions , InvalidRequest , BAD_REQUEST; -ImmutableApiKeyCreatedAt , InvalidRequest , BAD_REQUEST; -ImmutableApiKeyExpiresAt , InvalidRequest , BAD_REQUEST; -ImmutableApiKeyIndexes , InvalidRequest , BAD_REQUEST; -ImmutableApiKeyKey , InvalidRequest , BAD_REQUEST; -ImmutableApiKeyUid , InvalidRequest , BAD_REQUEST; -ImmutableApiKeyUpdatedAt , InvalidRequest , BAD_REQUEST; -ImmutableIndexCreatedAt , InvalidRequest , BAD_REQUEST; -ImmutableIndexUid , InvalidRequest , BAD_REQUEST; -ImmutableIndexUpdatedAt , InvalidRequest , BAD_REQUEST; -IndexAlreadyExists , InvalidRequest , CONFLICT ; -IndexCreationFailed , Internal , INTERNAL_SERVER_ERROR; -IndexNotFound , InvalidRequest , NOT_FOUND; -ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND; -IndexPrimaryKeyAlreadyExists , InvalidRequest , BAD_REQUEST ; -IndexPrimaryKeyMultipleCandidatesFound, InvalidRequest , BAD_REQUEST; -IndexPrimaryKeyNoCandidateFound , InvalidRequest , BAD_REQUEST ; -Internal , Internal , INTERNAL_SERVER_ERROR ; -InvalidApiKey , Auth , FORBIDDEN ; -InvalidApiKeyActions , InvalidRequest , BAD_REQUEST ; -InvalidApiKeyDescription , InvalidRequest , BAD_REQUEST ; -InvalidApiKeyExpiresAt , InvalidRequest , BAD_REQUEST ; -InvalidApiKeyIndexes , InvalidRequest , BAD_REQUEST ; -InvalidApiKeyLimit , InvalidRequest , BAD_REQUEST ; -InvalidApiKeyName , InvalidRequest , BAD_REQUEST ; -InvalidApiKeyOffset , InvalidRequest , BAD_REQUEST ; -InvalidApiKeyUid , InvalidRequest , BAD_REQUEST ; -InvalidContentType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ; -InvalidDocumentCsvDelimiter , InvalidRequest , BAD_REQUEST ; -InvalidDocumentFields , InvalidRequest , BAD_REQUEST ; -InvalidDocumentRetrieveVectors , InvalidRequest , BAD_REQUEST ; -MissingDocumentFilter , InvalidRequest , BAD_REQUEST ; -MissingDocumentEditionFunction , InvalidRequest , BAD_REQUEST ; -InvalidDocumentFilter , InvalidRequest , BAD_REQUEST ; -InvalidDocumentGeoField , InvalidRequest , BAD_REQUEST ; -InvalidVectorDimensions , InvalidRequest , BAD_REQUEST ; -InvalidVectorsType , InvalidRequest , BAD_REQUEST ; -InvalidDocumentId , InvalidRequest , BAD_REQUEST ; -InvalidDocumentIds , InvalidRequest , BAD_REQUEST ; -InvalidDocumentLimit , InvalidRequest , BAD_REQUEST ; -InvalidDocumentOffset , InvalidRequest , BAD_REQUEST ; -InvalidSearchEmbedder , InvalidRequest , BAD_REQUEST ; -InvalidSimilarEmbedder , InvalidRequest , BAD_REQUEST ; -InvalidSearchHybridQuery , InvalidRequest , BAD_REQUEST ; -InvalidIndexLimit , InvalidRequest , BAD_REQUEST ; -InvalidIndexOffset , InvalidRequest , BAD_REQUEST ; -InvalidIndexPrimaryKey , InvalidRequest , BAD_REQUEST ; -InvalidIndexUid , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchFacets , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchFacetsByIndex , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchFacetOrder , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchFederated , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchFederationOptions , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchMaxValuesPerFacet , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchMergeFacets , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchQueryFacets , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchQueryPagination , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchQueryRankingRules , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchQueryPosition , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchRemote , InvalidRequest , BAD_REQUEST ; -InvalidMultiSearchWeight , InvalidRequest , BAD_REQUEST ; -InvalidNetworkRemotes , InvalidRequest , BAD_REQUEST ; -InvalidNetworkSelf , InvalidRequest , BAD_REQUEST ; -InvalidNetworkSearchApiKey , InvalidRequest , BAD_REQUEST ; -InvalidNetworkUrl , InvalidRequest , BAD_REQUEST ; -InvalidSearchAttributesToSearchOn , InvalidRequest , BAD_REQUEST ; -InvalidSearchAttributesToCrop , InvalidRequest , BAD_REQUEST ; -InvalidSearchAttributesToHighlight , InvalidRequest , BAD_REQUEST ; -InvalidSimilarAttributesToRetrieve , InvalidRequest , BAD_REQUEST ; -InvalidSimilarRetrieveVectors , InvalidRequest , BAD_REQUEST ; -InvalidSearchAttributesToRetrieve , InvalidRequest , BAD_REQUEST ; -InvalidSearchRankingScoreThreshold , InvalidRequest , BAD_REQUEST ; -InvalidSimilarRankingScoreThreshold , InvalidRequest , BAD_REQUEST ; -InvalidSearchRetrieveVectors , InvalidRequest , BAD_REQUEST ; -InvalidSearchCropLength , InvalidRequest , BAD_REQUEST ; -InvalidSearchCropMarker , InvalidRequest , BAD_REQUEST ; -InvalidSearchFacets , InvalidRequest , BAD_REQUEST ; -InvalidSearchSemanticRatio , InvalidRequest , BAD_REQUEST ; -InvalidSearchLocales , InvalidRequest , BAD_REQUEST ; -InvalidFacetSearchExhaustiveFacetCount, InvalidRequest , BAD_REQUEST ; -InvalidFacetSearchFacetName , InvalidRequest , BAD_REQUEST ; -InvalidSimilarId , InvalidRequest , BAD_REQUEST ; -InvalidSearchFilter , InvalidRequest , BAD_REQUEST ; -InvalidSimilarFilter , InvalidRequest , BAD_REQUEST ; -InvalidSearchHighlightPostTag , InvalidRequest , BAD_REQUEST ; -InvalidSearchHighlightPreTag , InvalidRequest , BAD_REQUEST ; -InvalidSearchHitsPerPage , InvalidRequest , BAD_REQUEST ; -InvalidSimilarLimit , InvalidRequest , BAD_REQUEST ; -InvalidSearchLimit , InvalidRequest , BAD_REQUEST ; -InvalidSearchMatchingStrategy , InvalidRequest , BAD_REQUEST ; -InvalidSimilarOffset , InvalidRequest , BAD_REQUEST ; -InvalidSearchOffset , InvalidRequest , BAD_REQUEST ; -InvalidSearchPage , InvalidRequest , BAD_REQUEST ; -InvalidSearchQ , InvalidRequest , BAD_REQUEST ; -InvalidFacetSearchQuery , InvalidRequest , BAD_REQUEST ; -InvalidFacetSearchName , InvalidRequest , BAD_REQUEST ; -FacetSearchDisabled , InvalidRequest , BAD_REQUEST ; -InvalidSearchVector , InvalidRequest , BAD_REQUEST ; -InvalidSearchShowMatchesPosition , InvalidRequest , BAD_REQUEST ; -InvalidSearchShowRankingScore , InvalidRequest , BAD_REQUEST ; -InvalidSimilarShowRankingScore , InvalidRequest , BAD_REQUEST ; -InvalidSearchShowRankingScoreDetails , InvalidRequest , BAD_REQUEST ; -InvalidSimilarShowRankingScoreDetails , InvalidRequest , BAD_REQUEST ; -InvalidSearchSort , InvalidRequest , BAD_REQUEST ; -InvalidSearchDistinct , InvalidRequest , BAD_REQUEST ; -InvalidSettingsDisplayedAttributes , InvalidRequest , BAD_REQUEST ; -InvalidSettingsDistinctAttribute , InvalidRequest , BAD_REQUEST ; -InvalidSettingsProximityPrecision , InvalidRequest , BAD_REQUEST ; -InvalidSettingsFacetSearch , InvalidRequest , BAD_REQUEST ; -InvalidSettingsPrefixSearch , InvalidRequest , BAD_REQUEST ; -InvalidSettingsFaceting , InvalidRequest , BAD_REQUEST ; -InvalidSettingsFilterableAttributes , InvalidRequest , BAD_REQUEST ; -InvalidSettingsPagination , InvalidRequest , BAD_REQUEST ; -InvalidSettingsSearchCutoffMs , InvalidRequest , BAD_REQUEST ; -InvalidSettingsEmbedders , InvalidRequest , BAD_REQUEST ; -InvalidSettingsRankingRules , InvalidRequest , BAD_REQUEST ; -InvalidSettingsSearchableAttributes , InvalidRequest , BAD_REQUEST ; -InvalidSettingsSortableAttributes , InvalidRequest , BAD_REQUEST ; -InvalidSettingsStopWords , InvalidRequest , BAD_REQUEST ; -InvalidSettingsNonSeparatorTokens , InvalidRequest , BAD_REQUEST ; -InvalidSettingsSeparatorTokens , InvalidRequest , BAD_REQUEST ; -InvalidSettingsDictionary , InvalidRequest , BAD_REQUEST ; -InvalidSettingsSynonyms , InvalidRequest , BAD_REQUEST ; -InvalidSettingsTypoTolerance , InvalidRequest , BAD_REQUEST ; -InvalidSettingsLocalizedAttributes , InvalidRequest , BAD_REQUEST ; -InvalidState , Internal , INTERNAL_SERVER_ERROR ; -InvalidStoreFile , Internal , INTERNAL_SERVER_ERROR ; -InvalidSwapDuplicateIndexFound , InvalidRequest , BAD_REQUEST ; -InvalidSwapIndexes , InvalidRequest , BAD_REQUEST ; -InvalidTaskAfterEnqueuedAt , InvalidRequest , BAD_REQUEST ; -InvalidTaskAfterFinishedAt , InvalidRequest , BAD_REQUEST ; -InvalidTaskAfterStartedAt , InvalidRequest , BAD_REQUEST ; -InvalidTaskBeforeEnqueuedAt , InvalidRequest , BAD_REQUEST ; -InvalidTaskBeforeFinishedAt , InvalidRequest , BAD_REQUEST ; -InvalidTaskBeforeStartedAt , InvalidRequest , BAD_REQUEST ; -InvalidTaskCanceledBy , InvalidRequest , BAD_REQUEST ; -InvalidTaskFrom , InvalidRequest , BAD_REQUEST ; -InvalidTaskLimit , InvalidRequest , BAD_REQUEST ; -InvalidTaskReverse , InvalidRequest , BAD_REQUEST ; -InvalidTaskStatuses , InvalidRequest , BAD_REQUEST ; -InvalidTaskTypes , InvalidRequest , BAD_REQUEST ; -InvalidTaskUids , InvalidRequest , BAD_REQUEST ; -InvalidBatchUids , InvalidRequest , BAD_REQUEST ; -IoError , System , UNPROCESSABLE_ENTITY; -FeatureNotEnabled , InvalidRequest , BAD_REQUEST ; -MalformedPayload , InvalidRequest , BAD_REQUEST ; -MaxFieldsLimitExceeded , InvalidRequest , BAD_REQUEST ; -MissingApiKeyActions , InvalidRequest , BAD_REQUEST ; -MissingApiKeyExpiresAt , InvalidRequest , BAD_REQUEST ; -MissingApiKeyIndexes , InvalidRequest , BAD_REQUEST ; -MissingAuthorizationHeader , Auth , UNAUTHORIZED ; -MissingContentType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ; -MissingDocumentId , InvalidRequest , BAD_REQUEST ; -MissingFacetSearchFacetName , InvalidRequest , BAD_REQUEST ; -MissingIndexUid , InvalidRequest , BAD_REQUEST ; -MissingMasterKey , Auth , UNAUTHORIZED ; -MissingNetworkUrl , InvalidRequest , BAD_REQUEST ; -MissingPayload , InvalidRequest , BAD_REQUEST ; -MissingSearchHybrid , InvalidRequest , BAD_REQUEST ; -MissingSwapIndexes , InvalidRequest , BAD_REQUEST ; -MissingTaskFilters , InvalidRequest , BAD_REQUEST ; -NoSpaceLeftOnDevice , System , UNPROCESSABLE_ENTITY; -PayloadTooLarge , InvalidRequest , PAYLOAD_TOO_LARGE ; -RemoteBadResponse , System , BAD_GATEWAY ; -RemoteBadRequest , InvalidRequest , BAD_REQUEST ; -RemoteCouldNotSendRequest , System , BAD_GATEWAY ; -RemoteInvalidApiKey , Auth , FORBIDDEN ; -RemoteRemoteError , System , BAD_GATEWAY ; -RemoteTimeout , System , BAD_GATEWAY ; -TooManySearchRequests , System , SERVICE_UNAVAILABLE ; -TaskNotFound , InvalidRequest , NOT_FOUND ; -TaskFileNotFound , InvalidRequest , NOT_FOUND ; -BatchNotFound , InvalidRequest , NOT_FOUND ; -TooManyOpenFiles , System , UNPROCESSABLE_ENTITY ; -TooManyVectors , InvalidRequest , BAD_REQUEST ; -UnretrievableDocument , Internal , BAD_REQUEST ; -UnretrievableErrorCode , InvalidRequest , BAD_REQUEST ; -UnsupportedMediaType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ; +ApiKeyAlreadyExists , InvalidRequest , CONFLICT ; +ApiKeyNotFound , InvalidRequest , NOT_FOUND ; +BadParameter , InvalidRequest , BAD_REQUEST; +BadRequest , InvalidRequest , BAD_REQUEST; +DatabaseSizeLimitReached , Internal , INTERNAL_SERVER_ERROR; +DocumentNotFound , InvalidRequest , NOT_FOUND; +DumpAlreadyProcessing , InvalidRequest , CONFLICT; +DumpNotFound , InvalidRequest , NOT_FOUND; +DumpProcessFailed , Internal , INTERNAL_SERVER_ERROR; +DuplicateIndexFound , InvalidRequest , BAD_REQUEST; +ImmutableApiKeyActions , InvalidRequest , BAD_REQUEST; +ImmutableApiKeyCreatedAt , InvalidRequest , BAD_REQUEST; +ImmutableApiKeyExpiresAt , InvalidRequest , BAD_REQUEST; +ImmutableApiKeyIndexes , InvalidRequest , BAD_REQUEST; +ImmutableApiKeyKey , InvalidRequest , BAD_REQUEST; +ImmutableApiKeyUid , InvalidRequest , BAD_REQUEST; +ImmutableApiKeyUpdatedAt , InvalidRequest , BAD_REQUEST; +ImmutableIndexCreatedAt , InvalidRequest , BAD_REQUEST; +ImmutableIndexUid , InvalidRequest , BAD_REQUEST; +ImmutableIndexUpdatedAt , InvalidRequest , BAD_REQUEST; +IndexAlreadyExists , InvalidRequest , CONFLICT ; +IndexCreationFailed , Internal , INTERNAL_SERVER_ERROR; +IndexNotFound , InvalidRequest , NOT_FOUND; +IndexPrimaryKeyAlreadyExists , InvalidRequest , BAD_REQUEST ; +IndexPrimaryKeyMultipleCandidatesFound , InvalidRequest , BAD_REQUEST; +IndexPrimaryKeyNoCandidateFound , InvalidRequest , BAD_REQUEST ; +Internal , Internal , INTERNAL_SERVER_ERROR ; +InvalidApiKey , Auth , FORBIDDEN ; +InvalidApiKeyActions , InvalidRequest , BAD_REQUEST ; +InvalidApiKeyDescription , InvalidRequest , BAD_REQUEST ; +InvalidApiKeyExpiresAt , InvalidRequest , BAD_REQUEST ; +InvalidApiKeyIndexes , InvalidRequest , BAD_REQUEST ; +InvalidApiKeyLimit , InvalidRequest , BAD_REQUEST ; +InvalidApiKeyName , InvalidRequest , BAD_REQUEST ; +InvalidApiKeyOffset , InvalidRequest , BAD_REQUEST ; +InvalidApiKeyUid , InvalidRequest , BAD_REQUEST ; +InvalidContentType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ; +InvalidDocumentCsvDelimiter , InvalidRequest , BAD_REQUEST ; +InvalidDocumentFields , InvalidRequest , BAD_REQUEST ; +InvalidDocumentRetrieveVectors , InvalidRequest , BAD_REQUEST ; +MissingDocumentFilter , InvalidRequest , BAD_REQUEST ; +MissingDocumentEditionFunction , InvalidRequest , BAD_REQUEST ; +InvalidDocumentFilter , InvalidRequest , BAD_REQUEST ; +InvalidDocumentGeoField , InvalidRequest , BAD_REQUEST ; +InvalidVectorDimensions , InvalidRequest , BAD_REQUEST ; +InvalidVectorsType , InvalidRequest , BAD_REQUEST ; +InvalidDocumentId , InvalidRequest , BAD_REQUEST ; +InvalidDocumentIds , InvalidRequest , BAD_REQUEST ; +InvalidDocumentLimit , InvalidRequest , BAD_REQUEST ; +InvalidDocumentOffset , InvalidRequest , BAD_REQUEST ; +InvalidSearchEmbedder , InvalidRequest , BAD_REQUEST ; +InvalidSimilarEmbedder , InvalidRequest , BAD_REQUEST ; +InvalidSearchHybridQuery , InvalidRequest , BAD_REQUEST ; +InvalidIndexLimit , InvalidRequest , BAD_REQUEST ; +InvalidIndexOffset , InvalidRequest , BAD_REQUEST ; +InvalidIndexPrimaryKey , InvalidRequest , BAD_REQUEST ; +InvalidIndexUid , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchFacets , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchFacetsByIndex , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchFacetOrder , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchFederated , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchFederationOptions , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchMaxValuesPerFacet , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchMergeFacets , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchQueryFacets , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchQueryPagination , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchQueryRankingRules , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchQueryPosition , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchRemote , InvalidRequest , BAD_REQUEST ; +InvalidMultiSearchWeight , InvalidRequest , BAD_REQUEST ; +InvalidNetworkRemotes , InvalidRequest , BAD_REQUEST ; +InvalidNetworkSelf , InvalidRequest , BAD_REQUEST ; +InvalidNetworkSearchApiKey , InvalidRequest , BAD_REQUEST ; +InvalidNetworkUrl , InvalidRequest , BAD_REQUEST ; +InvalidSearchAttributesToSearchOn , InvalidRequest , BAD_REQUEST ; +InvalidSearchAttributesToCrop , InvalidRequest , BAD_REQUEST ; +InvalidSearchAttributesToHighlight , InvalidRequest , BAD_REQUEST ; +InvalidSimilarAttributesToRetrieve , InvalidRequest , BAD_REQUEST ; +InvalidSimilarRetrieveVectors , InvalidRequest , BAD_REQUEST ; +InvalidSearchAttributesToRetrieve , InvalidRequest , BAD_REQUEST ; +InvalidSearchRankingScoreThreshold , InvalidRequest , BAD_REQUEST ; +InvalidSimilarRankingScoreThreshold , InvalidRequest , BAD_REQUEST ; +InvalidSearchRetrieveVectors , InvalidRequest , BAD_REQUEST ; +InvalidSearchCropLength , InvalidRequest , BAD_REQUEST ; +InvalidSearchCropMarker , InvalidRequest , BAD_REQUEST ; +InvalidSearchFacets , InvalidRequest , BAD_REQUEST ; +InvalidSearchSemanticRatio , InvalidRequest , BAD_REQUEST ; +InvalidSearchLocales , InvalidRequest , BAD_REQUEST ; +InvalidFacetSearchExhaustiveFacetCount , InvalidRequest , BAD_REQUEST ; +InvalidFacetSearchFacetName , InvalidRequest , BAD_REQUEST ; +InvalidSimilarId , InvalidRequest , BAD_REQUEST ; +InvalidSearchFilter , InvalidRequest , BAD_REQUEST ; +InvalidSimilarFilter , InvalidRequest , BAD_REQUEST ; +InvalidSearchHighlightPostTag , InvalidRequest , BAD_REQUEST ; +InvalidSearchHighlightPreTag , InvalidRequest , BAD_REQUEST ; +InvalidSearchHitsPerPage , InvalidRequest , BAD_REQUEST ; +InvalidSimilarLimit , InvalidRequest , BAD_REQUEST ; +InvalidSearchLimit , InvalidRequest , BAD_REQUEST ; +InvalidSearchMatchingStrategy , InvalidRequest , BAD_REQUEST ; +InvalidSimilarOffset , InvalidRequest , BAD_REQUEST ; +InvalidSearchOffset , InvalidRequest , BAD_REQUEST ; +InvalidSearchPage , InvalidRequest , BAD_REQUEST ; +InvalidSearchQ , InvalidRequest , BAD_REQUEST ; +InvalidFacetSearchQuery , InvalidRequest , BAD_REQUEST ; +InvalidFacetSearchName , InvalidRequest , BAD_REQUEST ; +FacetSearchDisabled , InvalidRequest , BAD_REQUEST ; +InvalidSearchVector , InvalidRequest , BAD_REQUEST ; +InvalidSearchShowMatchesPosition , InvalidRequest , BAD_REQUEST ; +InvalidSearchShowRankingScore , InvalidRequest , BAD_REQUEST ; +InvalidSimilarShowRankingScore , InvalidRequest , BAD_REQUEST ; +InvalidSearchShowRankingScoreDetails , InvalidRequest , BAD_REQUEST ; +InvalidSimilarShowRankingScoreDetails , InvalidRequest , BAD_REQUEST ; +InvalidSearchSort , InvalidRequest , BAD_REQUEST ; +InvalidSearchDistinct , InvalidRequest , BAD_REQUEST ; +InvalidSettingsDisplayedAttributes , InvalidRequest , BAD_REQUEST ; +InvalidSettingsDistinctAttribute , InvalidRequest , BAD_REQUEST ; +InvalidSettingsProximityPrecision , InvalidRequest , BAD_REQUEST ; +InvalidSettingsFacetSearch , InvalidRequest , BAD_REQUEST ; +InvalidSettingsPrefixSearch , InvalidRequest , BAD_REQUEST ; +InvalidSettingsFaceting , InvalidRequest , BAD_REQUEST ; +InvalidSettingsFilterableAttributes , InvalidRequest , BAD_REQUEST ; +InvalidSettingsPagination , InvalidRequest , BAD_REQUEST ; +InvalidSettingsSearchCutoffMs , InvalidRequest , BAD_REQUEST ; +InvalidSettingsEmbedders , InvalidRequest , BAD_REQUEST ; +InvalidSettingsRankingRules , InvalidRequest , BAD_REQUEST ; +InvalidSettingsSearchableAttributes , InvalidRequest , BAD_REQUEST ; +InvalidSettingsSortableAttributes , InvalidRequest , BAD_REQUEST ; +InvalidSettingsStopWords , InvalidRequest , BAD_REQUEST ; +InvalidSettingsNonSeparatorTokens , InvalidRequest , BAD_REQUEST ; +InvalidSettingsSeparatorTokens , InvalidRequest , BAD_REQUEST ; +InvalidSettingsDictionary , InvalidRequest , BAD_REQUEST ; +InvalidSettingsSynonyms , InvalidRequest , BAD_REQUEST ; +InvalidSettingsTypoTolerance , InvalidRequest , BAD_REQUEST ; +InvalidSettingsLocalizedAttributes , InvalidRequest , BAD_REQUEST ; +InvalidState , Internal , INTERNAL_SERVER_ERROR ; +InvalidStoreFile , Internal , INTERNAL_SERVER_ERROR ; +InvalidSwapDuplicateIndexFound , InvalidRequest , BAD_REQUEST ; +InvalidSwapIndexes , InvalidRequest , BAD_REQUEST ; +InvalidTaskAfterEnqueuedAt , InvalidRequest , BAD_REQUEST ; +InvalidTaskAfterFinishedAt , InvalidRequest , BAD_REQUEST ; +InvalidTaskAfterStartedAt , InvalidRequest , BAD_REQUEST ; +InvalidTaskBeforeEnqueuedAt , InvalidRequest , BAD_REQUEST ; +InvalidTaskBeforeFinishedAt , InvalidRequest , BAD_REQUEST ; +InvalidTaskBeforeStartedAt , InvalidRequest , BAD_REQUEST ; +InvalidTaskCanceledBy , InvalidRequest , BAD_REQUEST ; +InvalidTaskFrom , InvalidRequest , BAD_REQUEST ; +InvalidTaskLimit , InvalidRequest , BAD_REQUEST ; +InvalidTaskReverse , InvalidRequest , BAD_REQUEST ; +InvalidTaskStatuses , InvalidRequest , BAD_REQUEST ; +InvalidTaskTypes , InvalidRequest , BAD_REQUEST ; +InvalidTaskUids , InvalidRequest , BAD_REQUEST ; +InvalidBatchUids , InvalidRequest , BAD_REQUEST ; +IoError , System , UNPROCESSABLE_ENTITY; +FeatureNotEnabled , InvalidRequest , BAD_REQUEST ; +MalformedPayload , InvalidRequest , BAD_REQUEST ; +MaxFieldsLimitExceeded , InvalidRequest , BAD_REQUEST ; +MissingApiKeyActions , InvalidRequest , BAD_REQUEST ; +MissingApiKeyExpiresAt , InvalidRequest , BAD_REQUEST ; +MissingApiKeyIndexes , InvalidRequest , BAD_REQUEST ; +MissingAuthorizationHeader , Auth , UNAUTHORIZED ; +MissingContentType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ; +MissingDocumentId , InvalidRequest , BAD_REQUEST ; +MissingFacetSearchFacetName , InvalidRequest , BAD_REQUEST ; +MissingIndexUid , InvalidRequest , BAD_REQUEST ; +MissingMasterKey , Auth , UNAUTHORIZED ; +MissingNetworkUrl , InvalidRequest , BAD_REQUEST ; +MissingPayload , InvalidRequest , BAD_REQUEST ; +MissingSearchHybrid , InvalidRequest , BAD_REQUEST ; +MissingSwapIndexes , InvalidRequest , BAD_REQUEST ; +MissingTaskFilters , InvalidRequest , BAD_REQUEST ; +NoSpaceLeftOnDevice , System , UNPROCESSABLE_ENTITY; +PayloadTooLarge , InvalidRequest , PAYLOAD_TOO_LARGE ; +RemoteBadResponse , System , BAD_GATEWAY ; +RemoteBadRequest , InvalidRequest , BAD_REQUEST ; +RemoteCouldNotSendRequest , System , BAD_GATEWAY ; +RemoteInvalidApiKey , Auth , FORBIDDEN ; +RemoteRemoteError , System , BAD_GATEWAY ; +RemoteTimeout , System , BAD_GATEWAY ; +TooManySearchRequests , System , SERVICE_UNAVAILABLE ; +TaskNotFound , InvalidRequest , NOT_FOUND ; +TaskFileNotFound , InvalidRequest , NOT_FOUND ; +BatchNotFound , InvalidRequest , NOT_FOUND ; +TooManyOpenFiles , System , UNPROCESSABLE_ENTITY ; +TooManyVectors , InvalidRequest , BAD_REQUEST ; +UnretrievableDocument , Internal , BAD_REQUEST ; +UnretrievableErrorCode , InvalidRequest , BAD_REQUEST ; +UnsupportedMediaType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ; // Experimental features -VectorEmbeddingError , InvalidRequest , BAD_REQUEST ; -NotFoundSimilarId , InvalidRequest , BAD_REQUEST ; -InvalidDocumentEditionContext , InvalidRequest , BAD_REQUEST ; -InvalidDocumentEditionFunctionFilter , InvalidRequest , BAD_REQUEST ; -EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST ; -InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST +VectorEmbeddingError , InvalidRequest , BAD_REQUEST ; +NotFoundSimilarId , InvalidRequest , BAD_REQUEST ; +InvalidDocumentEditionContext , InvalidRequest , BAD_REQUEST ; +InvalidDocumentEditionFunctionFilter , InvalidRequest , BAD_REQUEST ; +EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST ; +InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ; +// Experimental features - Chat Completions +ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND ; +InvalidChatCompletionSource , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionBaseApi , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionApiKey , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionPrompts , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionSystemPrompt , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionSearchDescriptionPrompt , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionSearchQueryParamPrompt , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionSearchIndexUidParamPrompt , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionPreQueryPrompt , InvalidRequest , BAD_REQUEST } impl ErrorCode for JoinError { diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 00e3b28b5..86feb14aa 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -23,7 +23,6 @@ use crate::{ use super::Pagination; -// TODO supports chats/$workspace/settings + /chats/$workspace/chat/completions pub mod chat_completions; pub mod settings; diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 6354066be..68ad2d45e 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -1,6 +1,9 @@ use actix_web::web::{self, Data}; use actix_web::HttpResponse; +use deserr::Deserr; use index_scheduler::IndexScheduler; +use meilisearch_types::deserr::DeserrJsonError; +use meilisearch_types::error::deserr_codes::*; use meilisearch_types::error::{Code, ResponseError}; use meilisearch_types::features::{ ChatCompletionPrompts as DbChatCompletionPrompts, ChatCompletionSettings, @@ -11,6 +14,7 @@ use meilisearch_types::features::{ use meilisearch_types::keys::actions; use meilisearch_types::milli::update::Setting; use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; @@ -154,8 +158,32 @@ async fn delete_settings( } } -#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, Clone, Deserialize, Deserr, ToSchema)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] #[serde(deny_unknown_fields, rename_all = "camelCase")] +#[schema(rename_all = "camelCase")] +pub struct GlobalChatSettings { + #[serde(default)] + #[deserr(default)] + #[schema(value_type = Option)] + pub source: Setting, + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("https://api.mistral.ai/v1"))] + pub base_api: Setting, + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("abcd1234..."))] + pub api_key: Setting, + #[serde(default)] + #[deserr(default)] + #[schema(inline, value_type = Option)] + pub prompts: Setting, +} + +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, Deserr, ToSchema)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub enum ChatCompletionSource { #[default] OpenAi, @@ -169,80 +197,29 @@ impl From for DbChatCompletionSource { } } -// TODO Implement Deserr on that. -#[derive(Debug, Clone, Deserialize)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub struct GlobalChatSettings { - #[serde(default)] - pub source: Setting, - #[serde(default)] - pub base_api: Setting, - #[serde(default)] - pub api_key: Setting, - #[serde(default)] - pub prompts: Setting, -} - -// TODO Implement Deserr on that. -// TODO Declare DbChatPrompts (alias it). -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Deserialize, Deserr, ToSchema)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] #[serde(deny_unknown_fields, rename_all = "camelCase")] +#[schema(rename_all = "camelCase")] pub struct ChatPrompts { - #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("You are a helpful assistant..."))] pub system: Setting, - #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("This is the search function..."))] pub search_description: Setting, - #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("This is query parameter..."))] pub search_q_param: Setting, - #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("This is index you want to search in..."))] pub search_index_uid_param: Setting, - #[serde(default, skip_serializing_if = "Setting::is_not_set")] + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option)] pub pre_query: Setting, } - -const DEFAULT_SYSTEM_MESSAGE: &str = "You are a highly capable research assistant with access to powerful search tools. IMPORTANT INSTRUCTIONS:\ - 1. When answering questions, you MUST make multiple tool calls (at least 2-3) to gather comprehensive information.\ - 2. Use different search queries for each tool call - vary keywords, rephrase questions, and explore different semantic angles to ensure broad coverage.\ - 3. Always explicitly announce BEFORE making each tool call by saying: \"I'll search for [specific information] now.\"\ - 4. Combine information from ALL tool calls to provide complete, nuanced answers rather than relying on a single source.\ - 5. For complex topics, break down your research into multiple targeted queries rather than using a single generic search."; - -/// The default description of the searchInIndex tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION: &str = - "Search the database for relevant JSON documents using an optional query."; -/// The default description of the searchInIndex `q` parameter tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION: &str = - "The search query string used to find relevant documents in the index. \ -This should contain keywords or phrases that best represent what the user is looking for. \ -More specific queries will yield more precise results."; -/// The default description of the searchInIndex `index` parameter tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION: &str = -"The name of the index to search within. An index is a collection of documents organized for search. \ -Selecting the right index ensures the most relevant results for the user query"; - -impl Default for GlobalChatSettings { - fn default() -> Self { - GlobalChatSettings { - source: Setting::NotSet, - base_api: Setting::NotSet, - api_key: Setting::NotSet, - prompts: Setting::Set(ChatPrompts::default()), - } - } -} - -impl Default for ChatPrompts { - fn default() -> Self { - ChatPrompts { - system: Setting::Set(DEFAULT_SYSTEM_MESSAGE.to_string()), - search_description: Setting::Set(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION.to_string()), - search_q_param: Setting::Set( - DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION.to_string(), - ), - search_index_uid_param: Setting::Set( - DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION.to_string(), - ), - pre_query: Setting::Set(Default::default()), - } - } -} From bed442528f554d162f243d6d4124711c9d7cbf6f Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Tue, 13 May 2025 16:22:33 +0200 Subject: [PATCH 165/292] Update charabia v0.9.4 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a21d2ab6..a7bebe2c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6067,9 +6067,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.1" +version = "1.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", "bytes", From 0efb72fe66f41505d10a88a70d0f8a19f49154e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 13 May 2025 11:19:32 +0200 Subject: [PATCH 166/292] Introduce the first version of the /chat route that mimics the OpenAI API --- Cargo.lock | 4 ++-- crates/meilisearch-types/src/keys.rs | 1 + crates/meilisearch/src/routes/chat.rs | 32 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 crates/meilisearch/src/routes/chat.rs diff --git a/Cargo.lock b/Cargo.lock index a7bebe2c6..4a21d2ab6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6067,9 +6067,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index e30ef1008..4fd1842ad 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -389,6 +389,7 @@ impl Action { EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), NETWORK_GET => Some(Self::NetworkGet), NETWORK_UPDATE => Some(Self::NetworkUpdate), + CHAT_GET => Some(Self::ChatGet), _otherwise => None, } } diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs new file mode 100644 index 000000000..1cb813acd --- /dev/null +++ b/crates/meilisearch/src/routes/chat.rs @@ -0,0 +1,32 @@ +use actix_web::web::{self, Data}; +use actix_web::HttpResponse; +use async_openai::config::OpenAIConfig; +use async_openai::types::CreateChatCompletionRequest; +use async_openai::Client; +use index_scheduler::IndexScheduler; +use meilisearch_types::error::ResponseError; +use meilisearch_types::keys::actions; + +use crate::extractors::authentication::policies::ActionPolicy; +use crate::extractors::authentication::GuardedData; + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.service(web::resource("").route(web::post().to(chat))); +} + +/// Get a chat completion +async fn chat( + _index_scheduler: GuardedData, Data>, + web::Json(chat_completion): web::Json, +) -> Result { + // To enable later on, when the feature will be experimental + // index_scheduler.features().check_chat("Using the /chat route")?; + + let api_key = std::env::var("MEILI_OPENAI_API_KEY") + .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); + let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base + let client = Client::with_config(config); + let response = client.chat().create(chat_completion).await.unwrap(); + + Ok(HttpResponse::Ok().json(response)) +} From ae135d1d46b12f3745941828b7e18e6a81d27301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 14 May 2025 11:18:21 +0200 Subject: [PATCH 167/292] Implement a first version of a streamed chat API --- crates/meilisearch/src/routes/chat.rs | 275 +++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 8 deletions(-) diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs index 1cb813acd..ad46d91c8 100644 --- a/crates/meilisearch/src/routes/chat.rs +++ b/crates/meilisearch/src/routes/chat.rs @@ -1,14 +1,50 @@ +use std::mem; + use actix_web::web::{self, Data}; -use actix_web::HttpResponse; +use actix_web::{Either, HttpResponse, Responder}; +use actix_web_lab::sse::{self, Event}; use async_openai::config::OpenAIConfig; -use async_openai::types::CreateChatCompletionRequest; +use async_openai::types::{ + ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, + ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, + ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, FinishReason, + FunctionObjectArgs, +}; use async_openai::Client; +use futures::StreamExt; use index_scheduler::IndexScheduler; use meilisearch_types::error::ResponseError; use meilisearch_types::keys::actions; +use meilisearch_types::milli::index::IndexEmbeddingConfig; +use meilisearch_types::milli::prompt::PromptData; +use meilisearch_types::milli::vector::EmbeddingConfig; +use meilisearch_types::{Document, Index}; +use serde::{Deserialize, Serialize}; +use serde_json::json; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; +use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; +use crate::routes::indexes::search::search_kind; +use crate::search::{ + add_search_rules, perform_search, HybridQuery, RetrieveVectors, SearchQuery, SemanticRatio, +}; +use crate::search_queue::SearchQueue; + +/// The default description of the searchInIndex tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION: &str = + "Search the database for relevant JSON documents using an optional query."; +/// The default description of the searchInIndex `q` parameter tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION: &str = + "The search query string used to find relevant documents in the index. \ +This should contain keywords or phrases that best represent what the user is looking for. \ +More specific queries will yield more precise results."; +/// The default description of the searchInIndex `index` parameter tool provided to OpenAI. +const DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION: &str = +"The name of the index to search within. An index is a collection of documents organized for search. \ +Selecting the right index ensures the most relevant results for the user query"; + +const EMBEDDER_NAME: &str = "openai"; pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("").route(web::post().to(chat))); @@ -16,17 +52,240 @@ pub fn configure(cfg: &mut web::ServiceConfig) { /// Get a chat completion async fn chat( - _index_scheduler: GuardedData, Data>, - web::Json(chat_completion): web::Json, -) -> Result { + index_scheduler: GuardedData, Data>, + search_queue: web::Data, + web::Json(mut chat_completion): web::Json, +) -> impl Responder { // To enable later on, when the feature will be experimental // index_scheduler.features().check_chat("Using the /chat route")?; + if chat_completion.stream.unwrap_or(false) { + Either::Right(streamed_chat(index_scheduler, search_queue, chat_completion).await) + } else { + Either::Left(non_streamed_chat(index_scheduler, search_queue, chat_completion).await) + } +} + +async fn non_streamed_chat( + index_scheduler: GuardedData, Data>, + search_queue: web::Data, + mut chat_completion: CreateChatCompletionRequest, +) -> Result { + let api_key = std::env::var("MEILI_OPENAI_API_KEY") + .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); + let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base + let client = Client::with_config(config); + + assert_eq!( + chat_completion.n.unwrap_or(1), + 1, + "Meilisearch /chat only support one completion at a time (n = 1, n = null)" + ); + + let rtxn = index_scheduler.read_txn().unwrap(); + let search_in_index_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) + .to_string(); + let search_in_index_q_param_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-q-param-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION) + .to_string(); + let search_in_index_index_description = index_scheduler + .chat_prompts(&rtxn, "searchInIndex-index-param-description") + .unwrap() + .unwrap_or(DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION) + .to_string(); + drop(rtxn); + + let mut response; + loop { + let tools = chat_completion.tools.get_or_insert_default(); + tools.push( + ChatCompletionToolArgs::default() + .r#type(ChatCompletionToolType::Function) + .function( + FunctionObjectArgs::default() + .name("searchInIndex") + .description(&search_in_index_description) + .parameters(json!({ + "type": "object", + "properties": { + "index_uid": { + "type": "string", + "enum": ["main"], + "description": search_in_index_index_description, + }, + "q": { + "type": ["string", "null"], + "description": search_in_index_q_param_description, + } + }, + "required": ["index_uid", "q"], + "additionalProperties": false, + })) + .strict(true) + .build() + .unwrap(), + ) + .build() + .unwrap(), + ); + response = client.chat().create(chat_completion.clone()).await.unwrap(); + + let choice = &mut response.choices[0]; + match choice.finish_reason { + Some(FinishReason::ToolCalls) => { + let tool_calls = mem::take(&mut choice.message.tool_calls).unwrap_or_default(); + + let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + tool_calls.into_iter().partition(|call| call.function.name == "searchInIndex"); + + chat_completion.messages.push( + ChatCompletionRequestAssistantMessageArgs::default() + .tool_calls(meili_calls.clone()) + .build() + .unwrap() + .into(), + ); + + for call in meili_calls { + let SearchInIndexParameters { index_uid, q } = + serde_json::from_str(&call.function.arguments).unwrap(); + + let mut query = SearchQuery { + q, + hybrid: Some(HybridQuery { + semantic_ratio: SemanticRatio::default(), + embedder: EMBEDDER_NAME.to_string(), + }), + limit: 20, + ..Default::default() + }; + + // Tenant token search_rules. + if let Some(search_rules) = + index_scheduler.filters().get_index_search_rules(&index_uid) + { + add_search_rules(&mut query.filter, search_rules); + } + + // TBD + // let mut aggregate = SearchAggregator::::from_query(&query); + + let index = index_scheduler.index(&index_uid)?; + let search_kind = search_kind( + &query, + index_scheduler.get_ref(), + index_uid.to_string(), + &index, + )?; + + let permit = search_queue.try_get_search_permit().await?; + let features = index_scheduler.features(); + let index_cloned = index.clone(); + let search_result = tokio::task::spawn_blocking(move || { + perform_search( + index_uid.to_string(), + &index_cloned, + query, + search_kind, + RetrieveVectors::new(false), + features, + ) + }) + .await; + permit.drop().await; + + let search_result = search_result?; + if let Ok(ref search_result) = search_result { + // aggregate.succeed(search_result); + if search_result.degraded { + MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); + } + } + // analytics.publish(aggregate, &req); + + let search_result = search_result?; + let formatted = format_documents( + &index, + search_result.hits.into_iter().map(|doc| doc.document), + ); + let text = formatted.join("\n"); + chat_completion.messages.push(ChatCompletionRequestMessage::Tool( + ChatCompletionRequestToolMessage { + tool_call_id: call.id, + content: ChatCompletionRequestToolMessageContent::Text(text), + }, + )); + } + + // Let the client call other tools by themselves + if !other_calls.is_empty() { + response.choices[0].message.tool_calls = Some(other_calls); + break; + } + } + _ => break, + } + } + + Ok(HttpResponse::Ok().json(response)) +} + +async fn streamed_chat( + index_scheduler: GuardedData, Data>, + search_queue: web::Data, + mut chat_completion: CreateChatCompletionRequest, +) -> impl Responder { + assert!(chat_completion.stream.unwrap_or(false)); + let api_key = std::env::var("MEILI_OPENAI_API_KEY") .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base let client = Client::with_config(config); - let response = client.chat().create(chat_completion).await.unwrap(); - - Ok(HttpResponse::Ok().json(response)) + let response = client.chat().create_stream(chat_completion).await.unwrap(); + actix_web_lab::sse::Sse::from_stream(response.map(|response| { + response + .map(|mut r| Event::Data(sse::Data::new_json(r.choices.pop().unwrap().delta).unwrap())) + })) +} + +#[derive(Deserialize)] +struct SearchInIndexParameters { + /// The index uid to search in. + index_uid: String, + /// The query parameter to use. + q: Option, +} + +fn format_documents(index: &Index, documents: impl Iterator) -> Vec { + let rtxn = index.read_txn().unwrap(); + let IndexEmbeddingConfig { name: _, config, user_provided: _ } = index + .embedding_configs(&rtxn) + .unwrap() + .into_iter() + .find(|conf| conf.name == EMBEDDER_NAME) + .unwrap(); + + let EmbeddingConfig { + embedder_options: _, + prompt: PromptData { template, max_bytes }, + quantized: _, + } = config; + + #[derive(Serialize)] + struct Doc { + doc: T, + } + + let template = liquid::ParserBuilder::with_stdlib().build().unwrap().parse(&template).unwrap(); + documents + .map(|doc| { + let object = liquid::to_object(&Doc { doc }).unwrap(); + template.render(&object).unwrap() + }) + .collect() } From 3b931e75d93364a73046722127ecbc76d35b608c Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Fri, 30 May 2025 15:56:57 +0200 Subject: [PATCH 168/292] Make the chats settings and chat completions route experimental --- crates/index-scheduler/src/features.rs | 13 +++++++++++++ crates/meilisearch-types/src/features.rs | 1 + .../meilisearch/src/analytics/segment_analytics.rs | 3 +++ .../src/routes/chats/chat_completions.rs | 5 ++--- crates/meilisearch/src/routes/chats/mod.rs | 2 ++ crates/meilisearch/src/routes/chats/settings.rs | 5 +++++ crates/meilisearch/src/routes/features.rs | 11 +++++++++++ 7 files changed, 37 insertions(+), 3 deletions(-) diff --git a/crates/index-scheduler/src/features.rs b/crates/index-scheduler/src/features.rs index 109e6b867..78ffc0766 100644 --- a/crates/index-scheduler/src/features.rs +++ b/crates/index-scheduler/src/features.rs @@ -131,6 +131,19 @@ impl RoFeatures { .into()) } } + + pub fn check_chat_completions(&self, disabled_action: &'static str) -> Result<()> { + if self.runtime.chat_completions { + Ok(()) + } else { + Err(FeatureNotEnabledError { + disabled_action, + feature: "chat completions", + issue_link: "https://github.com/orgs/meilisearch/discussions/835", + } + .into()) + } + } } impl FeatureData { diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index f12cbcfc9..10c39e09c 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -19,6 +19,7 @@ pub struct RuntimeTogglableFeatures { pub network: bool, pub get_task_documents_route: bool, pub composite_embedders: bool, + pub chat_completions: bool, } #[derive(Default, Debug, Clone, Copy)] diff --git a/crates/meilisearch/src/analytics/segment_analytics.rs b/crates/meilisearch/src/analytics/segment_analytics.rs index ee8a9ee20..c7e0634f4 100644 --- a/crates/meilisearch/src/analytics/segment_analytics.rs +++ b/crates/meilisearch/src/analytics/segment_analytics.rs @@ -197,6 +197,7 @@ struct Infos { experimental_max_number_of_batched_tasks: usize, experimental_limit_batched_tasks_total_size: u64, experimental_network: bool, + experimental_chat_completions: bool, experimental_get_task_documents_route: bool, experimental_composite_embedders: bool, experimental_embedding_cache_entries: usize, @@ -296,6 +297,7 @@ impl Infos { network, get_task_documents_route, composite_embedders, + chat_completions, } = features; // We're going to override every sensible information. @@ -314,6 +316,7 @@ impl Infos { experimental_enable_logs_route: experimental_enable_logs_route | logs_route, experimental_reduce_indexing_memory_usage, experimental_network: network, + experimental_chat_completions: chat_completions, experimental_get_task_documents_route: get_task_documents_route, experimental_composite_embedders: composite_embedders, experimental_embedding_cache_entries, diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index a923d2ff9..c82e29524 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -74,9 +74,6 @@ async fn chat( search_queue: web::Data, web::Json(chat_completion): web::Json, ) -> impl Responder { - // To enable later on, when the feature will be experimental - // index_scheduler.features().check_chat("Using the /chat route")?; - let ChatsParam { workspace_uid } = chats_param.into_inner(); assert_eq!( @@ -317,6 +314,7 @@ async fn non_streamed_chat( req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats chat completions route")?; let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; @@ -414,6 +412,7 @@ async fn streamed_chat( req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats chat completions route")?; let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 86feb14aa..0fa0d54b4 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -70,6 +70,8 @@ pub async fn list_workspaces( index_scheduler: GuardedData, Data>, paginate: AwebQueryParameter, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + debug!(parameters = ?paginate, "List chat workspaces"); let filters = index_scheduler.filters(); let (total, workspaces) = index_scheduler.paginated_chat_workspace_uids( diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 68ad2d45e..e118a3ef1 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -38,6 +38,8 @@ async fn get_settings( >, chats_param: web::Path, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here ??? @@ -63,6 +65,7 @@ async fn patch_settings( chats_param: web::Path, web::Json(new): web::Json, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here @@ -143,6 +146,8 @@ async fn delete_settings( >, chats_param: web::Path, ) -> Result { + index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here diff --git a/crates/meilisearch/src/routes/features.rs b/crates/meilisearch/src/routes/features.rs index eb8e7ac04..179b9cf68 100644 --- a/crates/meilisearch/src/routes/features.rs +++ b/crates/meilisearch/src/routes/features.rs @@ -53,6 +53,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { network: Some(false), get_task_documents_route: Some(false), composite_embedders: Some(false), + chat_completions: Some(false), })), (status = 401, description = "The authorization header is missing", body = ResponseError, content_type = "application/json", example = json!( { @@ -97,6 +98,8 @@ pub struct RuntimeTogglableFeatures { pub get_task_documents_route: Option, #[deserr(default)] pub composite_embedders: Option, + #[deserr(default)] + pub chat_completions: Option, } impl From for RuntimeTogglableFeatures { @@ -109,6 +112,7 @@ impl From for RuntimeTogg network, get_task_documents_route, composite_embedders, + chat_completions, } = value; Self { @@ -119,6 +123,7 @@ impl From for RuntimeTogg network: Some(network), get_task_documents_route: Some(get_task_documents_route), composite_embedders: Some(composite_embedders), + chat_completions: Some(chat_completions), } } } @@ -132,6 +137,7 @@ pub struct PatchExperimentalFeatureAnalytics { network: bool, get_task_documents_route: bool, composite_embedders: bool, + chat_completions: bool, } impl Aggregate for PatchExperimentalFeatureAnalytics { @@ -148,6 +154,7 @@ impl Aggregate for PatchExperimentalFeatureAnalytics { network: new.network, get_task_documents_route: new.get_task_documents_route, composite_embedders: new.composite_embedders, + chat_completions: new.chat_completions, }) } @@ -173,6 +180,7 @@ impl Aggregate for PatchExperimentalFeatureAnalytics { network: Some(false), get_task_documents_route: Some(false), composite_embedders: Some(false), + chat_completions: Some(false), })), (status = 401, description = "The authorization header is missing", body = ResponseError, content_type = "application/json", example = json!( { @@ -214,6 +222,7 @@ async fn patch_features( .0 .composite_embedders .unwrap_or(old_features.composite_embedders), + chat_completions: new_features.0.chat_completions.unwrap_or(old_features.chat_completions), }; // explicitly destructure for analytics rather than using the `Serialize` implementation, because @@ -227,6 +236,7 @@ async fn patch_features( network, get_task_documents_route, composite_embedders, + chat_completions, } = new_features; analytics.publish( @@ -238,6 +248,7 @@ async fn patch_features( network, get_task_documents_route, composite_embedders, + chat_completions, }, &req, ); From 87d2e213f34383d29c1c344c635ef31ea5f511f1 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Fri, 30 May 2025 16:03:48 +0200 Subject: [PATCH 169/292] Update chat keys --- crates/meilisearch-types/src/keys.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 4fd1842ad..a3f6ff046 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -324,12 +324,12 @@ pub enum Action { #[deserr(rename = "network.update")] NetworkUpdate, // TODO should we rename it chatCompletions.get ? - #[serde(rename = "chat.get")] - #[deserr(rename = "chat.get")] + #[serde(rename = "chat")] + #[deserr(rename = "chat")] Chat, #[serde(rename = "chats.get")] #[deserr(rename = "chats.get")] - Chats, + ChatsGet, #[serde(rename = "chatsSettings.*")] #[deserr(rename = "chatsSettings.*")] ChatsSettingsAll, @@ -368,7 +368,7 @@ impl Action { SETTINGS_GET => Some(Self::SettingsGet), SETTINGS_UPDATE => Some(Self::SettingsUpdate), CHAT => Some(Self::Chat), - CHATS_GET => Some(Self::Chats), + CHATS_GET => Some(Self::ChatsGet), CHATS_SETTINGS_ALL => Some(Self::ChatsSettingsAll), CHATS_SETTINGS_GET => Some(Self::ChatsSettingsGet), CHATS_SETTINGS_UPDATE => Some(Self::ChatsSettingsUpdate), @@ -389,7 +389,6 @@ impl Action { EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), NETWORK_GET => Some(Self::NetworkGet), NETWORK_UPDATE => Some(Self::NetworkUpdate), - CHAT_GET => Some(Self::ChatGet), _otherwise => None, } } @@ -440,7 +439,7 @@ pub mod actions { pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); pub const CHAT: u8 = Chat.repr(); - pub const CHATS_GET: u8 = Chats.repr(); + pub const CHATS_GET: u8 = ChatsGet.repr(); pub const CHATS_SETTINGS_ALL: u8 = ChatsSettingsAll.repr(); pub const CHATS_SETTINGS_GET: u8 = ChatsSettingsGet.repr(); pub const CHATS_SETTINGS_UPDATE: u8 = ChatsSettingsUpdate.repr(); From f827c2442c01dc2cc967774e52eb1197d2cdb127 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Fri, 30 May 2025 16:37:16 +0200 Subject: [PATCH 170/292] Mark tool calls to be implemented later for non-streaming --- crates/meilisearch/src/routes/chats/chat_completions.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index c82e29524..66fa12abf 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -338,7 +338,8 @@ async fn non_streamed_chat( let client = Client::with_config(config); let auth_token = extract_token_from_request(&req)?.unwrap(); - let FunctionSupport { report_progress, report_sources, append_to_conversation, report_errors } = + // TODO do function support later + let _function_support = setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; let mut response; @@ -377,8 +378,9 @@ async fn non_streamed_chat( Err(err) => Err(err.to_string()), }; + // TODO report documents sources later let text = match result { - Ok((_, documents, text)) => text, + Ok((_, _documents, text)) => text, Err(err) => err, }; From 201a808fe20935c50fdb5f8fc552760731b6d017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 3 Jun 2025 14:07:38 +0200 Subject: [PATCH 171/292] Better report errors happening with the underlying LLM --- Cargo.lock | 4 +- crates/meilisearch/Cargo.toml | 2 +- .../src/routes/chats/chat_completions.rs | 226 +++++++++++++++--- 3 files changed, 200 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a21d2ab6..e310c967d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -476,7 +476,7 @@ dependencies = [ [[package]] name = "async-openai" version = "0.28.1" -source = "git+https://github.com/meilisearch/async-openai?branch=optional-type-function#603f1d17bb4530c45fb9a6e93294ab715a7af869" +source = "git+https://github.com/meilisearch/async-openai?branch=better-error-handling#42d05e5f7dd7cdd46115c0855965f0b3f24754a2" dependencies = [ "async-openai-macros", "backoff", @@ -501,7 +501,7 @@ dependencies = [ [[package]] name = "async-openai-macros" version = "0.1.0" -source = "git+https://github.com/meilisearch/async-openai?branch=optional-type-function#603f1d17bb4530c45fb9a6e93294ab715a7af869" +source = "git+https://github.com/meilisearch/async-openai?branch=better-error-handling#42d05e5f7dd7cdd46115c0855965f0b3f24754a2" dependencies = [ "proc-macro2", "quote", diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index 62f7cfa0a..deea9f803 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -113,7 +113,7 @@ utoipa = { version = "5.3.1", features = [ "openapi_extensions", ] } utoipa-scalar = { version = "0.3.0", optional = true, features = ["actix-web"] } -async-openai = { git = "https://github.com/meilisearch/async-openai", branch = "optional-type-function" } +async-openai = { git = "https://github.com/meilisearch/async-openai", branch = "better-error-handling" } actix-web-lab = { version = "0.24.1", default-features = false } [dev-dependencies] diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 66fa12abf..e14ce3c2c 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -10,7 +10,8 @@ use actix_web::web::{self, Data}; use actix_web::{Either, HttpRequest, HttpResponse, Responder}; use actix_web_lab::sse::{self, Event, Sse}; use async_openai::config::{Config, OpenAIConfig}; -use async_openai::error::OpenAIError; +use async_openai::error::{ApiError, OpenAIError}; +use async_openai::reqwest_eventsource::Error as EventSourceError; use async_openai::types::{ ChatChoiceStream, ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, ChatCompletionRequestAssistantMessage, ChatCompletionRequestAssistantMessageArgs, @@ -45,6 +46,7 @@ use serde_json::json; use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; use tokio::sync::mpsc::Sender; +use uuid::Uuid; use super::ChatsParam; use crate::error::MeilisearchHttpError; @@ -120,9 +122,6 @@ pub struct FunctionSupport { /// Defines if we can call the _meiliAppendConversationMessage /// function to provide the messages to append into the conversation. append_to_conversation: bool, - /// Defines if we can call the _meiliReportErrors function - /// to inform the front-end about potential errors. - report_errors: bool, } /// Setup search tool in chat completion request @@ -222,7 +221,7 @@ fn setup_search_tool( }), ); - Ok(FunctionSupport { report_progress, report_sources, append_to_conversation, report_errors }) + Ok(FunctionSupport { report_progress, report_sources, append_to_conversation }) } /// Process search request and return formatted results @@ -441,6 +440,8 @@ async fn streamed_chat( let function_support = setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; + tracing::debug!("Conversation function support: {function_support:?}"); + let (tx, rx) = tokio::sync::mpsc::channel(10); let tx = SseEventSender(tx); let _join_handle = Handle::current().spawn(async move { @@ -491,7 +492,7 @@ async fn run_conversation( function_support: FunctionSupport, ) -> Result, ()>, SendError> { let mut finish_reason = None; - + // safety: The unwrap can only happen if the stream is not correctly configured. let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); while let Some(result) = response.next().await { match result { @@ -590,10 +591,9 @@ async fn run_conversation( } } } - Err(err) => { - if function_support.report_errors { - tx.report_error(err).await?; - } + Err(error) => { + let error = StreamErrorEvent::from_openai_error(error).await.unwrap(); + tx.send_error(&error).await?; return Ok(ControlFlow::Break(None)); } } @@ -835,25 +835,6 @@ impl SseEventSender { self.send_json(&resp).await } - pub async fn report_error(&self, error: OpenAIError) -> Result<(), SendError> { - tracing::error!("OpenAI Error: {}", error); - - let (error_code, message) = match error { - OpenAIError::Reqwest(e) => ("internal_reqwest_error", e.to_string()), - OpenAIError::ApiError(api_error) => ("llm_api_issue", api_error.to_string()), - OpenAIError::JSONDeserialize(error) => ("internal_json_deserialize", error.to_string()), - OpenAIError::FileSaveError(_) | OpenAIError::FileReadError(_) => unreachable!(), - OpenAIError::StreamError(error) => ("llm_api_stream_error", error.to_string()), - OpenAIError::InvalidArgument(error) => ("internal_invalid_argument", error.to_string()), - }; - - self.send_json(&json!({ - "error_code": error_code, - "message": message, - })) - .await - } - pub async fn forward_response( &self, resp: &CreateChatCompletionStreamResponse, @@ -861,6 +842,10 @@ impl SseEventSender { self.send_json(resp).await } + pub async fn send_error(&self, error: &StreamErrorEvent) -> Result<(), SendError> { + self.send_json(error).await + } + pub async fn stop(self) -> Result<(), SendError> { self.0.send(Event::Data(sse::Data::new("[DONE]"))).await } @@ -941,3 +926,186 @@ fn format_documents<'t, 'doc>( Ok(renders) } + +/// An error that occurs during the streaming process. +/// +/// It directly comes from the OpenAI API and you can +/// read more about error events on their website: +/// +#[derive(Debug, Serialize, Deserialize)] +pub struct StreamErrorEvent { + /// The unique ID of the server event. + event_id: String, + /// The event type, must be error. + r#type: String, + /// Details of the error. + error: StreamError, +} + +/// Details of the error. +#[derive(Debug, Serialize, Deserialize)] +pub struct StreamError { + /// The type of error (e.g., "invalid_request_error", "server_error"). + r#type: String, + /// Error code, if any. + code: Option, + /// A human-readable error message. + message: String, + /// Parameter related to the error, if any. + param: Option, + /// The event_id of the client event that caused the error, if applicable. + event_id: Option, +} + +impl StreamErrorEvent { + pub async fn from_openai_error(error: OpenAIError) -> Result { + let error_type = "error".to_string(); + match error { + OpenAIError::Reqwest(e) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "internal_reqwest_error".to_string(), + code: Some("internal".to_string()), + message: e.to_string(), + param: None, + event_id: None, + }, + }), + OpenAIError::ApiError(ApiError { message, r#type, param, code }) => { + Ok(StreamErrorEvent { + r#type: error_type, + event_id: Uuid::new_v4().to_string(), + error: StreamError { + r#type: r#type.unwrap_or_else(|| "unknown".to_string()), + code, + message, + param, + event_id: None, + }, + }) + } + OpenAIError::JSONDeserialize(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "json_deserialize_error".to_string(), + code: Some("internal".to_string()), + message: error.to_string(), + param: None, + event_id: None, + }, + }), + OpenAIError::FileSaveError(_) | OpenAIError::FileReadError(_) => unreachable!(), + OpenAIError::StreamError(error) => match error { + EventSourceError::InvalidStatusCode(_status_code, response) => { + let OpenAiOutsideError { + error: OpenAiInnerError { code, message, param, r#type }, + } = response.json().await?; + + Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { r#type, code, message, param, event_id: None }, + }) + } + EventSourceError::InvalidContentType(_header_value, response) => { + let OpenAiOutsideError { + error: OpenAiInnerError { code, message, param, r#type }, + } = response.json().await?; + + Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { r#type, code, message, param, event_id: None }, + }) + } + EventSourceError::Utf8(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "invalid_utf8_error".to_string(), + code: None, + message: error.to_string(), + param: None, + event_id: None, + }, + }), + EventSourceError::Parser(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "parser_error".to_string(), + code: None, + message: error.to_string(), + param: None, + event_id: None, + }, + }), + EventSourceError::Transport(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "transport_error".to_string(), + code: None, + message: error.to_string(), + param: None, + event_id: None, + }, + }), + EventSourceError::InvalidLastEventId(message) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "invalid_last_event_id".to_string(), + code: None, + message, + param: None, + event_id: None, + }, + }), + EventSourceError::StreamEnded => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "stream_ended".to_string(), + code: None, + message: "Stream ended".to_string(), + param: None, + event_id: None, + }, + }), + }, + OpenAIError::InvalidArgument(message) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "invalid_argument".to_string(), + code: None, + message, + param: None, + event_id: None, + }, + }), + } + } +} + +#[derive(Debug, Clone, Deserialize)] +pub struct OpenAiOutsideError { + /// Emitted when an error occurs. + error: OpenAiInnerError, +} + +/// Emitted when an error occurs. +#[derive(Debug, Clone, Deserialize)] +pub struct OpenAiInnerError { + /// The error code. + code: Option, + /// The error message. + message: String, + /// The error parameter. + param: Option, + /// The type of the event. Always `error`. + r#type: String, +} From 7d574433b603a115fe3d1805a97a1321023cb0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 3 Jun 2025 14:28:01 +0200 Subject: [PATCH 172/292] Clean up chat completions modules a bit --- .../src/routes/chats/chat_completions.rs | 450 +----------------- crates/meilisearch/src/routes/chats/errors.rs | 187 ++++++++ crates/meilisearch/src/routes/chats/mod.rs | 41 +- crates/meilisearch/src/routes/chats/utils.rs | 243 ++++++++++ 4 files changed, 472 insertions(+), 449 deletions(-) create mode 100644 crates/meilisearch/src/routes/chats/errors.rs create mode 100644 crates/meilisearch/src/routes/chats/utils.rs diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index e14ce3c2c..ed8df3c8b 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -1,26 +1,21 @@ -use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Write as _; use std::mem; use std::ops::ControlFlow; -use std::sync::RwLock; use std::time::Duration; use actix_web::web::{self, Data}; use actix_web::{Either, HttpRequest, HttpResponse, Responder}; -use actix_web_lab::sse::{self, Event, Sse}; +use actix_web_lab::sse::{Event, Sse}; use async_openai::config::{Config, OpenAIConfig}; -use async_openai::error::{ApiError, OpenAIError}; -use async_openai::reqwest_eventsource::Error as EventSourceError; use async_openai::types::{ - ChatChoiceStream, ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, - ChatCompletionRequestAssistantMessage, ChatCompletionRequestAssistantMessageArgs, - ChatCompletionRequestMessage, ChatCompletionRequestSystemMessage, - ChatCompletionRequestSystemMessageContent, ChatCompletionRequestToolMessage, - ChatCompletionRequestToolMessageContent, ChatCompletionStreamResponseDelta, - ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, - CreateChatCompletionStreamResponse, FinishReason, FunctionCall, FunctionCallStream, - FunctionObjectArgs, Role, + ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, + ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, + ChatCompletionRequestSystemMessage, ChatCompletionRequestSystemMessageContent, + ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, + ChatCompletionStreamResponseDelta, ChatCompletionToolArgs, ChatCompletionToolType, + CreateChatCompletionRequest, CreateChatCompletionStreamResponse, FinishReason, FunctionCall, + FunctionCallStream, FunctionObjectArgs, }; use async_openai::Client; use bumpalo::Bump; @@ -31,38 +26,30 @@ use meilisearch_types::error::{Code, ResponseError}; use meilisearch_types::features::{ ChatCompletionPrompts as DbChatCompletionPrompts, ChatCompletionSettings as DbChatSettings, }; -use meilisearch_types::heed::RoTxn; use meilisearch_types::keys::actions; use meilisearch_types::milli::index::ChatConfig; -use meilisearch_types::milli::prompt::{Prompt, PromptData}; -use meilisearch_types::milli::update::new::document::DocumentFromDb; -use meilisearch_types::milli::{ - all_obkv_to_json, obkv_to_json, DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, - MetadataBuilder, TimeBudget, -}; +use meilisearch_types::milli::{all_obkv_to_json, obkv_to_json, TimeBudget}; use meilisearch_types::{Document, Index}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use serde_json::json; use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; -use tokio::sync::mpsc::Sender; -use uuid::Uuid; -use super::ChatsParam; +use super::errors::StreamErrorEvent; +use super::utils::format_documents; +use super::{ + ChatsParam, MEILI_APPEND_CONVERSATION_MESSAGE_NAME, MEILI_SEARCH_IN_INDEX_FUNCTION_NAME, + MEILI_SEARCH_PROGRESS_NAME, MEILI_SEARCH_SOURCES_NAME, +}; use crate::error::MeilisearchHttpError; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::{extract_token_from_request, GuardedData, Policy as _}; use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; +use crate::routes::chats::utils::SseEventSender; use crate::routes::indexes::search::search_kind; use crate::search::{add_search_rules, prepare_search, search_from_kind, SearchQuery}; use crate::search_queue::SearchQueue; -const MEILI_SEARCH_PROGRESS_NAME: &str = "_meiliSearchProgress"; -const MEILI_APPEND_CONVERSATION_MESSAGE_NAME: &str = "_meiliAppendConversationMessage"; -const MEILI_SEARCH_SOURCES_NAME: &str = "_meiliSearchSources"; -const MEILI_REPORT_ERRORS_NAME: &str = "_meiliReportErrors"; -const MEILI_SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; - pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("").route(web::post().to(chat))); } @@ -140,7 +127,6 @@ fn setup_search_tool( let mut report_progress = false; let mut report_sources = false; let mut append_to_conversation = false; - let mut report_errors = false; tools.retain(|tool| { match tool.function.name.as_str() { MEILI_SEARCH_PROGRESS_NAME => { @@ -155,10 +141,6 @@ fn setup_search_tool( append_to_conversation = true; false } - MEILI_REPORT_ERRORS_NAME => { - report_errors = true; - false - } _ => true, // keep other tools } }); @@ -443,7 +425,7 @@ async fn streamed_chat( tracing::debug!("Conversation function support: {function_support:?}"); let (tx, rx) = tokio::sync::mpsc::channel(10); - let tx = SseEventSender(tx); + let tx = SseEventSender::new(tx); let _join_handle = Handle::current().spawn(async move { let client = Client::with_config(config.clone()); let mut global_tool_calls = HashMap::::new(); @@ -521,9 +503,7 @@ async fn run_conversation( } }) .or_insert_with(|| { - if name - .as_ref() - .map_or(false, |n| n == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME) + if name.as_deref() == Some(MEILI_SEARCH_IN_INDEX_FUNCTION_NAME) { Call::Internal { id: id.as_ref().unwrap().clone(), @@ -680,181 +660,6 @@ async fn handle_meili_tools( Ok(()) } -pub struct SseEventSender(Sender); - -impl SseEventSender { - /// Ask the front-end user to append this tool *call* to the conversation - pub async fn append_tool_call_conversation_message( - &self, - resp: CreateChatCompletionStreamResponse, - call_id: String, - function_name: String, - function_arguments: String, - ) -> Result<(), SendError> { - #[allow(deprecated)] - let message = - ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { - content: None, - refusal: None, - name: None, - audio: None, - tool_calls: Some(vec![ChatCompletionMessageToolCall { - id: call_id, - r#type: Some(ChatCompletionToolType::Function), - function: FunctionCall { name: function_name, arguments: function_arguments }, - }]), - function_call: None, - }); - - self.append_conversation_message(resp, &message).await - } - - /// Ask the front-end user to append this tool to the conversation - pub async fn append_conversation_message( - &self, - mut resp: CreateChatCompletionStreamResponse, - message: &ChatCompletionRequestMessage, - ) -> Result<(), SendError> { - let call_text = serde_json::to_string(message).unwrap(); - let tool_call = ChatCompletionMessageToolCallChunk { - index: 0, - id: Some(uuid::Uuid::new_v4().to_string()), - r#type: Some(ChatCompletionToolType::Function), - function: Some(FunctionCallStream { - name: Some(MEILI_APPEND_CONVERSATION_MESSAGE_NAME.to_string()), - arguments: Some(call_text), - }), - }; - - resp.choices[0] = ChatChoiceStream { - index: 0, - #[allow(deprecated)] - delta: ChatCompletionStreamResponseDelta { - content: None, - function_call: None, - tool_calls: Some(vec![tool_call]), - role: Some(Role::Assistant), - refusal: None, - }, - finish_reason: None, - logprobs: None, - }; - - self.send_json(&resp).await - } - - pub async fn report_search_progress( - &self, - mut resp: CreateChatCompletionStreamResponse, - call_id: &str, - function_name: &str, - function_arguments: &str, - ) -> Result<(), SendError> { - #[derive(Debug, Clone, Serialize)] - /// Provides information about the current Meilisearch search operation. - struct MeiliSearchProgress<'a> { - /// The call ID to track the sources of the search. - call_id: &'a str, - /// The name of the function we are executing. - function_name: &'a str, - /// The arguments of the function we are executing, encoded in JSON. - function_arguments: &'a str, - } - - let progress = MeiliSearchProgress { call_id, function_name, function_arguments }; - let call_text = serde_json::to_string(&progress).unwrap(); - let tool_call = ChatCompletionMessageToolCallChunk { - index: 0, - id: Some(uuid::Uuid::new_v4().to_string()), - r#type: Some(ChatCompletionToolType::Function), - function: Some(FunctionCallStream { - name: Some(MEILI_SEARCH_PROGRESS_NAME.to_string()), - arguments: Some(call_text), - }), - }; - - resp.choices[0] = ChatChoiceStream { - index: 0, - #[allow(deprecated)] - delta: ChatCompletionStreamResponseDelta { - content: None, - function_call: None, - tool_calls: Some(vec![tool_call]), - role: Some(Role::Assistant), - refusal: None, - }, - finish_reason: None, - logprobs: None, - }; - - self.send_json(&resp).await - } - - pub async fn report_sources( - &self, - mut resp: CreateChatCompletionStreamResponse, - call_id: &str, - documents: &[Document], - ) -> Result<(), SendError> { - #[derive(Debug, Clone, Serialize)] - /// Provides sources of the search. - struct MeiliSearchSources<'a> { - /// The call ID to track the original search associated to those sources. - call_id: &'a str, - /// The documents associated with the search (call_id). - /// Only the displayed attributes of the documents are returned. - sources: &'a [Document], - } - - let sources = MeiliSearchSources { call_id, sources: documents }; - let call_text = serde_json::to_string(&sources).unwrap(); - let tool_call = ChatCompletionMessageToolCallChunk { - index: 0, - id: Some(uuid::Uuid::new_v4().to_string()), - r#type: Some(ChatCompletionToolType::Function), - function: Some(FunctionCallStream { - name: Some(MEILI_SEARCH_SOURCES_NAME.to_string()), - arguments: Some(call_text), - }), - }; - - resp.choices[0] = ChatChoiceStream { - index: 0, - #[allow(deprecated)] - delta: ChatCompletionStreamResponseDelta { - content: None, - function_call: None, - tool_calls: Some(vec![tool_call]), - role: Some(Role::Assistant), - refusal: None, - }, - finish_reason: None, - logprobs: None, - }; - - self.send_json(&resp).await - } - - pub async fn forward_response( - &self, - resp: &CreateChatCompletionStreamResponse, - ) -> Result<(), SendError> { - self.send_json(resp).await - } - - pub async fn send_error(&self, error: &StreamErrorEvent) -> Result<(), SendError> { - self.send_json(error).await - } - - pub async fn stop(self) -> Result<(), SendError> { - self.0.send(Event::Data(sse::Data::new("[DONE]"))).await - } - - async fn send_json(&self, data: &S) -> Result<(), SendError> { - self.0.send(Event::Data(sse::Data::new_json(data).unwrap())).await - } -} - /// The structure used to aggregate the function calls to make. #[derive(Debug)] enum Call { @@ -892,220 +697,3 @@ struct SearchInIndexParameters { /// The query parameter to use. q: Option, } - -fn format_documents<'t, 'doc>( - rtxn: &RoTxn<'t>, - index: &Index, - doc_alloc: &'doc Bump, - internal_docids: Vec, -) -> Result, ResponseError> { - let ChatConfig { prompt: PromptData { template, max_bytes }, .. } = index.chat_config(rtxn)?; - - let prompt = Prompt::new(template, max_bytes).unwrap(); - let fid_map = index.fields_ids_map(rtxn)?; - let metadata_builder = MetadataBuilder::from_index(index, rtxn)?; - let fid_map_with_meta = FieldIdMapWithMetadata::new(fid_map.clone(), metadata_builder); - let global = RwLock::new(fid_map_with_meta); - let gfid_map = RefCell::new(GlobalFieldsIdsMap::new(&global)); - - let external_ids: Vec = index - .external_id_of(rtxn, internal_docids.iter().copied())? - .into_iter() - .collect::>()?; - - let mut renders = Vec::new(); - for (docid, external_docid) in internal_docids.into_iter().zip(external_ids) { - let document = match DocumentFromDb::new(docid, rtxn, index, &fid_map)? { - Some(doc) => doc, - None => continue, - }; - - let text = prompt.render_document(&external_docid, document, &gfid_map, doc_alloc).unwrap(); - renders.push(text); - } - - Ok(renders) -} - -/// An error that occurs during the streaming process. -/// -/// It directly comes from the OpenAI API and you can -/// read more about error events on their website: -/// -#[derive(Debug, Serialize, Deserialize)] -pub struct StreamErrorEvent { - /// The unique ID of the server event. - event_id: String, - /// The event type, must be error. - r#type: String, - /// Details of the error. - error: StreamError, -} - -/// Details of the error. -#[derive(Debug, Serialize, Deserialize)] -pub struct StreamError { - /// The type of error (e.g., "invalid_request_error", "server_error"). - r#type: String, - /// Error code, if any. - code: Option, - /// A human-readable error message. - message: String, - /// Parameter related to the error, if any. - param: Option, - /// The event_id of the client event that caused the error, if applicable. - event_id: Option, -} - -impl StreamErrorEvent { - pub async fn from_openai_error(error: OpenAIError) -> Result { - let error_type = "error".to_string(); - match error { - OpenAIError::Reqwest(e) => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "internal_reqwest_error".to_string(), - code: Some("internal".to_string()), - message: e.to_string(), - param: None, - event_id: None, - }, - }), - OpenAIError::ApiError(ApiError { message, r#type, param, code }) => { - Ok(StreamErrorEvent { - r#type: error_type, - event_id: Uuid::new_v4().to_string(), - error: StreamError { - r#type: r#type.unwrap_or_else(|| "unknown".to_string()), - code, - message, - param, - event_id: None, - }, - }) - } - OpenAIError::JSONDeserialize(error) => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "json_deserialize_error".to_string(), - code: Some("internal".to_string()), - message: error.to_string(), - param: None, - event_id: None, - }, - }), - OpenAIError::FileSaveError(_) | OpenAIError::FileReadError(_) => unreachable!(), - OpenAIError::StreamError(error) => match error { - EventSourceError::InvalidStatusCode(_status_code, response) => { - let OpenAiOutsideError { - error: OpenAiInnerError { code, message, param, r#type }, - } = response.json().await?; - - Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { r#type, code, message, param, event_id: None }, - }) - } - EventSourceError::InvalidContentType(_header_value, response) => { - let OpenAiOutsideError { - error: OpenAiInnerError { code, message, param, r#type }, - } = response.json().await?; - - Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { r#type, code, message, param, event_id: None }, - }) - } - EventSourceError::Utf8(error) => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "invalid_utf8_error".to_string(), - code: None, - message: error.to_string(), - param: None, - event_id: None, - }, - }), - EventSourceError::Parser(error) => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "parser_error".to_string(), - code: None, - message: error.to_string(), - param: None, - event_id: None, - }, - }), - EventSourceError::Transport(error) => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "transport_error".to_string(), - code: None, - message: error.to_string(), - param: None, - event_id: None, - }, - }), - EventSourceError::InvalidLastEventId(message) => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "invalid_last_event_id".to_string(), - code: None, - message, - param: None, - event_id: None, - }, - }), - EventSourceError::StreamEnded => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "stream_ended".to_string(), - code: None, - message: "Stream ended".to_string(), - param: None, - event_id: None, - }, - }), - }, - OpenAIError::InvalidArgument(message) => Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: error_type, - error: StreamError { - r#type: "invalid_argument".to_string(), - code: None, - message, - param: None, - event_id: None, - }, - }), - } - } -} - -#[derive(Debug, Clone, Deserialize)] -pub struct OpenAiOutsideError { - /// Emitted when an error occurs. - error: OpenAiInnerError, -} - -/// Emitted when an error occurs. -#[derive(Debug, Clone, Deserialize)] -pub struct OpenAiInnerError { - /// The error code. - code: Option, - /// The error message. - message: String, - /// The error parameter. - param: Option, - /// The type of the event. Always `error`. - r#type: String, -} diff --git a/crates/meilisearch/src/routes/chats/errors.rs b/crates/meilisearch/src/routes/chats/errors.rs new file mode 100644 index 000000000..f1aa9722b --- /dev/null +++ b/crates/meilisearch/src/routes/chats/errors.rs @@ -0,0 +1,187 @@ +use async_openai::error::{ApiError, OpenAIError}; +use async_openai::reqwest_eventsource::Error as EventSourceError; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Clone, Deserialize)] +pub struct OpenAiOutsideError { + /// Emitted when an error occurs. + error: OpenAiInnerError, +} + +/// Emitted when an error occurs. +#[derive(Debug, Clone, Deserialize)] +pub struct OpenAiInnerError { + /// The error code. + code: Option, + /// The error message. + message: String, + /// The error parameter. + param: Option, + /// The type of the event. Always `error`. + r#type: String, +} + +/// An error that occurs during the streaming process. +/// +/// It directly comes from the OpenAI API and you can +/// read more about error events on their website: +/// +#[derive(Debug, Serialize, Deserialize)] +pub struct StreamErrorEvent { + /// The unique ID of the server event. + pub event_id: String, + /// The event type, must be error. + pub r#type: String, + /// Details of the error. + pub error: StreamError, +} + +/// Details of the error. +#[derive(Debug, Serialize, Deserialize)] +pub struct StreamError { + /// The type of error (e.g., "invalid_request_error", "server_error"). + pub r#type: String, + /// Error code, if any. + pub code: Option, + /// A human-readable error message. + pub message: String, + /// Parameter related to the error, if any. + pub param: Option, + /// The event_id of the client event that caused the error, if applicable. + pub event_id: Option, +} + +impl StreamErrorEvent { + pub async fn from_openai_error(error: OpenAIError) -> Result { + let error_type = "error".to_string(); + match error { + OpenAIError::Reqwest(e) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "internal_reqwest_error".to_string(), + code: Some("internal".to_string()), + message: e.to_string(), + param: None, + event_id: None, + }, + }), + OpenAIError::ApiError(ApiError { message, r#type, param, code }) => { + Ok(StreamErrorEvent { + r#type: error_type, + event_id: Uuid::new_v4().to_string(), + error: StreamError { + r#type: r#type.unwrap_or_else(|| "unknown".to_string()), + code, + message, + param, + event_id: None, + }, + }) + } + OpenAIError::JSONDeserialize(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "json_deserialize_error".to_string(), + code: Some("internal".to_string()), + message: error.to_string(), + param: None, + event_id: None, + }, + }), + OpenAIError::FileSaveError(_) | OpenAIError::FileReadError(_) => unreachable!(), + OpenAIError::StreamError(error) => match error { + EventSourceError::InvalidStatusCode(_status_code, response) => { + let OpenAiOutsideError { + error: OpenAiInnerError { code, message, param, r#type }, + } = response.json().await?; + + Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { r#type, code, message, param, event_id: None }, + }) + } + EventSourceError::InvalidContentType(_header_value, response) => { + let OpenAiOutsideError { + error: OpenAiInnerError { code, message, param, r#type }, + } = response.json().await?; + + Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { r#type, code, message, param, event_id: None }, + }) + } + EventSourceError::Utf8(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "invalid_utf8_error".to_string(), + code: None, + message: error.to_string(), + param: None, + event_id: None, + }, + }), + EventSourceError::Parser(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "parser_error".to_string(), + code: None, + message: error.to_string(), + param: None, + event_id: None, + }, + }), + EventSourceError::Transport(error) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "transport_error".to_string(), + code: None, + message: error.to_string(), + param: None, + event_id: None, + }, + }), + EventSourceError::InvalidLastEventId(message) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "invalid_last_event_id".to_string(), + code: None, + message, + param: None, + event_id: None, + }, + }), + EventSourceError::StreamEnded => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "stream_ended".to_string(), + code: None, + message: "Stream ended".to_string(), + param: None, + event_id: None, + }, + }), + }, + OpenAIError::InvalidArgument(message) => Ok(StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: error_type, + error: StreamError { + r#type: "invalid_argument".to_string(), + code: None, + message, + param: None, + event_id: None, + }, + }), + } + } +} diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 0fa0d54b4..bb0476ab8 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -1,30 +1,35 @@ -use actix_web::{ - web::{self, Data}, - HttpResponse, -}; -use deserr::{actix_web::AwebQueryParameter, Deserr}; +use actix_web::web::{self, Data}; +use actix_web::HttpResponse; +use deserr::actix_web::AwebQueryParameter; +use deserr::Deserr; use index_scheduler::IndexScheduler; -use meilisearch_types::{ - deserr::{query_params::Param, DeserrQueryParamError}, - error::{ - deserr_codes::{InvalidIndexLimit, InvalidIndexOffset}, - ResponseError, - }, - keys::actions, -}; +use meilisearch_types::deserr::query_params::Param; +use meilisearch_types::deserr::DeserrQueryParamError; +use meilisearch_types::error::deserr_codes::{InvalidIndexLimit, InvalidIndexOffset}; +use meilisearch_types::error::ResponseError; +use meilisearch_types::keys::actions; use serde::{Deserialize, Serialize}; use tracing::debug; use utoipa::{IntoParams, ToSchema}; -use crate::{ - extractors::authentication::{policies::ActionPolicy, GuardedData}, - routes::PAGINATION_DEFAULT_LIMIT, -}; - use super::Pagination; +use crate::extractors::authentication::policies::ActionPolicy; +use crate::extractors::authentication::GuardedData; +use crate::routes::PAGINATION_DEFAULT_LIMIT; pub mod chat_completions; +mod errors; pub mod settings; +mod utils; + +/// The function name to report search progress. +const MEILI_SEARCH_PROGRESS_NAME: &str = "_meiliSearchProgress"; +/// The function name to append a conversation message in the user conversation. +const MEILI_APPEND_CONVERSATION_MESSAGE_NAME: &str = "_meiliAppendConversationMessage"; +/// The function name to report sources to the frontend. +const MEILI_SEARCH_SOURCES_NAME: &str = "_meiliSearchSources"; +/// The *internal* function name to provide to the LLM to search in indexes. +const MEILI_SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; #[derive(Deserialize)] pub struct ChatsParam { diff --git a/crates/meilisearch/src/routes/chats/utils.rs b/crates/meilisearch/src/routes/chats/utils.rs new file mode 100644 index 000000000..424b4ea64 --- /dev/null +++ b/crates/meilisearch/src/routes/chats/utils.rs @@ -0,0 +1,243 @@ +use std::cell::RefCell; +use std::sync::RwLock; + +use actix_web_lab::sse::{self, Event}; +use async_openai::types::{ + ChatChoiceStream, ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, + ChatCompletionRequestAssistantMessage, ChatCompletionRequestMessage, + ChatCompletionStreamResponseDelta, ChatCompletionToolType, CreateChatCompletionStreamResponse, + FunctionCall, FunctionCallStream, Role, +}; +use bumpalo::Bump; +use meilisearch_types::error::ResponseError; +use meilisearch_types::heed::RoTxn; +use meilisearch_types::milli::index::ChatConfig; +use meilisearch_types::milli::prompt::{Prompt, PromptData}; +use meilisearch_types::milli::update::new::document::DocumentFromDb; +use meilisearch_types::milli::{ + DocumentId, FieldIdMapWithMetadata, GlobalFieldsIdsMap, MetadataBuilder, +}; +use meilisearch_types::{Document, Index}; +use serde::Serialize; +use tokio::sync::mpsc::error::SendError; +use tokio::sync::mpsc::Sender; + +use super::errors::StreamErrorEvent; +use super::MEILI_APPEND_CONVERSATION_MESSAGE_NAME; +use crate::routes::chats::{MEILI_SEARCH_PROGRESS_NAME, MEILI_SEARCH_SOURCES_NAME}; + +pub struct SseEventSender(Sender); + +impl SseEventSender { + pub fn new(sender: Sender) -> Self { + Self(sender) + } + + /// Ask the front-end user to append this tool *call* to the conversation + pub async fn append_tool_call_conversation_message( + &self, + resp: CreateChatCompletionStreamResponse, + call_id: String, + function_name: String, + function_arguments: String, + ) -> Result<(), SendError> { + #[allow(deprecated)] + let message = + ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { + content: None, + refusal: None, + name: None, + audio: None, + tool_calls: Some(vec![ChatCompletionMessageToolCall { + id: call_id, + r#type: Some(ChatCompletionToolType::Function), + function: FunctionCall { name: function_name, arguments: function_arguments }, + }]), + function_call: None, + }); + + self.append_conversation_message(resp, &message).await + } + + /// Ask the front-end user to append this tool to the conversation + pub async fn append_conversation_message( + &self, + mut resp: CreateChatCompletionStreamResponse, + message: &ChatCompletionRequestMessage, + ) -> Result<(), SendError> { + let call_text = serde_json::to_string(message).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_APPEND_CONVERSATION_MESSAGE_NAME.to_string()), + arguments: Some(call_text), + }), + }; + + resp.choices[0] = ChatChoiceStream { + index: 0, + #[allow(deprecated)] + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + + self.send_json(&resp).await + } + + pub async fn report_search_progress( + &self, + mut resp: CreateChatCompletionStreamResponse, + call_id: &str, + function_name: &str, + function_arguments: &str, + ) -> Result<(), SendError> { + #[derive(Debug, Clone, Serialize)] + /// Provides information about the current Meilisearch search operation. + struct MeiliSearchProgress<'a> { + /// The call ID to track the sources of the search. + call_id: &'a str, + /// The name of the function we are executing. + function_name: &'a str, + /// The arguments of the function we are executing, encoded in JSON. + function_arguments: &'a str, + } + + let progress = MeiliSearchProgress { call_id, function_name, function_arguments }; + let call_text = serde_json::to_string(&progress).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_SEARCH_PROGRESS_NAME.to_string()), + arguments: Some(call_text), + }), + }; + + resp.choices[0] = ChatChoiceStream { + index: 0, + #[allow(deprecated)] + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + + self.send_json(&resp).await + } + + pub async fn report_sources( + &self, + mut resp: CreateChatCompletionStreamResponse, + call_id: &str, + documents: &[Document], + ) -> Result<(), SendError> { + #[derive(Debug, Clone, Serialize)] + /// Provides sources of the search. + struct MeiliSearchSources<'a> { + /// The call ID to track the original search associated to those sources. + call_id: &'a str, + /// The documents associated with the search (call_id). + /// Only the displayed attributes of the documents are returned. + sources: &'a [Document], + } + + let sources = MeiliSearchSources { call_id, sources: documents }; + let call_text = serde_json::to_string(&sources).unwrap(); + let tool_call = ChatCompletionMessageToolCallChunk { + index: 0, + id: Some(uuid::Uuid::new_v4().to_string()), + r#type: Some(ChatCompletionToolType::Function), + function: Some(FunctionCallStream { + name: Some(MEILI_SEARCH_SOURCES_NAME.to_string()), + arguments: Some(call_text), + }), + }; + + resp.choices[0] = ChatChoiceStream { + index: 0, + #[allow(deprecated)] + delta: ChatCompletionStreamResponseDelta { + content: None, + function_call: None, + tool_calls: Some(vec![tool_call]), + role: Some(Role::Assistant), + refusal: None, + }, + finish_reason: None, + logprobs: None, + }; + + self.send_json(&resp).await + } + + pub async fn forward_response( + &self, + resp: &CreateChatCompletionStreamResponse, + ) -> Result<(), SendError> { + self.send_json(resp).await + } + + pub async fn send_error(&self, error: &StreamErrorEvent) -> Result<(), SendError> { + self.send_json(error).await + } + + pub async fn stop(self) -> Result<(), SendError> { + self.0.send(Event::Data(sse::Data::new("[DONE]"))).await + } + + async fn send_json(&self, data: &S) -> Result<(), SendError> { + self.0.send(Event::Data(sse::Data::new_json(data).unwrap())).await + } +} + +/// Format documents based on the provided template and maximum bytes. +/// +/// This formatting function is usually used to generate a summary of the documents for LLMs. +pub fn format_documents<'t, 'doc>( + rtxn: &RoTxn<'t>, + index: &Index, + doc_alloc: &'doc Bump, + internal_docids: Vec, +) -> Result, ResponseError> { + let ChatConfig { prompt: PromptData { template, max_bytes }, .. } = index.chat_config(rtxn)?; + + let prompt = Prompt::new(template, max_bytes).unwrap(); + let fid_map = index.fields_ids_map(rtxn)?; + let metadata_builder = MetadataBuilder::from_index(index, rtxn)?; + let fid_map_with_meta = FieldIdMapWithMetadata::new(fid_map.clone(), metadata_builder); + let global = RwLock::new(fid_map_with_meta); + let gfid_map = RefCell::new(GlobalFieldsIdsMap::new(&global)); + + let external_ids: Vec = index + .external_id_of(rtxn, internal_docids.iter().copied())? + .into_iter() + .collect::>()?; + + let mut renders = Vec::new(); + for (docid, external_docid) in internal_docids.into_iter().zip(external_ids) { + let document = match DocumentFromDb::new(docid, rtxn, index, &fid_map)? { + Some(doc) => doc, + None => continue, + }; + + let text = prompt.render_document(&external_docid, document, &gfid_map, doc_alloc).unwrap(); + renders.push(text); + } + + Ok(renders) +} From 3c218cc3a03df5774598a4530406628f01fe1124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 3 Jun 2025 14:34:03 +0200 Subject: [PATCH 173/292] Update the default chat completions prompt Co-authored-by: Martin Grigorov --- crates/meilisearch-types/src/features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 10c39e09c..95706fb46 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -6,7 +6,7 @@ pub const DEFAULT_CHAT_SYSTEM_PROMPT: &str = "You are a highly capable research pub const DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT: &str = "Search the database for relevant JSON documents using an optional query."; pub const DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT: &str = "The search query string used to find relevant documents in the index. This should contain keywords or phrases that best represent what the user is looking for. More specific queries will yield more precise results."; -pub const DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT: &str = "The name of the index to search within. An index is a collection of documents organized for search. Selecting the right index ensures the most relevant results for the user query. You can access to two indexes: movies, steam. The movies index contains movies with overviews. The steam index contains steam games from the Steam platform with their prices"; +pub const DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT: &str = "The name of the index to search within. An index is a collection of documents organized for search. Selecting the right index ensures the most relevant results for the user query. You have access to two indexes: movies, steam. The movies index contains movies with overviews. The steam index contains steam games from the Steam platform with their prices"; pub const DEFAULT_CHAT_PRE_QUERY_PROMPT: &str = ""; #[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)] From 8fdcdee0ccc5d97ec253fc726c67a769a3f0b148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 3 Jun 2025 14:47:39 +0200 Subject: [PATCH 174/292] Do a first clippy pass --- .../src/routes/chats/chat_completions.rs | 24 ++++++++++--------- .../meilisearch/src/routes/chats/settings.rs | 6 ++--- crates/meilisearch/src/routes/chats/utils.rs | 4 ++-- crates/meilisearch/src/search/mod.rs | 2 +- crates/milli/src/index.rs | 2 +- crates/milli/src/update/chat.rs | 5 ---- crates/milli/src/update/settings.rs | 6 ++--- 7 files changed, 22 insertions(+), 27 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index ed8df3c8b..01e22d6f8 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -119,7 +119,7 @@ fn setup_search_tool( prompts: &DbChatCompletionPrompts, ) -> Result { let tools = chat_completion.tools.get_or_insert_default(); - if tools.iter().find(|t| t.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME).is_some() { + if tools.iter().any(|t| t.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME) { panic!("{MEILI_SEARCH_IN_INDEX_FUNCTION_NAME} function already set"); } @@ -149,7 +149,7 @@ fn setup_search_tool( let mut function_description = prompts.search_description.clone(); index_scheduler.try_for_each_index::<_, ()>(|name, index| { // Make sure to skip unauthorized indexes - if !filters.is_index_authorized(&name) { + if !filters.is_index_authorized(name) { return Ok(()); } @@ -350,7 +350,7 @@ async fn non_streamed_chat( &index_scheduler, auth_ctrl.clone(), &search_queue, - &auth_token, + auth_token, index_uid, q, ) @@ -461,6 +461,7 @@ async fn streamed_chat( /// Updates the chat completion with the new messages, streams the LLM tokens, /// and report progress and errors. +#[allow(clippy::too_many_arguments)] async fn run_conversation( index_scheduler: &GuardedData, Data>, auth_ctrl: &web::Data, @@ -515,7 +516,7 @@ async fn run_conversation( } }); - if global_tool_calls.get(index).map_or(false, Call::is_external) { + if global_tool_calls.get(index).is_some_and(Call::is_external) { todo!("Support forwarding external tool calls"); } } @@ -553,10 +554,10 @@ async fn run_conversation( ); handle_meili_tools( - &index_scheduler, - &auth_ctrl, - &search_queue, - &auth_token, + index_scheduler, + auth_ctrl, + search_queue, + auth_token, chat_settings, tx, meili_calls, @@ -586,6 +587,7 @@ async fn run_conversation( } } +#[allow(clippy::too_many_arguments)] async fn handle_meili_tools( index_scheduler: &GuardedData, Data>, auth_ctrl: &web::Data, @@ -621,10 +623,10 @@ async fn handle_meili_tools( let result = match serde_json::from_str(&call.function.arguments) { Ok(SearchInIndexParameters { index_uid, q }) => process_search_request( - &index_scheduler, + index_scheduler, auth_ctrl.clone(), - &search_queue, - &auth_token, + search_queue, + auth_token, index_uid, q, ) diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index e118a3ef1..a87fbed70 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -16,12 +16,11 @@ use meilisearch_types::milli::update::Setting; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; +use super::ChatsParam; use crate::extractors::authentication::policies::ActionPolicy; use crate::extractors::authentication::GuardedData; use crate::extractors::sequential_extractor::SeqHandler; -use super::ChatsParam; - pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service( web::resource("") @@ -70,8 +69,7 @@ async fn patch_settings( // TODO do a spawn_blocking here let mut wtxn = index_scheduler.write_txn()?; - let old_settings = - index_scheduler.chat_settings(&mut wtxn, &workspace_uid)?.unwrap_or_default(); + let old_settings = index_scheduler.chat_settings(&wtxn, &workspace_uid)?.unwrap_or_default(); let prompts = match new.prompts { Setting::Set(new_prompts) => DbChatCompletionPrompts { diff --git a/crates/meilisearch/src/routes/chats/utils.rs b/crates/meilisearch/src/routes/chats/utils.rs index 424b4ea64..b29747bc9 100644 --- a/crates/meilisearch/src/routes/chats/utils.rs +++ b/crates/meilisearch/src/routes/chats/utils.rs @@ -208,8 +208,8 @@ impl SseEventSender { /// Format documents based on the provided template and maximum bytes. /// /// This formatting function is usually used to generate a summary of the documents for LLMs. -pub fn format_documents<'t, 'doc>( - rtxn: &RoTxn<'t>, +pub fn format_documents<'doc>( + rtxn: &RoTxn<'_>, index: &Index, doc_alloc: &'doc Bump, internal_docids: Vec, diff --git a/crates/meilisearch/src/search/mod.rs b/crates/meilisearch/src/search/mod.rs index 037083b2d..27369591b 100644 --- a/crates/meilisearch/src/search/mod.rs +++ b/crates/meilisearch/src/search/mod.rs @@ -204,7 +204,7 @@ impl std::convert::TryFrom for RankingScoreThreshold { impl From for RankingScoreThreshold { fn from(threshold: index::RankingScoreThreshold) -> Self { let threshold = threshold.as_f64(); - assert!(threshold >= 0.0 && threshold <= 1.0); + assert!((0.0..=1.0).contains(&threshold)); RankingScoreThreshold(threshold) } } diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index b2df46af3..6ff972ae0 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -1984,7 +1984,7 @@ impl TryFrom for RankingScoreThreshold { type Error = InvalidSearchRankingScoreThreshold; fn try_from(value: f64) -> StdResult { - if value < 0.0 || value > 1.0 { + if !(0.0..=1.0).contains(&value) { Err(InvalidSearchRankingScoreThreshold) } else { Ok(RankingScoreThreshold(value)) diff --git a/crates/milli/src/update/chat.rs b/crates/milli/src/update/chat.rs index ae95ddfd9..c52ede029 100644 --- a/crates/milli/src/update/chat.rs +++ b/crates/milli/src/update/chat.rs @@ -69,11 +69,6 @@ impl From for ChatSettings { HybridQuery { semantic_ratio: SemanticRatio(semantic_ratio), embedder } }); - let matching_strategy = matching_strategy.map(MatchingStrategy::from); - - let ranking_score_threshold = - ranking_score_threshold.map(RankingScoreThreshold::from); - ChatSearchParams { hybrid: Setting::some_or_not_set(hybrid), limit: Setting::some_or_not_set(limit), diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index 9f152710a..0e44654a5 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -23,7 +23,7 @@ use crate::error::UserError; use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder}; use crate::filterable_attributes_rules::match_faceted_field; use crate::index::{ - ChatConfig, IndexEmbeddingConfig, MatchingStrategy, PrefixSearch, RankingScoreThreshold, + ChatConfig, IndexEmbeddingConfig, PrefixSearch, SearchParameters, DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS, }; use crate::order_by_map::OrderByMap; @@ -1326,7 +1326,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { }, matching_strategy: match matching_strategy { Setting::Set(matching_strategy) => { - Some(MatchingStrategy::from(*matching_strategy)) + Some(*matching_strategy) } Setting::Reset => None, Setting::NotSet => search_parameters.matching_strategy, @@ -1341,7 +1341,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { } }, ranking_score_threshold: match ranking_score_threshold { - Setting::Set(rst) => Some(RankingScoreThreshold::from(*rst)), + Setting::Set(rst) => Some(*rst), Setting::Reset => None, Setting::NotSet => search_parameters.ranking_score_threshold, }, From 82313a4444f09628bba063e57c8ea554b3e28d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 3 Jun 2025 14:50:21 +0200 Subject: [PATCH 175/292] Cargo fmt --- crates/benchmarks/benches/search_geo.rs | 3 ++- crates/benchmarks/benches/search_songs.rs | 3 ++- crates/index-scheduler/src/scheduler/mod.rs | 4 +++- crates/index-scheduler/src/scheduler/test_failure.rs | 3 +-- crates/meilisearch/tests/index/get_index.rs | 2 +- crates/meilisearch/tests/search/errors.rs | 3 +-- crates/meilisearch/tests/search/filters.rs | 6 +++--- crates/meilisearch/tests/search/geo.rs | 3 +-- crates/milli/src/database_stats.rs | 5 +---- crates/milli/src/disabled_typos_terms.rs | 9 ++++----- crates/milli/src/error.rs | 3 +-- crates/milli/src/filterable_attributes_rules.rs | 11 +++++------ crates/milli/src/progress.rs | 2 +- crates/milli/src/search/new/geo_sort.rs | 3 ++- crates/milli/src/search/new/mod.rs | 3 +-- .../src/update/new/extract/faceted/facet_document.rs | 3 +-- crates/milli/src/update/new/extract/mod.rs | 3 ++- crates/milli/src/update/settings.rs | 8 +++----- 18 files changed, 35 insertions(+), 42 deletions(-) diff --git a/crates/benchmarks/benches/search_geo.rs b/crates/benchmarks/benches/search_geo.rs index d76929f99..b16eb41f1 100644 --- a/crates/benchmarks/benches/search_geo.rs +++ b/crates/benchmarks/benches/search_geo.rs @@ -2,7 +2,8 @@ mod datasets_paths; mod utils; use criterion::{criterion_group, criterion_main}; -use milli::{update::Settings, FilterableAttributesRule}; +use milli::update::Settings; +use milli::FilterableAttributesRule; use utils::Conf; #[cfg(not(windows))] diff --git a/crates/benchmarks/benches/search_songs.rs b/crates/benchmarks/benches/search_songs.rs index 680a675ef..e1cbb5730 100644 --- a/crates/benchmarks/benches/search_songs.rs +++ b/crates/benchmarks/benches/search_songs.rs @@ -2,7 +2,8 @@ mod datasets_paths; mod utils; use criterion::{criterion_group, criterion_main}; -use milli::{update::Settings, FilterableAttributesRule}; +use milli::update::Settings; +use milli::FilterableAttributesRule; use utils::Conf; #[cfg(not(windows))] diff --git a/crates/index-scheduler/src/scheduler/mod.rs b/crates/index-scheduler/src/scheduler/mod.rs index f1775a892..0e258e27b 100644 --- a/crates/index-scheduler/src/scheduler/mod.rs +++ b/crates/index-scheduler/src/scheduler/mod.rs @@ -375,9 +375,11 @@ impl IndexScheduler { post_commit_dabases_sizes .get(dbname) .map(|post_size| { - use byte_unit::{Byte, UnitType::Binary}; use std::cmp::Ordering::{Equal, Greater, Less}; + use byte_unit::Byte; + use byte_unit::UnitType::Binary; + let post = Byte::from_u64(*post_size as u64).get_appropriate_unit(Binary); let diff_size = post_size.abs_diff(*pre_size) as u64; let diff = Byte::from_u64(diff_size).get_appropriate_unit(Binary); diff --git a/crates/index-scheduler/src/scheduler/test_failure.rs b/crates/index-scheduler/src/scheduler/test_failure.rs index 191910d38..ad7f22bd8 100644 --- a/crates/index-scheduler/src/scheduler/test_failure.rs +++ b/crates/index-scheduler/src/scheduler/test_failure.rs @@ -2,10 +2,9 @@ use std::time::Instant; use big_s::S; use meili_snap::snapshot; -use meilisearch_types::milli::obkv_to_json; use meilisearch_types::milli::update::IndexDocumentsMethod::*; use meilisearch_types::milli::update::Setting; -use meilisearch_types::milli::FilterableAttributesRule; +use meilisearch_types::milli::{obkv_to_json, FilterableAttributesRule}; use meilisearch_types::tasks::{Kind, KindWithContent}; use crate::insta_snapshot::snapshot_index_scheduler; diff --git a/crates/meilisearch/tests/index/get_index.rs b/crates/meilisearch/tests/index/get_index.rs index a436b649b..b07b7821b 100644 --- a/crates/meilisearch/tests/index/get_index.rs +++ b/crates/meilisearch/tests/index/get_index.rs @@ -1,8 +1,8 @@ -use crate::json; use meili_snap::{json_string, snapshot}; use serde_json::Value; use crate::common::{shared_does_not_exists_index, Server}; +use crate::json; #[actix_rt::test] async fn create_and_get_index() { diff --git a/crates/meilisearch/tests/search/errors.rs b/crates/meilisearch/tests/search/errors.rs index 2b63a07b1..7490544bf 100644 --- a/crates/meilisearch/tests/search/errors.rs +++ b/crates/meilisearch/tests/search/errors.rs @@ -1,10 +1,9 @@ use meili_snap::*; +use super::test_settings_documents_indexing_swapping_and_search; use crate::common::{shared_does_not_exists_index, Server, DOCUMENTS, NESTED_DOCUMENTS}; use crate::json; -use super::test_settings_documents_indexing_swapping_and_search; - #[actix_rt::test] async fn search_unexisting_index() { let index = shared_does_not_exists_index().await; diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 4219d2ec1..ec80eb63e 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,10 +3,10 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; -use crate::{ - common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, - json, +use crate::common::{ + default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS, }; +use crate::json; #[actix_rt::test] async fn search_with_filter_string_notation() { diff --git a/crates/meilisearch/tests/search/geo.rs b/crates/meilisearch/tests/search/geo.rs index a314ca241..eda02e440 100644 --- a/crates/meilisearch/tests/search/geo.rs +++ b/crates/meilisearch/tests/search/geo.rs @@ -2,11 +2,10 @@ use meili_snap::{json_string, snapshot}; use meilisearch_types::milli::constants::RESERVED_GEO_FIELD_NAME; use once_cell::sync::Lazy; +use super::test_settings_documents_indexing_swapping_and_search; use crate::common::{Server, Value}; use crate::json; -use super::test_settings_documents_indexing_swapping_and_search; - static DOCUMENTS: Lazy = Lazy::new(|| { json!([ { diff --git a/crates/milli/src/database_stats.rs b/crates/milli/src/database_stats.rs index 7da1fbd2b..381408621 100644 --- a/crates/milli/src/database_stats.rs +++ b/crates/milli/src/database_stats.rs @@ -1,9 +1,6 @@ use std::mem; -use heed::Database; -use heed::DatabaseStat; -use heed::RoTxn; -use heed::Unspecified; +use heed::{Database, DatabaseStat, RoTxn, Unspecified}; use serde::{Deserialize, Serialize}; use crate::BEU32; diff --git a/crates/milli/src/disabled_typos_terms.rs b/crates/milli/src/disabled_typos_terms.rs index 7ae35f828..c5acad7cd 100644 --- a/crates/milli/src/disabled_typos_terms.rs +++ b/crates/milli/src/disabled_typos_terms.rs @@ -1,10 +1,9 @@ -use heed::{ - types::{SerdeJson, Str}, - RoTxn, RwTxn, -}; +use heed::types::{SerdeJson, Str}; +use heed::{RoTxn, RwTxn}; use serde::{Deserialize, Serialize}; -use crate::{index::main_key, Index}; +use crate::index::main_key; +use crate::Index; #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] #[serde(rename_all = "camelCase")] diff --git a/crates/milli/src/error.rs b/crates/milli/src/error.rs index 237a895d3..e129a31a0 100644 --- a/crates/milli/src/error.rs +++ b/crates/milli/src/error.rs @@ -1,5 +1,4 @@ -use std::collections::BTreeSet; -use std::collections::HashMap; +use std::collections::{BTreeSet, HashMap}; use std::convert::Infallible; use std::fmt::Write; use std::{io, str}; diff --git a/crates/milli/src/filterable_attributes_rules.rs b/crates/milli/src/filterable_attributes_rules.rs index 53af30fd6..ae1a9755a 100644 --- a/crates/milli/src/filterable_attributes_rules.rs +++ b/crates/milli/src/filterable_attributes_rules.rs @@ -1,13 +1,12 @@ +use std::collections::{BTreeSet, HashSet}; + use deserr::{DeserializeError, Deserr, ValuePointerRef}; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeSet, HashSet}; use utoipa::ToSchema; -use crate::{ - attribute_patterns::{match_distinct_field, match_field_legacy, PatternMatch}, - constants::RESERVED_GEO_FIELD_NAME, - AttributePatterns, -}; +use crate::attribute_patterns::{match_distinct_field, match_field_legacy, PatternMatch}; +use crate::constants::RESERVED_GEO_FIELD_NAME; +use crate::AttributePatterns; #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, ToSchema)] #[serde(untagged)] diff --git a/crates/milli/src/progress.rs b/crates/milli/src/progress.rs index 75dafa8ec..fa651e17f 100644 --- a/crates/milli/src/progress.rs +++ b/crates/milli/src/progress.rs @@ -1,4 +1,3 @@ -use enum_iterator::Sequence; use std::any::TypeId; use std::borrow::Cow; use std::marker::PhantomData; @@ -6,6 +5,7 @@ use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::{Arc, RwLock}; use std::time::{Duration, Instant}; +use enum_iterator::Sequence; use indexmap::IndexMap; use itertools::Itertools; use serde::Serialize; diff --git a/crates/milli/src/search/new/geo_sort.rs b/crates/milli/src/search/new/geo_sort.rs index 663599553..3e7fe3458 100644 --- a/crates/milli/src/search/new/geo_sort.rs +++ b/crates/milli/src/search/new/geo_sort.rs @@ -1,8 +1,9 @@ +use std::collections::VecDeque; + use heed::types::{Bytes, Unit}; use heed::{RoPrefix, RoTxn}; use roaring::RoaringBitmap; use rstar::RTree; -use std::collections::VecDeque; use super::facet_string_values; use super::ranking_rules::{RankingRule, RankingRuleOutput, RankingRuleQueryTrait}; diff --git a/crates/milli/src/search/new/mod.rs b/crates/milli/src/search/new/mod.rs index 6e794ef53..86d0816ba 100644 --- a/crates/milli/src/search/new/mod.rs +++ b/crates/milli/src/search/new/mod.rs @@ -47,8 +47,7 @@ use sort::Sort; use self::distinct::facet_string_values; use self::geo_sort::GeoSort; -pub use self::geo_sort::Parameter as GeoSortParameter; -pub use self::geo_sort::Strategy as GeoSortStrategy; +pub use self::geo_sort::{Parameter as GeoSortParameter, Strategy as GeoSortStrategy}; use self::graph_based_ranking_rule::Words; use self::interner::Interned; use self::vector_sort::VectorSort; diff --git a/crates/milli/src/update/new/extract/faceted/facet_document.rs b/crates/milli/src/update/new/extract/faceted/facet_document.rs index e74131402..ff15f146d 100644 --- a/crates/milli/src/update/new/extract/faceted/facet_document.rs +++ b/crates/milli/src/update/new/extract/faceted/facet_document.rs @@ -4,6 +4,7 @@ use serde_json::Value; use crate::attribute_patterns::PatternMatch; use crate::fields_ids_map::metadata::Metadata; +use crate::filterable_attributes_rules::match_faceted_field; use crate::update::new::document::Document; use crate::update::new::extract::geo::extract_geo_coordinates; use crate::update::new::extract::perm_json_p; @@ -11,8 +12,6 @@ use crate::{ FieldId, FilterableAttributesRule, GlobalFieldsIdsMap, InternalError, Result, UserError, }; -use crate::filterable_attributes_rules::match_faceted_field; - #[allow(clippy::too_many_arguments)] pub fn extract_document_facets<'doc>( document: impl Document<'doc>, diff --git a/crates/milli/src/update/new/extract/mod.rs b/crates/milli/src/update/new/extract/mod.rs index a8264ba4a..2abefb098 100644 --- a/crates/milli/src/update/new/extract/mod.rs +++ b/crates/milli/src/update/new/extract/mod.rs @@ -18,7 +18,8 @@ pub use vectors::EmbeddingExtractor; pub mod perm_json_p { use serde_json::{Map, Value}; - use crate::{attribute_patterns::PatternMatch, Result}; + use crate::attribute_patterns::PatternMatch; + use crate::Result; const SPLIT_SYMBOL: char = '.'; /// Returns `true` if the `selector` match the `key`. diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index 0e44654a5..70a190b19 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -23,8 +23,8 @@ use crate::error::UserError; use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder}; use crate::filterable_attributes_rules::match_faceted_field; use crate::index::{ - ChatConfig, IndexEmbeddingConfig, PrefixSearch, - SearchParameters, DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS, + ChatConfig, IndexEmbeddingConfig, PrefixSearch, SearchParameters, + DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS, }; use crate::order_by_map::OrderByMap; use crate::prompt::{default_max_bytes, default_template_text, PromptData}; @@ -1325,9 +1325,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { Setting::NotSet => search_parameters.distinct.clone(), }, matching_strategy: match matching_strategy { - Setting::Set(matching_strategy) => { - Some(*matching_strategy) - } + Setting::Set(matching_strategy) => Some(*matching_strategy), Setting::Reset => None, Setting::NotSet => search_parameters.matching_strategy, }, From c4e1407e77be9fdb34964725513b312e2627db3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 3 Jun 2025 15:13:42 +0200 Subject: [PATCH 176/292] Fix the chat, chats, and chatsSettings actions --- crates/meilisearch-auth/src/store.rs | 7 +++++++ crates/meilisearch-types/src/keys.rs | 14 ++++++------- .../src/extractors/authentication/mod.rs | 2 +- .../src/routes/chats/chat_completions.rs | 21 +++++++++++++------ 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/crates/meilisearch-auth/src/store.rs b/crates/meilisearch-auth/src/store.rs index 2fd380194..e20f259ee 100644 --- a/crates/meilisearch-auth/src/store.rs +++ b/crates/meilisearch-auth/src/store.rs @@ -125,6 +125,13 @@ impl HeedAuthStore { Action::MetricsAll => { actions.insert(Action::MetricsGet); } + Action::ChatsSettingsAll => { + actions.extend([ + Action::ChatsSettingsGet, + Action::ChatsSettingsUpdate, + Action::ChatsSettingsDelete, + ]); + } other => { actions.insert(*other); } diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index a3f6ff046..5634d585f 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -53,7 +53,7 @@ pub struct CreateApiKey { #[schema(example = json!(["documents.add"]))] #[deserr(error = DeserrJsonError, missing_field_error = DeserrJsonError::missing_api_key_actions)] pub actions: Vec, - /// A list of accesible indexes permitted for the key. `["*"]` for all indexes. The `*` character can be used as a wildcard when located at the last position. e.g. `products_*` to allow access to all indexes whose names start with `products_`. + /// A list of accessible indexes permitted for the key. `["*"]` for all indexes. The `*` character can be used as a wildcard when located at the last position. e.g. `products_*` to allow access to all indexes whose names start with `products_`. #[deserr(error = DeserrJsonError, missing_field_error = DeserrJsonError::missing_api_key_indexes)] #[schema(value_type = Vec, example = json!(["products"]))] pub indexes: Vec, @@ -166,7 +166,7 @@ impl Key { name: Some("Default Chat API Key".to_string()), description: Some("Use it to chat and search from the frontend".to_string()), uid, - actions: vec![Action::Chat, Action::Search], + actions: vec![Action::ChatCompletions, Action::Search], indexes: vec![IndexUidPattern::all()], expires_at: None, created_at: now, @@ -324,9 +324,9 @@ pub enum Action { #[deserr(rename = "network.update")] NetworkUpdate, // TODO should we rename it chatCompletions.get ? - #[serde(rename = "chat")] - #[deserr(rename = "chat")] - Chat, + #[serde(rename = "chatCompletion")] + #[deserr(rename = "chatCompletion")] + ChatCompletions, #[serde(rename = "chats.get")] #[deserr(rename = "chats.get")] ChatsGet, @@ -367,7 +367,7 @@ impl Action { SETTINGS_ALL => Some(Self::SettingsAll), SETTINGS_GET => Some(Self::SettingsGet), SETTINGS_UPDATE => Some(Self::SettingsUpdate), - CHAT => Some(Self::Chat), + CHAT_COMPLETIONS => Some(Self::ChatCompletions), CHATS_GET => Some(Self::ChatsGet), CHATS_SETTINGS_ALL => Some(Self::ChatsSettingsAll), CHATS_SETTINGS_GET => Some(Self::ChatsSettingsGet), @@ -438,7 +438,7 @@ pub mod actions { pub const NETWORK_GET: u8 = NetworkGet.repr(); pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); - pub const CHAT: u8 = Chat.repr(); + pub const CHAT_COMPLETIONS: u8 = ChatCompletions.repr(); pub const CHATS_GET: u8 = ChatsGet.repr(); pub const CHATS_SETTINGS_ALL: u8 = ChatsSettingsAll.repr(); pub const CHATS_SETTINGS_GET: u8 = ChatsSettingsGet.repr(); diff --git a/crates/meilisearch/src/extractors/authentication/mod.rs b/crates/meilisearch/src/extractors/authentication/mod.rs index eb250190d..86614f153 100644 --- a/crates/meilisearch/src/extractors/authentication/mod.rs +++ b/crates/meilisearch/src/extractors/authentication/mod.rs @@ -309,7 +309,7 @@ pub mod policies { token: &str, ) -> Result { // Only search and chat actions can be accessed by a tenant token. - if A != actions::SEARCH && A != actions::CHAT { + if A != actions::SEARCH && A != actions::CHAT_COMPLETIONS { return Ok(TenantTokenOutcome::NotATenantToken); } diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 01e22d6f8..8b7ff2689 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -56,7 +56,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { /// Get a chat completion async fn chat( - index_scheduler: GuardedData, Data>, + index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, chats_param: web::Path, req: HttpRequest, @@ -208,7 +208,10 @@ fn setup_search_tool( /// Process search request and return formatted results async fn process_search_request( - index_scheduler: &GuardedData, Data>, + index_scheduler: &GuardedData< + ActionPolicy<{ actions::CHAT_COMPLETIONS }>, + Data, + >, auth_ctrl: web::Data, search_queue: &web::Data, auth_token: &str, @@ -288,7 +291,7 @@ async fn process_search_request( } async fn non_streamed_chat( - index_scheduler: GuardedData, Data>, + index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, search_queue: web::Data, workspace_uid: &str, @@ -388,7 +391,7 @@ async fn non_streamed_chat( } async fn streamed_chat( - index_scheduler: GuardedData, Data>, + index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, search_queue: web::Data, workspace_uid: &str, @@ -463,7 +466,10 @@ async fn streamed_chat( /// and report progress and errors. #[allow(clippy::too_many_arguments)] async fn run_conversation( - index_scheduler: &GuardedData, Data>, + index_scheduler: &GuardedData< + ActionPolicy<{ actions::CHAT_COMPLETIONS }>, + Data, + >, auth_ctrl: &web::Data, search_queue: &web::Data, auth_token: &str, @@ -589,7 +595,10 @@ async fn run_conversation( #[allow(clippy::too_many_arguments)] async fn handle_meili_tools( - index_scheduler: &GuardedData, Data>, + index_scheduler: &GuardedData< + ActionPolicy<{ actions::CHAT_COMPLETIONS }>, + Data, + >, auth_ctrl: &web::Data, search_queue: &web::Data, auth_token: &str, From 28dc7b836ba277ec07162ba0b70628d7164f73f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 3 Jun 2025 17:10:53 +0200 Subject: [PATCH 177/292] Fix the chat completions feature gate --- .../src/routes/chats/chat_completions.rs | 4 ++-- crates/meilisearch/src/routes/chats/mod.rs | 2 +- crates/meilisearch/src/routes/chats/settings.rs | 6 +++--- crates/meilisearch/src/routes/indexes/settings.rs | 15 ++++++++++++++- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 8b7ff2689..6f6b50d1c 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -298,7 +298,7 @@ async fn non_streamed_chat( req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { - index_scheduler.features().check_chat_completions("Using the /chats chat completions route")?; + index_scheduler.features().check_chat_completions("using the /chats chat completions route")?; let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; @@ -398,7 +398,7 @@ async fn streamed_chat( req: HttpRequest, mut chat_completion: CreateChatCompletionRequest, ) -> Result { - index_scheduler.features().check_chat_completions("Using the /chats chat completions route")?; + index_scheduler.features().check_chat_completions("using the /chats chat completions route")?; let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index bb0476ab8..35afd69c0 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -75,7 +75,7 @@ pub async fn list_workspaces( index_scheduler: GuardedData, Data>, paginate: AwebQueryParameter, ) -> Result { - index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + index_scheduler.features().check_chat_completions("listing the chats")?; debug!(parameters = ?paginate, "List chat workspaces"); let filters = index_scheduler.filters(); diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index a87fbed70..0bb25f30d 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -37,7 +37,7 @@ async fn get_settings( >, chats_param: web::Path, ) -> Result { - index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + index_scheduler.features().check_chat_completions("using the /chats/settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); @@ -64,7 +64,7 @@ async fn patch_settings( chats_param: web::Path, web::Json(new): web::Json, ) -> Result { - index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + index_scheduler.features().check_chat_completions("using the /chats/settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here @@ -144,7 +144,7 @@ async fn delete_settings( >, chats_param: web::Path, ) -> Result { - index_scheduler.features().check_chat_completions("Using the /chats settings route")?; + index_scheduler.features().check_chat_completions("using the /chats/settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); diff --git a/crates/meilisearch/src/routes/indexes/settings.rs b/crates/meilisearch/src/routes/indexes/settings.rs index a35ae5136..d91c3cd35 100644 --- a/crates/meilisearch/src/routes/indexes/settings.rs +++ b/crates/meilisearch/src/routes/indexes/settings.rs @@ -5,6 +5,7 @@ use index_scheduler::IndexScheduler; use meilisearch_types::deserr::DeserrJsonError; use meilisearch_types::error::ResponseError; use meilisearch_types::index_uid::IndexUid; +use meilisearch_types::milli::update::Setting; use meilisearch_types::settings::{ settings, ChatSettings, SecretPolicy, SettingEmbeddingSettings, Settings, Unchecked, }; @@ -568,6 +569,10 @@ pub async fn update_all( debug!(parameters = ?new_settings, "Update all settings"); let new_settings = validate_settings(new_settings, &index_scheduler)?; + if !new_settings.chat.is_not_set() { + index_scheduler.features().check_chat_completions("setting `chat` in the index route")?; + } + analytics.publish( SettingsAnalytics { ranking_rules: RankingRulesAnalytics::new(new_settings.ranking_rules.as_ref().set()), @@ -663,7 +668,11 @@ pub async fn get_all( let index = index_scheduler.index(&index_uid)?; let rtxn = index.read_txn()?; - let new_settings = settings(&index, &rtxn, SecretPolicy::HideSecrets)?; + let mut new_settings = settings(&index, &rtxn, SecretPolicy::HideSecrets)?; + if index_scheduler.features().check_chat_completions("showing index `chat` settings").is_err() { + new_settings.chat = Setting::NotSet; + } + debug!(returns = ?new_settings, "Get all settings"); Ok(HttpResponse::Ok().json(new_settings)) } @@ -753,5 +762,9 @@ fn validate_settings( } } + if let Setting::Set(_chat) = &settings.chat { + features.check_chat_completions("setting `chat` in the index settings")?; + } + Ok(settings.validate()?) } From 352ac759b528e3662f0160353345a8ef202b13a8 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Wed, 4 Jun 2025 09:35:43 +0200 Subject: [PATCH 178/292] Update dependencies --- Cargo.lock | 2108 +++++++++++++++++++++++++++------------------------- 1 file changed, 1078 insertions(+), 1030 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e310c967d..4e897e580 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,11 +4,11 @@ version = 4 [[package]] name = "actix-codec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "bytes", "futures-core", "futures-sink", @@ -21,13 +21,13 @@ dependencies = [ [[package]] name = "actix-cors" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" +checksum = "daa239b93927be1ff123eebada5a3ff23e89f0124ccb8609234e5103d5a5ae6d" dependencies = [ "actix-utils", "actix-web", - "derive_more 0.99.17", + "derive_more", "futures-util", "log", "once_cell", @@ -46,17 +46,17 @@ dependencies = [ "actix-tls", "actix-utils", "base64 0.22.1", - "bitflags 2.9.0", + "bitflags 2.9.1", "brotli 8.0.1", "bytes", "bytestring", - "derive_more 2.0.1", + "derive_more", "encoding_rs", "flate2", "foldhash", "futures-core", "h2 0.3.26", - "http 0.2.11", + "http 0.2.12", "httparse", "httpdate", "itoa", @@ -80,7 +80,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -91,7 +91,7 @@ checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", "cfg-if", - "http 0.2.11", + "http 0.2.12", "regex", "regex-lite", "serde", @@ -111,30 +111,28 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.2.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" dependencies = [ "actix-rt", "actix-service", "actix-utils", "futures-core", "futures-util", - "mio 0.8.11", - "num_cpus", - "socket2 0.4.9", + "mio", + "socket2", "tokio", "tracing", ] [[package]] name = "actix-service" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" dependencies = [ "futures-core", - "paste", "pin-project-lite", ] @@ -169,9 +167,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.9.0" +version = "4.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" +checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" dependencies = [ "actix-codec", "actix-http", @@ -183,13 +181,13 @@ dependencies = [ "actix-tls", "actix-utils", "actix-web-codegen", - "ahash 0.8.11", "bytes", "bytestring", "cfg-if", "cookie", - "derive_more 0.99.17", + "derive_more", "encoding_rs", + "foldhash", "futures-core", "futures-util", "impl-more", @@ -204,8 +202,9 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.10", + "socket2", "time", + "tracing", "url", ] @@ -218,7 +217,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -232,16 +231,16 @@ dependencies = [ "actix-service", "actix-utils", "actix-web", - "ahash 0.8.11", + "ahash 0.8.12", "arc-swap", "bytes", "bytestring", "csv", - "derive_more 2.0.1", + "derive_more", "form_urlencoded", "futures-core", "futures-util", - "http 0.2.11", + "http 0.2.12", "impl-more", "itertools 0.14.0", "local-channel", @@ -260,19 +259,13 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.20.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -302,20 +295,20 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "const-random", - "getrandom 0.2.15", + "getrandom 0.3.3", "once_cell", "version_check", "zerocopy", @@ -359,15 +352,16 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] @@ -379,30 +373,31 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "once_cell_polyfill", + "windows-sys 0.59.0", ] [[package]] @@ -437,9 +432,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "arroy" @@ -505,18 +500,18 @@ source = "git+https://github.com/meilisearch/async-openai?branch=better-error-ha dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -527,9 +522,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backoff" @@ -538,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ "futures-core", - "getrandom 0.2.15", + "getrandom 0.2.16", "instant", "pin-project-lite", "rand 0.8.5", @@ -547,17 +542,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.2", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -590,7 +585,7 @@ dependencies = [ "anyhow", "bumpalo", "bytes", - "convert_case 0.6.0", + "convert_case", "criterion", "csv", "flate2", @@ -635,7 +630,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.13.0", @@ -644,7 +639,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -681,9 +676,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -720,9 +715,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" dependencies = [ "borsh-derive", "cfg_aliases", @@ -730,16 +725,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", - "syn_derive", + "syn 2.0.101", ] [[package]] @@ -750,7 +744,7 @@ checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor 4.0.1", + "brotli-decompressor 4.0.3", ] [[package]] @@ -766,9 +760,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -786,9 +780,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -806,9 +800,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" dependencies = [ "allocator-api2", "serde", @@ -823,7 +817,7 @@ dependencies = [ "allocator-api2", "bitpacking", "bumpalo", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", "serde_json", ] @@ -863,15 +857,15 @@ dependencies = [ [[package]] name = "bytecount" -version = "0.6.3" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ "bytemuck_derive", ] @@ -884,7 +878,7 @@ checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -895,15 +889,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bytestring" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" dependencies = [ "bytes", ] @@ -929,55 +923,55 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ "serde", ] [[package]] name = "candle-core" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "855dfedff437d2681d68e1f34ae559d88b0dd84aa5a6b63f2c8e75ebdd875bbf" +checksum = "06ccf5ee3532e66868516d9b315f73aec9f34ea1a37ae98514534d458915dbf1" dependencies = [ "byteorder", "candle-kernels", "cudarc", - "gemm", - "half 2.4.1", + "gemm 0.17.1", + "half", "memmap2", "num-traits", "num_cpus", - "rand 0.8.5", + "rand 0.9.1", "rand_distr", "rayon", "safetensors", "thiserror 1.0.69", "ug", "ug-cuda", - "yoke", + "yoke 0.7.5", "zip 1.1.4", ] [[package]] name = "candle-kernels" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53343628fa470b7075c28c589b98735b4220b464e37ddbb8e117040e199f4787" +checksum = "a10885bd902fad1b8518ba2b22369aaed88a3d94e123533ad3ca73db33b1c8ca" dependencies = [ "bindgen_cuda", ] [[package]] name = "candle-nn" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd3c6b2ee0dfd64af12ae5b07e4b7c517898981cdaeffcb10b71d7dd5c8f359" +checksum = "be1160c3b63f47d40d91110a3e1e1e566ae38edddbbf492a60b40ffc3bc1ff38" dependencies = [ "candle-core", - "half 2.4.1", + "half", "num-traits", "rayon", "safetensors", @@ -987,16 +981,16 @@ dependencies = [ [[package]] name = "candle-transformers" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4270cc692c4a3df2051c2e8c3c4da3a189746af7ca3a547b99ecd335582b92e1" +checksum = "94a0900d49f8605e0e7e6693a1f560e6271279de98e5fa369e7abf3aac245020" dependencies = [ "byteorder", "candle-core", "candle-nn", "fancy-regex", "num-traits", - "rand 0.8.5", + "rand 0.9.1", "rayon", "serde", "serde_json", @@ -1006,18 +1000,18 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", "cargo-platform", @@ -1045,9 +1039,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "jobserver", "libc", @@ -1118,9 +1112,9 @@ dependencies = [ [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -1129,18 +1123,18 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", - "half 1.8.2", + "half", ] [[package]] @@ -1155,9 +1149,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -1166,9 +1160,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.24" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9560b07a799281c7e0958b9296854d6fafd4c5f31444a7e5bb1ad6dde5ccf1bd" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -1176,9 +1170,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.24" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874e0dd3eb68bf99058751ac9712f622e61e6f393a94f7128fa26e3f02f5c7cd" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -1188,14 +1182,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1218,9 +1212,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "concat-arrays" @@ -1235,15 +1229,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", + "once_cell", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.59.0", ] [[package]] @@ -1261,22 +1255,16 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "tiny-keccak", ] [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "convert_case" @@ -1298,16 +1286,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -1335,18 +1313,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -1413,9 +1391,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1432,24 +1410,24 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -1475,20 +1453,20 @@ dependencies = [ [[package]] name = "csv-core" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] [[package]] name = "cudarc" -version = "0.12.2" +version = "0.13.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd76de2aa3a7bdb9a65941ea5a3c688d941688f736a81b2fc5beb88747a7f25" +checksum = "486c221362668c63a1636cfa51463b09574433b39029326cff40864b3ba12b6e" dependencies = [ - "half 2.4.1", + "half", "libloading", ] @@ -1504,12 +1482,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] @@ -1528,16 +1506,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1553,13 +1531,13 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core 0.20.10", + "darling_core 0.20.11", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1603,9 +1581,9 @@ checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -1619,7 +1597,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1658,10 +1636,10 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling 0.20.10", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1681,20 +1659,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core 0.20.2", - "syn 2.0.87", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case 0.4.0", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", + "syn 2.0.101", ] [[package]] @@ -1714,7 +1679,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", "unicode-xid", ] @@ -1741,10 +1706,10 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aadef696fce456c704f10186def1bdc0a40e646c9f4f18cf091477acadb731d8" dependencies = [ - "convert_case 0.6.0", + "convert_case", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1808,15 +1773,9 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "doxygen-rs" version = "0.4.2" @@ -1833,7 +1792,7 @@ dependencies = [ "anyhow", "big_s", "flate2", - "http 1.2.0", + "http 1.3.1", "maplit", "meili-snap", "meilisearch-types", @@ -1861,19 +1820,28 @@ dependencies = [ ] [[package]] -name = "either" -version = "1.13.0" +name = "dyn-stack" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "490bd48eb68fffcfed519b4edbfd82c69cbe741d175b84f0e0cbe8c57cbe0bdd" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" dependencies = [ "serde", ] [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding" @@ -1959,14 +1927,14 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -1986,23 +1954,23 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2051,14 +2019,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -2078,7 +2046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", - "miniz_oxide 0.8.8", + "miniz_oxide", ] [[package]] @@ -2106,9 +2074,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" @@ -2187,7 +2155,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -2256,7 +2224,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce20bbb48248608ba4908b45fe36e17e40f56f8c6bb385ecf5d3c4a1e8b05a22" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "debugid", "fxhash", "serde", @@ -2270,17 +2238,37 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ab24cc62135b40090e31a76a9b2766a501979f3070fa27f689c27ec04377d32" dependencies = [ - "dyn-stack", - "gemm-c32", - "gemm-c64", - "gemm-common", - "gemm-f16", - "gemm-f32", - "gemm-f64", + "dyn-stack 0.10.0", + "gemm-c32 0.17.1", + "gemm-c64 0.17.1", + "gemm-common 0.17.1", + "gemm-f16 0.17.1", + "gemm-f32 0.17.1", + "gemm-f64 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-c32 0.18.2", + "gemm-c64 0.18.2", + "gemm-common 0.18.2", + "gemm-f16 0.18.2", + "gemm-f32 0.18.2", + "gemm-f64 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2290,12 +2278,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9c030d0b983d1e34a546b86e08f600c11696fde16199f971cd46c12e67512c0" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2305,12 +2308,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbb5f2e79fefb9693d18e1066a557b4546cd334b226beadc68b11a8f9431852a" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-c64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2321,17 +2339,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2e7ea062c987abcd8db95db917b4ffb4ecdfd0668471d8dc54734fdff2354e8" dependencies = [ "bytemuck", - "dyn-stack", - "half 2.4.1", + "dyn-stack 0.10.0", + "half", "num-complex", "num-traits", "once_cell", "paste", - "pulp", - "raw-cpuid", + "pulp 0.18.22", + "raw-cpuid 10.7.0", "rayon", "seq-macro", - "sysctl", + "sysctl 0.5.5", +] + +[[package]] +name = "gemm-common" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3" +dependencies = [ + "bytemuck", + "dyn-stack 0.13.0", + "half", + "libm", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp 0.21.5", + "raw-cpuid 11.5.0", + "rayon", + "seq-macro", + "sysctl 0.6.0", ] [[package]] @@ -2340,14 +2379,32 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ca4c06b9b11952071d317604acb332e924e817bd891bec8dfb494168c7cedd4" dependencies = [ - "dyn-stack", - "gemm-common", - "gemm-f32", - "half 2.4.1", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", + "gemm-f32 0.17.1", + "half", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "rayon", + "seq-macro", +] + +[[package]] +name = "gemm-f16" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "gemm-f32 0.18.2", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "rayon", "seq-macro", ] @@ -2358,12 +2415,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9a69f51aaefbd9cf12d18faf273d3e982d9d711f60775645ed5c8047b4ae113" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f32" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2373,12 +2445,27 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa397a48544fadf0b81ec8741e5c0fba0043008113f71f2034def1935645d2b0" dependencies = [ - "dyn-stack", - "gemm-common", + "dyn-stack 0.10.0", + "gemm-common 0.17.1", "num-complex", "num-traits", "paste", - "raw-cpuid", + "raw-cpuid 10.7.0", + "seq-macro", +] + +[[package]] +name = "gemm-f64" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd" +dependencies = [ + "dyn-stack 0.13.0", + "gemm-common 0.18.2", + "num-complex", + "num-traits", + "paste", + "raw-cpuid 11.5.0", "seq-macro", ] @@ -2400,9 +2487,9 @@ checksum = "36d244a08113319b5ebcabad2b8b7925732d15eec46d7e7ac3c11734f3b7a6ad" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", @@ -2413,31 +2500,31 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.13.3+wasi-0.2.2", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", "wasm-bindgen", - "windows-targets 0.52.6", ] [[package]] name = "gimli" -version = "0.27.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "git2" -version = "0.19.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "libgit2-sys", "log", @@ -2474,7 +2561,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.11", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -2484,16 +2571,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.2.0", + "http 1.3.1", "indexmap", "slab", "tokio", @@ -2503,21 +2590,15 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "bytemuck", "cfg-if", "crunchy", "num-traits", - "rand 0.8.5", + "rand 0.9.1", "rand_distr", ] @@ -2541,19 +2622,19 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.11", + "ahash 0.8.12", "allocator-api2", ] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -2571,12 +2652,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -2589,7 +2664,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a56c94661ddfb51aa9cdfbf102cfcc340aa69267f95ebccc4af08d7c530d393" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "byteorder", "heed-traits", "heed-types", @@ -2622,15 +2697,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -2644,7 +2713,7 @@ version = "0.3.2" source = "git+https://github.com/dureuill/hf-hub.git?branch=rust_tls#88d4f11cb9fa079f2912bacb96f5080b16825ce8" dependencies = [ "dirs", - "http 1.2.0", + "http 1.3.1", "indicatif", "log", "rand 0.8.5", @@ -2665,9 +2734,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -2676,9 +2745,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -2687,23 +2756,23 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http 1.3.1", ] [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", - "http 1.2.0", + "futures-core", + "http 1.3.1", "http-body", "pin-project-lite", ] @@ -2716,9 +2785,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -2729,8 +2798,8 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", - "http 1.2.0", + "h2 0.4.10", + "http 1.3.1", "http-body", "httparse", "httpdate", @@ -2743,21 +2812,20 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ - "futures-util", - "http 1.2.0", + "http 1.3.1", "hyper", "hyper-util", "rustls", - "rustls-native-certs 0.7.3", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 0.26.1", + "webpki-roots 1.0.0", ] [[package]] @@ -2771,14 +2839,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2", "tokio", "tower-service", "tracing", @@ -2786,21 +2854,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", - "yoke", + "potential_utf", + "yoke 0.8.0", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -2809,31 +2878,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -2841,67 +2890,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", - "yoke", + "yoke 0.8.0", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -2921,9 +2957,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -2955,7 +2991,7 @@ dependencies = [ "libflate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -2968,7 +3004,7 @@ dependencies = [ "bumpalo", "bumparaw-collections", "byte-unit", - "convert_case 0.6.0", + "convert_case", "crossbeam-channel", "csv", "derive_builder 0.20.2", @@ -2999,33 +3035,33 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "serde", ] [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", "unicode-width", + "web-time", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] @@ -3047,9 +3083,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -3083,15 +3119,21 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -3139,9 +3181,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jieba-macros" @@ -3154,9 +3196,9 @@ dependencies = [ [[package]] name = "jieba-rs" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1bcad6332969e4d48ee568d430e14ee6dea70740c2549d005d87677ebefb0c" +checksum = "b06096b4b61fb4bfdbf16c6a968ea2d6be1ac9617cf3db741c3b641e6c290a35" dependencies = [ "cedarwood", "fxhash", @@ -3169,10 +3211,11 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] @@ -3196,11 +3239,11 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.3.0" +version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "js-sys", "pem", "ring", @@ -3220,9 +3263,9 @@ dependencies = [ [[package]] name = "kstring" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" dependencies = [ "serde", "static_assertions", @@ -3251,9 +3294,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libflate" @@ -3275,15 +3318,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" dependencies = [ "core2", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "rle-decode-fast", ] [[package]] name = "libgit2-sys" -version = "0.17.0+1.8.1" +version = "0.18.1+1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" dependencies = [ "cc", "libc", @@ -3293,25 +3336,25 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] name = "libm" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.39" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" +checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" dependencies = [ "cc", "libc", @@ -3329,10 +3372,21 @@ dependencies = [ ] [[package]] -name = "libz-sys" -version = "1.1.15" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.9.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "libc", @@ -3471,17 +3525,22 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "liquid" -version = "0.26.9" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cdcc72b82748f47c2933c172313f5a9aea5b2c4eb3fa4c66b4ea55bb60bb4b1" +checksum = "2a494c3f9dad3cb7ed16f1c51812cbe4b29493d6c2e5cd1e2b87477263d9534d" dependencies = [ - "doc-comment", "liquid-core", "liquid-derive", "liquid-lib", @@ -3490,15 +3549,14 @@ dependencies = [ [[package]] name = "liquid-core" -version = "0.26.9" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2752e978ffc53670f3f2e8b3ef09f348d6f7b5474a3be3f8a5befe5382e4effb" +checksum = "fc623edee8a618b4543e8e8505584f4847a4e51b805db1af6d9af0a3395d0d57" dependencies = [ "anymap2", - "itertools 0.13.0", + "itertools 0.14.0", "kstring", "liquid-derive", - "num-traits", "pest", "pest_derive", "regex", @@ -3508,24 +3566,23 @@ dependencies = [ [[package]] name = "liquid-derive" -version = "0.26.8" +version = "0.26.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b51f1d220e3fa869e24cfd75915efe3164bd09bb11b3165db3f37f57bf673e3" +checksum = "de66c928222984aea59fcaed8ba627f388aaac3c1f57dcb05cc25495ef8faefe" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "liquid-lib" -version = "0.26.9" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b1a298d3d2287ee5b1e43840d885b8fdfc37d3f4e90d82aacfd04d021618da" +checksum = "9befeedd61f5995bc128c571db65300aeb50d62e4f0542c88282dbcb5f72372a" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "liquid-core", - "once_cell", "percent-encoding", "regex", "time", @@ -3534,9 +3591,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lmdb-master-sys" @@ -3551,38 +3608,31 @@ dependencies = [ [[package]] name = "local-channel" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" dependencies = [ "futures-core", "futures-sink", - "futures-util", "local-waker", ] [[package]] name = "local-waker" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.27" @@ -3595,9 +3645,15 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lzma-rs" version = "0.3.0" @@ -3621,9 +3677,9 @@ dependencies = [ [[package]] name = "macro_rules_attribute" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a82271f7bc033d84bbca59a3ce3e4159938cb08a9c3aebbe54d215131518a13" +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" dependencies = [ "macro_rules_attribute-proc_macro", "paste", @@ -3631,9 +3687,9 @@ dependencies = [ [[package]] name = "macro_rules_attribute-proc_macro" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dd856d451cc0da70e2ef2ce95a18e39a93b7558bedf10201ad28503f918568" +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" [[package]] name = "manifest-dir-macros" @@ -3644,7 +3700,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -3738,7 +3794,7 @@ dependencies = [ "serde_urlencoded", "sha-1", "sha2", - "siphasher 1.0.1", + "siphasher", "slice-group-by", "static-files", "sysinfo", @@ -3761,7 +3817,7 @@ dependencies = [ "uuid", "wiremock", "yaup", - "zip 2.3.0", + "zip 2.4.2", ] [[package]] @@ -3791,7 +3847,7 @@ dependencies = [ "anyhow", "bumpalo", "bumparaw-collections", - "convert_case 0.6.0", + "convert_case", "csv", "deserr", "either", @@ -3804,7 +3860,7 @@ dependencies = [ "memmap2", "milli", "roaring", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "serde-cs", "serde_json", @@ -3871,7 +3927,7 @@ dependencies = [ "candle-transformers", "charabia", "concat-arrays", - "convert_case 0.6.0", + "convert_case", "crossbeam-channel", "csv", "deserr", @@ -3884,7 +3940,7 @@ dependencies = [ "fxhash", "geoutils", "grenad", - "hashbrown 0.15.2", + "hashbrown 0.15.3", "heed", "hf-hub", "indexmap", @@ -3909,7 +3965,7 @@ dependencies = [ "rhai", "roaring", "rstar", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "serde_json", "slice-group-by", @@ -3932,9 +3988,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.43" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" +checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" dependencies = [ "libmimalloc-sys", ] @@ -3947,9 +4003,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -3961,15 +4017,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.8" @@ -3981,32 +4028,21 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "monostate" -version = "0.1.9" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f370ae88093ec6b11a710dec51321a61d420fafd1bad6e30d01bd9c920e8ee" +checksum = "aafe1be9d0c75642e3e50fedc7ecadf1ef1cbce6eb66462153fc44245343fbee" dependencies = [ "monostate-impl", "serde", @@ -4014,13 +4050,13 @@ dependencies = [ [[package]] name = "monostate-impl" -version = "0.1.9" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "371717c0a5543d6a800cac822eac735aa7d2d2fbb41002e9856a4089532dbdce" +checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -4164,33 +4200,33 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -4210,9 +4246,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.31.1" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -4230,12 +4266,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "onig" -version = "6.4.0" +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "onig" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "libc", "once_cell", "onig_sys", @@ -4243,9 +4285,9 @@ dependencies = [ [[package]] name = "onig_sys" -version = "69.8.1" +version = "69.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" dependencies = [ "cc", "pkg-config", @@ -4253,9 +4295,9 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "openssl-probe" @@ -4302,9 +4344,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -4312,22 +4354,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall", "smallvec", - "windows-targets 0.48.1", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "path-matchers" @@ -4356,11 +4398,11 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.3" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "serde", ] @@ -4380,19 +4422,20 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ - "thiserror 1.0.69", + "memchr", + "thiserror 2.0.12", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" dependencies = [ "pest", "pest_generator", @@ -4400,22 +4443,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "pest_meta" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ "once_cell", "pest", @@ -4424,9 +4467,9 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", "phf_shared", @@ -4434,9 +4477,9 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", @@ -4444,9 +4487,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand 0.8.5", @@ -4454,44 +4497,44 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher 0.3.11", + "siphasher", ] [[package]] name = "pin-project" -version = "1.1.4" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.4" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -4514,9 +4557,9 @@ checksum = "16f2611cd06a1ac239a0cea4521de9eb068a6ca110324ee00631aa68daa74fc0" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "platform-dirs" @@ -4529,9 +4572,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -4542,24 +4585,33 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "portable-atomic" -version = "1.5.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -4569,47 +4621,27 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ - "toml_edit 0.21.0", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -4620,10 +4652,10 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "hex", "procfs-core", - "rustix", + "rustix 0.38.44", ] [[package]] @@ -4632,7 +4664,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "hex", ] @@ -4695,9 +4727,9 @@ dependencies = [ [[package]] name = "pulp" -version = "0.18.9" +version = "0.18.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03457ac216146f43f921500bac4e892d5cd32b0479b929cbfc90f95cd6c599c2" +checksum = "a0a01a0dc67cf4558d279f0c25b0962bd08fc6dec0137699eae304103e882fe6" dependencies = [ "bytemuck", "libm", @@ -4706,61 +4738,89 @@ dependencies = [ ] [[package]] -name = "quinn" -version = "0.11.2" +name = "pulp" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "reborrow", + "version_check", +] + +[[package]] +name = "quinn" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "rustls", - "thiserror 1.0.69", + "socket2", + "thiserror 2.0.12", "tokio", "tracing", + "web-time", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "rand 0.8.5", + "getrandom 0.3.3", + "lru-slab", + "rand 0.9.1", "ring", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "rustls", + "rustls-pki-types", "slab", - "thiserror 1.0.69", + "thiserror 2.0.12", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "ee4e529991f949c5e25755532370b8af5d114acae52326361d68d47af64aa842" dependencies = [ + "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -4814,7 +4874,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -4823,17 +4883,17 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.3", ] [[package]] name = "rand_distr" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" dependencies = [ "num-traits", - "rand 0.8.5", + "rand 0.9.1", ] [[package]] @@ -4845,6 +4905,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "raw-cpuid" +version = "11.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +dependencies = [ + "bitflags 2.9.1", +] + [[package]] name = "rayon" version = "1.10.0" @@ -4893,30 +4962,21 @@ checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", - "redox_syscall 0.2.16", + "getrandom 0.2.16", + "libredox", "thiserror 1.0.69", ] @@ -4975,7 +5035,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "http-body-util", "hyper", @@ -4991,7 +5051,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-native-certs 0.8.1", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", @@ -5032,8 +5092,8 @@ name = "rhai" version = "1.20.0" source = "git+https://github.com/rhaiscript/rhai?rev=ef3df63121d27aacd838f366f2b83fd65f20a1e4#ef3df63121d27aacd838f366f2b83fd65f20a1e4" dependencies = [ - "ahash 0.8.11", - "bitflags 2.9.0", + "ahash 0.8.12", + "bitflags 2.9.1", "instant", "num-traits", "once_cell", @@ -5051,7 +5111,7 @@ source = "git+https://github.com/rhaiscript/rhai?rev=ef3df63121d27aacd838f366f2b dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5062,7 +5122,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -5070,9 +5130,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", @@ -5088,9 +5148,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.44" +version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", @@ -5105,9 +5165,9 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" [[package]] name = "roaring" -version = "0.10.10" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a652edd001c53df0b3f96a36a8dc93fce6866988efc16808235653c6bcac8bf2" +checksum = "19e8d2cfa184d94d0726d650a9f4a1be7f9b76ac9fdb954219878dc00c1c1e7b" dependencies = [ "bytemuck", "byteorder", @@ -5128,9 +5188,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.35.0" +version = "1.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" dependencies = [ "arrayvec", "borsh", @@ -5144,9 +5204,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -5156,37 +5216,41 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustix" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "semver", + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", ] [[package]] name = "rustix" -version = "0.38.41" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.52.0", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ "log", "once_cell", @@ -5197,19 +5261,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "rustls-pki-types", - "schannel", - "security-framework 2.11.1", -] - [[package]] name = "rustls-native-certs" version = "0.8.1" @@ -5219,7 +5270,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework", ] [[package]] @@ -5233,15 +5284,19 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "web-time", + "zeroize", +] [[package]] name = "rustls-webpki" -version = "0.102.8" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -5250,21 +5305,21 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "safetensors" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d980e6bfb34436fb0a81e42bc41af43f11805bbbca443e7f68e9faaabe669ed" +checksum = "44560c11236a6130a46ce36c836a62936dc81ebf8c36a37947423571be0e55b6" dependencies = [ "serde", "serde_json", @@ -5310,27 +5365,14 @@ dependencies = [ "zeroize", ] -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.1", + "bitflags 2.9.1", + "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", @@ -5348,9 +5390,9 @@ dependencies = [ [[package]] name = "segment" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd0f21b6eb87a45a7cce06075a29ccdb42658a6eb84bf40c8fc179479630609" +checksum = "971369158e31ad10bd73b558625f99de39554a2f00c2ff886a6796d950e69664" dependencies = [ "async-trait", "reqwest", @@ -5362,18 +5404,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] [[package]] name = "seq-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" @@ -5401,7 +5443,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5507,9 +5549,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -5533,9 +5575,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -5548,34 +5590,28 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "simdutf8" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "2.2.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple_asn1" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", - "thiserror 1.0.69", + "thiserror 2.0.12", "time", ] -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "siphasher" version = "1.0.1" @@ -5584,9 +5620,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -5609,9 +5645,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" dependencies = [ "serde", ] @@ -5628,16 +5664,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.10" @@ -5730,18 +5756,18 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -5756,32 +5782,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -5797,13 +5811,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5812,7 +5826,21 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags 2.9.1", "byteorder", "enum-as-inner", "libc", @@ -5862,15 +5890,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.2.15", + "getrandom 0.3.3", "once_cell", - "rustix", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -5885,9 +5912,9 @@ dependencies = [ [[package]] name = "thin-vec" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" +checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" dependencies = [ "serde", ] @@ -5918,7 +5945,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5929,7 +5956,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -5960,9 +5987,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -5977,15 +6004,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -6002,9 +6029,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -6022,9 +6049,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -6043,7 +6070,7 @@ dependencies = [ "aho-corasick", "derive_builder 0.12.0", "esaxx-rs", - "getrandom 0.2.15", + "getrandom 0.2.16", "itertools 0.12.1", "lazy_static", "log", @@ -6074,11 +6101,11 @@ dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.3", + "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.10", + "socket2", "tokio-macros", "windows-sys 0.52.0", ] @@ -6091,17 +6118,16 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] @@ -6131,49 +6157,45 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.22", + "toml_write", + "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "tower" version = "0.5.2" @@ -6191,14 +6213,14 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "bytes", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body", "iri-string", "pin-project-lite", @@ -6233,9 +6255,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9f5c1aca50ebebf074ee665b9f99f2e84906dcf6b993a0d0090edb835166d" +checksum = "2340b7722695166c7fc9b3e3cd1166e7c74fedb9075b8f0c74d3822d2e41caf5" dependencies = [ "actix-web", "mutually_exclusive_features", @@ -6252,7 +6274,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -6331,21 +6353,21 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uell" @@ -6358,48 +6380,52 @@ dependencies = [ [[package]] name = "ug" -version = "0.0.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4eef2ebfc18c67a6dbcacd9d8a4d85e0568cc58c82515552382312c2730ea13" +checksum = "03719c61a91b51541f076dfdba45caacf750b230cefaa4b32d6f5411c3f7f437" dependencies = [ - "half 2.4.1", + "gemm 0.18.2", + "half", + "libloading", + "memmap2", "num", + "num-traits", + "num_cpus", + "rayon", + "safetensors", "serde", - "serde_json", "thiserror 1.0.69", + "tracing", + "yoke 0.7.5", ] [[package]] name = "ug-cuda" -version = "0.0.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4dcab280ad0ef3957e153a82dcad608c954d02cf253b695322f502d1f8902e" +checksum = "50758486d7941f8b0a636ba7e29455c07071f41590beac1fd307ec893e8db69a" dependencies = [ "cudarc", - "half 2.4.1", + "half", "serde", - "serde_json", "thiserror 1.0.69", "ug", ] [[package]] name = "unescaper" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" +checksum = "c01d12e3a56a4432a8b436f293c25f4808bdf9e9f9f98f9260bba1f1bc5a1f26" dependencies = [ - "thiserror 1.0.69", + "thiserror 2.0.12", ] [[package]] name = "unicase" -version = "2.6.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-blocks" @@ -6409,9 +6435,9 @@ checksum = "6b12e05d9e06373163a9bb6bb8c263c261b396643a99445fe6b9811fd376581b" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -6433,15 +6459,15 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "unicode-xid" @@ -6483,7 +6509,7 @@ dependencies = [ "serde_json", "socks", "url", - "webpki-roots 0.26.1", + "webpki-roots 0.26.11", ] [[package]] @@ -6504,17 +6530,11 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8_iter" @@ -6524,9 +6544,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utoipa" @@ -6549,7 +6569,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.87", + "syn 2.0.101", "uuid", ] @@ -6567,19 +6587,21 @@ dependencies = [ [[package]] name = "uuid" -version = "1.11.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -6589,9 +6611,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "9.0.2" +version = "9.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f25fc8f8f05df455c7941e87f093ad22522a9ff33d7a027774815acf6f0639" +checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" dependencies = [ "anyhow", "derive_builder 0.20.2", @@ -6601,9 +6623,9 @@ dependencies = [ [[package]] name = "vergen-git2" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e63e069d8749fead1e3bab7a9d79e8fb90516b2ec66fc2243a798ecdc1a31d7" +checksum = "4f6ee511ec45098eabade8a0750e76eec671e7fb2d9360c563911336bea9cac1" dependencies = [ "anyhow", "derive_builder 0.20.2", @@ -6616,9 +6638,9 @@ dependencies = [ [[package]] name = "vergen-lib" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c767e6751c09fc85cde58722cf2f1007e80e4c8d5a4321fc90d83dc54ca147" +checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" dependencies = [ "anyhow", "derive_builder 0.20.2", @@ -6627,9 +6649,9 @@ dependencies = [ [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -6669,9 +6691,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -6698,18 +6720,19 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] @@ -6732,7 +6755,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6748,9 +6771,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -6761,9 +6784,19 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -6771,11 +6804,11 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.1" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "rustls-pki-types", + "webpki-roots 1.0.0", ] [[package]] @@ -6793,7 +6826,7 @@ version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "471d1c1645d361eb782a1650b1786a8fb58dd625e681a04c09f5ff7c8764a7b0" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", "once_cell", ] @@ -6815,11 +6848,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -6858,7 +6891,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -6869,7 +6902,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -6881,22 +6914,13 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.5", ] [[package]] @@ -6919,32 +6943,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -6956,7 +6965,7 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", @@ -6964,16 +6973,26 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" +name = "windows-targets" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" @@ -6982,16 +7001,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +name = "windows_aarch64_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" @@ -7000,16 +7019,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "windows_i686_gnu" -version = "0.42.2" +name = "windows_aarch64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" @@ -7017,6 +7036,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" @@ -7024,16 +7049,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "windows_i686_msvc" -version = "0.42.2" +name = "windows_i686_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" @@ -7042,16 +7067,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" +name = "windows_i686_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" @@ -7060,16 +7085,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +name = "windows_x86_64_gnu" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" @@ -7078,16 +7103,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +name = "windows_x86_64_gnullvm" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" @@ -7096,35 +7121,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winnow" -version = "0.5.40" +name = "windows_x86_64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.6.22" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] [[package]] name = "wiremock" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fff469918e7ca034884c7fd8f93fe27bacb7fcb599fd879df6c7b429a29b646" +checksum = "101681b74cd87b5899e87bcf5a64e83334dd313fcd3053ea72e6dba18928e301" dependencies = [ "assert-json-diff", "async-trait", "base64 0.22.1", "deadpool", "futures", - "http 1.2.0", + "http 1.3.1", "http-body-util", "hyper", "hyper-util", @@ -7139,24 +7161,18 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -7169,13 +7185,12 @@ dependencies = [ [[package]] name = "xattr" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "rustix 1.0.7", ] [[package]] @@ -7235,7 +7250,19 @@ checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", - "yoke-derive", + "yoke-derive 0.7.5", + "zerofrom", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.8.0", "zerofrom", ] @@ -7247,48 +7274,60 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] name = "zerofrom" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", "synstructure", ] @@ -7309,29 +7348,40 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke 0.8.0", + "zerofrom", ] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ - "yoke", + "yoke 0.8.0", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.101", ] [[package]] @@ -7351,9 +7401,9 @@ dependencies = [ [[package]] name = "zip" -version = "2.3.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e9a772a54b54236b9b744aaaf8d7be01b4d6e99725523cb82cb32d1c81b1d7" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" dependencies = [ "aes", "arbitrary", @@ -7364,7 +7414,7 @@ dependencies = [ "deflate64", "displaydoc", "flate2", - "getrandom 0.3.1", + "getrandom 0.3.3", "hmac", "indexmap", "lzma-rs", @@ -7381,41 +7431,39 @@ dependencies = [ [[package]] name = "zopfli" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] [[package]] name = "zstd" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.0" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", From 92d0d36ff63da54c77346cbfcf9c4d2c78eb138b Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Wed, 4 Jun 2025 10:25:35 +0200 Subject: [PATCH 179/292] Fix a bunch of snapshot tests --- .../after_registering_settings_task.snap | 2 +- .../settings_update_processed.snap | 2 +- .../Intel to kefir succeeds.snap | 2 +- .../import_vectors/Intel to kefir.snap | 2 +- .../import_vectors/adding Intel succeeds.snap | 2 +- .../import_vectors/after adding Intel.snap | 2 +- ...ter_registering_settings_task_vectors.snap | 2 +- .../settings_update_processed_vectors.snap | 2 +- .../after_adding_the_documents.snap | 2 +- .../after_adding_the_settings.snap | 2 +- .../after_removing_the_documents.snap | 2 +- .../registered_the_document_deletions.snap | 2 +- ...red_the_setting_and_document_addition.snap | 2 +- crates/meilisearch/tests/auth/api_keys.rs | 8 ++++---- crates/meilisearch/tests/dumps/mod.rs | 9 ++++++--- crates/meilisearch/tests/features/mod.rs | 20 ++++++++++++------- 16 files changed, 36 insertions(+), 27 deletions(-) diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/after_registering_settings_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/after_registering_settings_task.snap index d9d8b0724..c66a6b5b3 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/after_registering_settings_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/after_registering_settings_task.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, status: enqueued, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, status: enqueued, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: enqueued [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/settings_update_processed.snap b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/settings_update_processed.snap index 35eb3f162..b7faefa8a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/settings_update_processed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test.rs/test_settings_update/settings_update_processed.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"default": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(4), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: enqueued [] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir succeeds.snap b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir succeeds.snap index b90d5944a..c8955e2b6 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir succeeds.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir succeeds.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_embedders.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { received_documents: 1, indexed_documents: Some(1) }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: UpdateDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 1, allow_index_creation: true }} 2 {uid: 2, batch_uid: 2, status: succeeded, details: { received_documents: 1, indexed_documents: Some(1) }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: None, method: UpdateDocuments, content_file: 00000000-0000-0000-0000-000000000001, documents_count: 1, allow_index_creation: true }} ---------------------------------------------------------------------- diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir.snap b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir.snap index 58bf78290..23e43860f 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/Intel to kefir.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_embedders.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { received_documents: 1, indexed_documents: Some(1) }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: UpdateDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 1, allow_index_creation: true }} 2 {uid: 2, status: enqueued, details: { received_documents: 1, indexed_documents: None }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: None, method: UpdateDocuments, content_file: 00000000-0000-0000-0000-000000000001, documents_count: 1, allow_index_creation: true }} ---------------------------------------------------------------------- diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/adding Intel succeeds.snap b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/adding Intel succeeds.snap index 90ac17702..732527fa8 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/adding Intel succeeds.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/adding Intel succeeds.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_embedders.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { received_documents: 1, indexed_documents: Some(1) }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: UpdateDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 1, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after adding Intel.snap b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after adding Intel.snap index 10f87d389..5e01ffcdf 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after adding Intel.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after adding Intel.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_embedders.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, status: enqueued, details: { received_documents: 1, indexed_documents: None }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: UpdateDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 1, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after_registering_settings_task_vectors.snap b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after_registering_settings_task_vectors.snap index 35bd9dee9..1172d1118 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after_registering_settings_task_vectors.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/after_registering_settings_task_vectors.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_embedders.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, status: enqueued, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, status: enqueued, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: enqueued [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/settings_update_processed_vectors.snap b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/settings_update_processed_vectors.snap index ec8f387f0..3653eeb9a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/settings_update_processed_vectors.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_embedders.rs/import_vectors/settings_update_processed_vectors.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_embedders.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: NotSet, sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: Set({"A_fakerest": Set(EmbeddingSettings { source: Set(Rest), model: NotSet, revision: NotSet, pooling: NotSet, api_key: Set("My super secret"), dimensions: Set(384), binary_quantized: NotSet, document_template: NotSet, document_template_max_bytes: NotSet, url: Set("http://localhost:7777"), request: Set(String("{{text}}")), response: Set(String("{{embedding}}")), headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet }), "B_small_hf": Set(EmbeddingSettings { source: Set(HuggingFace), model: Set("sentence-transformers/all-MiniLM-L6-v2"), revision: Set("e4ce9877abf3edfe10b0d82785e83bdcb973e22e"), pooling: NotSet, api_key: NotSet, dimensions: NotSet, binary_quantized: NotSet, document_template: Set("{{doc.doggo}} the {{doc.breed}} best doggo"), document_template_max_bytes: NotSet, url: NotSet, request: NotSet, response: NotSet, headers: NotSet, search_embedder: NotSet, indexing_embedder: NotSet, distribution: NotSet })}), search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: enqueued [] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap index c5696578a..96d93de51 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_documents.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { received_documents: 3, indexed_documents: Some(3) }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: ReplaceDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 3, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap index edabbfa3c..76a77e5c0 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_adding_the_settings.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, status: enqueued, details: { received_documents: 3, indexed_documents: None }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: ReplaceDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 3, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap index aa86c61be..422bed51f 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/after_removing_the_documents.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { received_documents: 3, indexed_documents: Some(3) }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: ReplaceDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 3, allow_index_creation: true }} 2 {uid: 2, batch_uid: 2, status: succeeded, details: { received_document_ids: 1, deleted_documents: Some(1) }, kind: DocumentDeletion { index_uid: "doggos", documents_ids: ["1"] }} 3 {uid: 3, batch_uid: 2, status: failed, error: ResponseError { code: 200, message: "Index `doggos`: Invalid type for filter subexpression: expected: String, Array, found: true.", error_code: "invalid_document_filter", error_type: "invalid_request", error_link: "https://docs.meilisearch.com/errors#invalid_document_filter" }, details: { original_filter: true, deleted_documents: Some(0) }, kind: DocumentDeletionByFilter { index_uid: "doggos", filter_expr: Bool(true) }} diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap index 410c9c68e..d8996f82c 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_document_deletions.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { received_documents: 3, indexed_documents: Some(3) }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: ReplaceDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 3, allow_index_creation: true }} 2 {uid: 2, status: enqueued, details: { received_document_ids: 1, deleted_documents: None }, kind: DocumentDeletion { index_uid: "doggos", documents_ids: ["1"] }} 3 {uid: 3, status: enqueued, details: { original_filter: true, deleted_documents: None }, kind: DocumentDeletionByFilter { index_uid: "doggos", filter_expr: Bool(true) }} diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_setting_and_document_addition.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_setting_and_document_addition.snap index 0ba3ef598..e7b06eb31 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_setting_and_document_addition.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/fail_in_process_batch_for_document_deletion/registered_the_setting_and_document_addition.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, status: enqueued, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} +0 {uid: 0, status: enqueued, details: { settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData } }, kind: SettingsUpdate { index_uid: "doggos", new_settings: Settings { displayed_attributes: WildcardSetting(NotSet), searchable_attributes: WildcardSetting(NotSet), filterable_attributes: Set([Field("catto")]), sortable_attributes: NotSet, ranking_rules: NotSet, stop_words: NotSet, non_separator_tokens: NotSet, separator_tokens: NotSet, dictionary: NotSet, synonyms: NotSet, distinct_attribute: NotSet, proximity_precision: NotSet, typo_tolerance: NotSet, faceting: NotSet, pagination: NotSet, embedders: NotSet, search_cutoff_ms: NotSet, localized_attributes: NotSet, facet_search: NotSet, prefix_search: NotSet, chat: NotSet, _kind: PhantomData }, is_deletion: false, allow_index_creation: true }} 1 {uid: 1, status: enqueued, details: { received_documents: 3, indexed_documents: None }, kind: DocumentAdditionOrUpdate { index_uid: "doggos", primary_key: Some("id"), method: ReplaceDocuments, content_file: 00000000-0000-0000-0000-000000000000, documents_count: 3, allow_index_creation: true }} ---------------------------------------------------------------------- ### Status: diff --git a/crates/meilisearch/tests/auth/api_keys.rs b/crates/meilisearch/tests/auth/api_keys.rs index edfcd1c29..708feb2bb 100644 --- a/crates/meilisearch/tests/auth/api_keys.rs +++ b/crates/meilisearch/tests/auth/api_keys.rs @@ -421,7 +421,7 @@ async fn error_add_api_key_invalid_parameters_actions() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Unknown value `doc.add` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`", + "message": "Unknown value `doc.add` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`, `chatCompletion`, `chats.get`, `chatsSettings.*`, `chatsSettings.get`, `chatsSettings.update`, `chatsSettings.delete`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" @@ -826,8 +826,8 @@ async fn list_api_keys() { "key": "[ignored]", "uid": "[ignored]", "actions": [ - "search", - "chat.get" + "chatCompletion", + "search" ], "indexes": [ "*" @@ -869,7 +869,7 @@ async fn list_api_keys() { ], "offset": 0, "limit": 20, - "total": 3 + "total": 4 } "###); meili_snap::snapshot!(code, @"200 OK"); diff --git a/crates/meilisearch/tests/dumps/mod.rs b/crates/meilisearch/tests/dumps/mod.rs index 3ba3c20eb..3d3bc01db 100644 --- a/crates/meilisearch/tests/dumps/mod.rs +++ b/crates/meilisearch/tests/dumps/mod.rs @@ -2187,7 +2187,8 @@ async fn import_dump_v6_containing_experimental_features() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); @@ -2312,7 +2313,8 @@ async fn import_dump_v6_containing_batches_and_enqueued_tasks() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); @@ -2417,7 +2419,8 @@ async fn generate_and_import_dump_containing_vectors() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); diff --git a/crates/meilisearch/tests/features/mod.rs b/crates/meilisearch/tests/features/mod.rs index 34cd40e38..d0d457d3e 100644 --- a/crates/meilisearch/tests/features/mod.rs +++ b/crates/meilisearch/tests/features/mod.rs @@ -24,7 +24,8 @@ async fn experimental_features() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); @@ -39,7 +40,8 @@ async fn experimental_features() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); @@ -54,7 +56,8 @@ async fn experimental_features() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); @@ -70,7 +73,8 @@ async fn experimental_features() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); @@ -86,7 +90,8 @@ async fn experimental_features() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); } @@ -109,7 +114,8 @@ async fn experimental_feature_metrics() { "containsFilter": false, "network": false, "getTaskDocumentsRoute": false, - "compositeEmbedders": false + "compositeEmbedders": false, + "chatCompletions": false } "###); @@ -156,7 +162,7 @@ async fn errors() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "Unknown field `NotAFeature`: expected one of `metrics`, `logsRoute`, `editDocumentsByFunction`, `containsFilter`, `network`, `getTaskDocumentsRoute`, `compositeEmbedders`", + "message": "Unknown field `NotAFeature`: expected one of `metrics`, `logsRoute`, `editDocumentsByFunction`, `containsFilter`, `network`, `getTaskDocumentsRoute`, `compositeEmbedders`, `chatCompletions`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad_request" From c9efdf8c880d4a28aaa55070e5d538825a76c7d9 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 4 Jun 2025 13:00:47 +0300 Subject: [PATCH 180/292] Render details.dumpUid as [dump_uid] in Value's Display Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/mod.rs | 3 ++- crates/meilisearch/tests/tasks/mod.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/common/mod.rs b/crates/meilisearch/tests/common/mod.rs index 046519a0e..e5f910589 100644 --- a/crates/meilisearch/tests/common/mod.rs +++ b/crates/meilisearch/tests/common/mod.rs @@ -128,7 +128,8 @@ impl Display for Value { ".finishedAt" => "[date]", ".duration" => "[duration]", ".processingTimeMs" => "[duration]", - ".details.embedders.*.url" => "[url]" + ".details.embedders.*.url" => "[url]", + ".details.dumpUid" => "[dump_uid]", }) ) } diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index fb45223e6..c31e43883 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -1050,7 +1050,7 @@ async fn test_summarized_dump_creation() { "type": "dumpCreation", "canceledBy": null, "details": { - "dumpUid": "[dumpUid]" + "dumpUid": "[dump_uid]" }, "error": null, "duration": "[duration]", From 8b0c4291ae81d3616090914a3d02ae4c7c4e1c48 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 08:29:15 +0300 Subject: [PATCH 181/292] tests: Fater stats::mod IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/stats/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/meilisearch/tests/stats/mod.rs b/crates/meilisearch/tests/stats/mod.rs index aee626460..f448d893f 100644 --- a/crates/meilisearch/tests/stats/mod.rs +++ b/crates/meilisearch/tests/stats/mod.rs @@ -6,8 +6,8 @@ use crate::common::Server; use crate::json; #[actix_rt::test] -async fn get_settings_unexisting_index() { - let server = Server::new().await; +async fn get_version() { + let server = Server::new_shared(); let (response, code) = server.version().await; assert_eq!(code, 200); let version = response.as_object().unwrap(); @@ -18,7 +18,7 @@ async fn get_settings_unexisting_index() { #[actix_rt::test] async fn test_healthyness() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, status_code) = server.service.get("/health").await; assert_eq!(status_code, 200); @@ -27,8 +27,8 @@ async fn test_healthyness() { #[actix_rt::test] async fn stats() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (task, code) = index.create(Some("id")).await; assert_eq!(code, 202); @@ -55,7 +55,7 @@ async fn stats() { ]); let (response, code) = index.add_documents(documents, None).await; - assert_eq!(code, 202, "{}", response); + assert_eq!(code, 202, "{response}"); assert_eq!(response["taskUid"], 1); index.wait_task(response.uid()).await.succeeded(); @@ -78,8 +78,8 @@ async fn stats() { #[actix_rt::test] async fn add_remove_embeddings() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -216,8 +216,8 @@ async fn add_remove_embeddings() { #[actix_rt::test] async fn add_remove_embedded_documents() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); let (response, code) = index .update_settings(json!({ @@ -293,8 +293,8 @@ async fn add_remove_embedded_documents() { #[actix_rt::test] async fn update_embedder_settings() { - let server = Server::new().await; - let index = server.index("doggo"); + let server = Server::new_shared(); + let index = server.unique_index(); // 2 embedded documents for 3 embeddings in total // but no embedders are added in the settings yet so we expect 0 embedded documents for 0 embeddings in total From 930d5a09a842a453edb655759576c3ab195e6203 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 11:51:52 +0300 Subject: [PATCH 182/292] Use unique server + its own index for #stats() test Using a shared server will make this test fragile Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/stats/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/stats/mod.rs b/crates/meilisearch/tests/stats/mod.rs index f448d893f..f44812014 100644 --- a/crates/meilisearch/tests/stats/mod.rs +++ b/crates/meilisearch/tests/stats/mod.rs @@ -27,8 +27,8 @@ async fn test_healthyness() { #[actix_rt::test] async fn stats() { - let server = Server::new_shared(); - let index = server.unique_index(); + let server = Server::new().await; + let index = server.index("test"); let (task, code) = index.create(Some("id")).await; assert_eq!(code, 202); From 0557a4dd2f3eaac2867384c269c0c9a7e2f23759 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 14:28:30 +0300 Subject: [PATCH 183/292] Trigger build Signed-off-by: Martin Tzvetanov Grigorov From 61b0f50d4d8f0ece1db3a2efe0242869a6d62322 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 4 Jun 2025 13:37:42 +0300 Subject: [PATCH 184/292] Trigger build Signed-off-by: Martin Tzvetanov Grigorov From ef9fc6c85433706d4d961cd42e664262be36946c Mon Sep 17 00:00:00 2001 From: arthurgousset <46296830+arthurgousset@users.noreply.github.com> Date: Thu, 29 May 2025 23:24:01 +0100 Subject: [PATCH 185/292] fix(parse_query): cyrillic bug --- .../src/search/new/query_term/parse_query.rs | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/crates/milli/src/search/new/query_term/parse_query.rs b/crates/milli/src/search/new/query_term/parse_query.rs index e492363f8..58ddff206 100644 --- a/crates/milli/src/search/new/query_term/parse_query.rs +++ b/crates/milli/src/search/new/query_term/parse_query.rs @@ -202,11 +202,11 @@ pub fn number_of_typos_allowed<'ctx>( Ok(Box::new(move |word: &str| { if !authorize_typos - || word.len() < min_len_one_typo as usize + || word.chars().count() < min_len_one_typo as usize || exact_words.as_ref().is_some_and(|fst| fst.contains(word)) { 0 - } else if word.len() < min_len_two_typos as usize { + } else if word.chars().count() < min_len_two_typos as usize { 1 } else { 2 @@ -381,3 +381,63 @@ mod tests { Ok(()) } } + + #[test] + fn test_unicode_typo_tolerance_fixed() -> Result<()> { + let temp_index = temp_index_with_documents(); + let rtxn = temp_index.read_txn()?; + let ctx = SearchContext::new(&temp_index, &rtxn)?; + + let nbr_typos = number_of_typos_allowed(&ctx)?; + + // ASCII word "doggy" (5 chars, 5 bytes) + let ascii_word = "doggy"; + let ascii_typos = nbr_typos(ascii_word); + + // Cyrillic word "собак" (5 chars, 10 bytes) + let cyrillic_word = "собак"; + let cyrillic_typos = nbr_typos(cyrillic_word); + + eprintln!("ASCII '{}': char_count={}, typos={}", + ascii_word, ascii_word.chars().count(), ascii_typos); + eprintln!("Cyrillic '{}': char_count={}, typos={}", + cyrillic_word, cyrillic_word.chars().count(), cyrillic_typos); + + // Both words have 5 characters, so they should have the same typo tolerance + assert_eq!(ascii_typos, cyrillic_typos, + "Words with same character count should get same typo tolerance"); + + // With default settings (oneTypo=5, twoTypos=9), 5-char words should get 1 typo + assert_eq!(ascii_typos, 1, "5-character word should get 1 typo tolerance"); + assert_eq!(cyrillic_typos, 1, "5-character word should get 1 typo tolerance"); + + Ok(()) + } + + #[test] + fn test_various_unicode_scripts() -> Result<()> { + let temp_index = temp_index_with_documents(); + let rtxn = temp_index.read_txn()?; + let ctx = SearchContext::new(&temp_index, &rtxn)?; + + let nbr_typos = number_of_typos_allowed(&ctx)?; + + // Let's use 5-character words for consistent testing + let five_char_words = vec![ + ("doggy", "ASCII"), // 5 chars, 5 bytes + ("café!", "Accented"), // 5 chars, 7 bytes + ("собак", "Cyrillic"), // 5 chars, 10 bytes + ]; + + let expected_typos = 1; // With default settings, 5-char words get 1 typo + + for (word, script) in five_char_words { + let typos = nbr_typos(word); + eprintln!("{} '{}': chars={}, bytes={}, typos={}", + script, word, word.chars().count(), word.chars().count(), typos); + assert_eq!(typos, expected_typos, + "{} word '{}' should get {} typo(s)", script, word, expected_typos); + } + + Ok(()) + } From ab3d92d16392166f96f570874980f4b41f5cc0b3 Mon Sep 17 00:00:00 2001 From: arthurgousset <46296830+arthurgousset@users.noreply.github.com> Date: Thu, 29 May 2025 23:33:32 +0100 Subject: [PATCH 186/292] chore(parse_query): delete println and move test inside tests module --- crates/milli/src/search/new/query_term/parse_query.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/crates/milli/src/search/new/query_term/parse_query.rs b/crates/milli/src/search/new/query_term/parse_query.rs index 58ddff206..8a23a0e61 100644 --- a/crates/milli/src/search/new/query_term/parse_query.rs +++ b/crates/milli/src/search/new/query_term/parse_query.rs @@ -380,7 +380,6 @@ mod tests { Ok(()) } -} #[test] fn test_unicode_typo_tolerance_fixed() -> Result<()> { @@ -398,11 +397,6 @@ mod tests { let cyrillic_word = "собак"; let cyrillic_typos = nbr_typos(cyrillic_word); - eprintln!("ASCII '{}': char_count={}, typos={}", - ascii_word, ascii_word.chars().count(), ascii_typos); - eprintln!("Cyrillic '{}': char_count={}, typos={}", - cyrillic_word, cyrillic_word.chars().count(), cyrillic_typos); - // Both words have 5 characters, so they should have the same typo tolerance assert_eq!(ascii_typos, cyrillic_typos, "Words with same character count should get same typo tolerance"); @@ -433,11 +427,10 @@ mod tests { for (word, script) in five_char_words { let typos = nbr_typos(word); - eprintln!("{} '{}': chars={}, bytes={}, typos={}", - script, word, word.chars().count(), word.chars().count(), typos); assert_eq!(typos, expected_typos, "{} word '{}' should get {} typo(s)", script, word, expected_typos); } Ok(()) } +} From 263300b3a30c7c5eb56c422d08e9157ed5ac5a64 Mon Sep 17 00:00:00 2001 From: arthurgousset <46296830+arthurgousset@users.noreply.github.com> Date: Wed, 4 Jun 2025 10:56:02 +0100 Subject: [PATCH 187/292] style(milli): linting --- .../src/search/new/query_term/parse_query.rs | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/crates/milli/src/search/new/query_term/parse_query.rs b/crates/milli/src/search/new/query_term/parse_query.rs index 8a23a0e61..64bbb94c0 100644 --- a/crates/milli/src/search/new/query_term/parse_query.rs +++ b/crates/milli/src/search/new/query_term/parse_query.rs @@ -386,51 +386,56 @@ mod tests { let temp_index = temp_index_with_documents(); let rtxn = temp_index.read_txn()?; let ctx = SearchContext::new(&temp_index, &rtxn)?; - + let nbr_typos = number_of_typos_allowed(&ctx)?; - + // ASCII word "doggy" (5 chars, 5 bytes) let ascii_word = "doggy"; let ascii_typos = nbr_typos(ascii_word); - - // Cyrillic word "собак" (5 chars, 10 bytes) + + // Cyrillic word "собак" (5 chars, 10 bytes) let cyrillic_word = "собак"; let cyrillic_typos = nbr_typos(cyrillic_word); - + // Both words have 5 characters, so they should have the same typo tolerance - assert_eq!(ascii_typos, cyrillic_typos, - "Words with same character count should get same typo tolerance"); - + assert_eq!( + ascii_typos, cyrillic_typos, + "Words with same character count should get same typo tolerance" + ); + // With default settings (oneTypo=5, twoTypos=9), 5-char words should get 1 typo assert_eq!(ascii_typos, 1, "5-character word should get 1 typo tolerance"); assert_eq!(cyrillic_typos, 1, "5-character word should get 1 typo tolerance"); - + Ok(()) } - #[test] + #[test] fn test_various_unicode_scripts() -> Result<()> { let temp_index = temp_index_with_documents(); let rtxn = temp_index.read_txn()?; let ctx = SearchContext::new(&temp_index, &rtxn)?; - + let nbr_typos = number_of_typos_allowed(&ctx)?; - + // Let's use 5-character words for consistent testing let five_char_words = vec![ - ("doggy", "ASCII"), // 5 chars, 5 bytes - ("café!", "Accented"), // 5 chars, 7 bytes - ("собак", "Cyrillic"), // 5 chars, 10 bytes + ("doggy", "ASCII"), // 5 chars, 5 bytes + ("café!", "Accented"), // 5 chars, 7 bytes + ("собак", "Cyrillic"), // 5 chars, 10 bytes ]; - + let expected_typos = 1; // With default settings, 5-char words get 1 typo - + for (word, script) in five_char_words { let typos = nbr_typos(word); - assert_eq!(typos, expected_typos, - "{} word '{}' should get {} typo(s)", script, word, expected_typos); + assert_eq!( + typos, expected_typos, + "{} word '{}' should get {} typo(s)", + script, word, expected_typos + ); } - + Ok(()) } } From cf2bc03bed30674cff82c10a7159801bda14ab32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 4 Jun 2025 14:50:20 +0200 Subject: [PATCH 188/292] Fix the API key issue by reordering the default keys --- crates/meilisearch-auth/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch-auth/src/lib.rs b/crates/meilisearch-auth/src/lib.rs index a19ad7b8c..27d163192 100644 --- a/crates/meilisearch-auth/src/lib.rs +++ b/crates/meilisearch-auth/src/lib.rs @@ -350,9 +350,9 @@ pub struct IndexSearchRules { } fn generate_default_keys(store: &HeedAuthStore) -> Result<()> { + store.put_api_key(Key::default_chat())?; store.put_api_key(Key::default_admin())?; store.put_api_key(Key::default_search())?; - store.put_api_key(Key::default_chat())?; Ok(()) } From 27527849bb58ec8323e3394a138f4d515cd2d599 Mon Sep 17 00:00:00 2001 From: arthurgousset <46296830+arthurgousset@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:17:10 +0100 Subject: [PATCH 189/292] test(meilisearch/search/locales.rs): updates snapshot Used `cargo insta test` Reviewed with `cargo insta review` --- crates/meilisearch/tests/search/locales.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/tests/search/locales.rs b/crates/meilisearch/tests/search/locales.rs index b1c9b2bc2..8da7f585b 100644 --- a/crates/meilisearch/tests/search/locales.rs +++ b/crates/meilisearch/tests/search/locales.rs @@ -147,23 +147,20 @@ async fn simple_search() { .search( json!({"q": "進撃", "locales": ["jpn"], "attributesToRetrieve": ["id"]}), |response, code| { - snapshot!(response, @r###" + snapshot!(response, @r#" { "hits": [ { "id": 852 - }, - { - "id": 853 } ], "query": "進撃", "processingTimeMs": "[duration]", "limit": 20, "offset": 0, - "estimatedTotalHits": 2 + "estimatedTotalHits": 1 } - "###); + "#); snapshot!(code, @"200 OK"); }, ) From 666680bd87edace5dc6acc0c726ebd2fd9edf946 Mon Sep 17 00:00:00 2001 From: arthurgousset <46296830+arthurgousset@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:18:20 +0100 Subject: [PATCH 190/292] test(meilisearch/search/locales.rs): updates snapshot Used `cargo insta test` Reviewed with `cargo insta review` --- crates/meilisearch/tests/search/locales.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/tests/search/locales.rs b/crates/meilisearch/tests/search/locales.rs index 8da7f585b..f45554d41 100644 --- a/crates/meilisearch/tests/search/locales.rs +++ b/crates/meilisearch/tests/search/locales.rs @@ -169,23 +169,20 @@ async fn simple_search() { // chinese index .search(json!({"q": "进击", "attributesToRetrieve": ["id"]}), |response, code| { - snapshot!(response, @r###" + snapshot!(response, @r#" { "hits": [ { "id": 853 - }, - { - "id": 852 } ], "query": "进击", "processingTimeMs": "[duration]", "limit": 20, "offset": 0, - "estimatedTotalHits": 2 + "estimatedTotalHits": 1 } - "###); + "#); snapshot!(code, @"200 OK"); }) .await; From 258e6a115b9225b4e7d587786589bb9d9ff38097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 4 Jun 2025 15:29:55 +0200 Subject: [PATCH 191/292] Fix some other tests --- crates/meilisearch/tests/auth/api_keys.rs | 32 +++++++++++------------ crates/meilisearch/tests/auth/errors.rs | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/meilisearch/tests/auth/api_keys.rs b/crates/meilisearch/tests/auth/api_keys.rs index 708feb2bb..69a1ccb53 100644 --- a/crates/meilisearch/tests/auth/api_keys.rs +++ b/crates/meilisearch/tests/auth/api_keys.rs @@ -820,22 +820,6 @@ async fn list_api_keys() { "createdAt": "[ignored]", "updatedAt": "[ignored]" }, - { - "name": "Default Chat API Key", - "description": "Use it to chat and search from the frontend", - "key": "[ignored]", - "uid": "[ignored]", - "actions": [ - "chatCompletion", - "search" - ], - "indexes": [ - "*" - ], - "expiresAt": null, - "createdAt": "[ignored]", - "updatedAt": "[ignored]" - }, { "name": "Default Search API Key", "description": "Use it to search from the frontend", @@ -865,6 +849,22 @@ async fn list_api_keys() { "expiresAt": null, "createdAt": "[ignored]", "updatedAt": "[ignored]" + }, + { + "name": "Default Chat API Key", + "description": "Use it to chat and search from the frontend", + "key": "[ignored]", + "uid": "[ignored]", + "actions": [ + "chatCompletion", + "search" + ], + "indexes": [ + "*" + ], + "expiresAt": null, + "createdAt": "[ignored]", + "updatedAt": "[ignored]" } ], "offset": 0, diff --git a/crates/meilisearch/tests/auth/errors.rs b/crates/meilisearch/tests/auth/errors.rs index 0e8968ef0..6d4c17e19 100644 --- a/crates/meilisearch/tests/auth/errors.rs +++ b/crates/meilisearch/tests/auth/errors.rs @@ -93,7 +93,7 @@ async fn create_api_key_bad_actions() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Unknown value `doggo` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`", + "message": "Unknown value `doggo` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`, `chatCompletion`, `chats.get`, `chatsSettings.*`, `chatsSettings.get`, `chatsSettings.update`, `chatsSettings.delete`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" From 4dfb89168bbeb0326e38e06412cdc80dbdcea065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 4 Jun 2025 15:41:33 +0200 Subject: [PATCH 192/292] Add a test for the chat route --- crates/meilisearch/tests/settings/get_settings.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/meilisearch/tests/settings/get_settings.rs b/crates/meilisearch/tests/settings/get_settings.rs index 5c0f89ed3..e4c58cbcd 100644 --- a/crates/meilisearch/tests/settings/get_settings.rs +++ b/crates/meilisearch/tests/settings/get_settings.rs @@ -181,6 +181,16 @@ test_setting_routes!( update_verb: patch, default_value: {"enabled": true, "minWordSizeForTypos": {"oneTypo": 5, "twoTypos": 9}, "disableOnWords": [], "disableOnAttributes": [], "disableOnNumbers": false} }, + { + setting: chat, + update_verb: put, + default_value: { + "description": "", + "documentTemplate": "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}", + "documentTemplateMaxBytes": 400, + "searchParameters": {} + } + }, ); #[actix_rt::test] From 4d819ea636e5ebbb6406e0b48879555f74d2a877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 10:54:46 +0200 Subject: [PATCH 193/292] Initial working version for a prompt for email --- .../src/analytics/segment_analytics.rs | 1 + crates/meilisearch/src/main.rs | 30 ++++++++++++++++++- crates/meilisearch/src/option.rs | 10 +++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/analytics/segment_analytics.rs b/crates/meilisearch/src/analytics/segment_analytics.rs index ee8a9ee20..2c0121ffc 100644 --- a/crates/meilisearch/src/analytics/segment_analytics.rs +++ b/crates/meilisearch/src/analytics/segment_analytics.rs @@ -277,6 +277,7 @@ impl Infos { log_level, indexer_options, config_file_path, + contact_email: _, no_analytics: _, } = options; diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index b16dda097..cca704df5 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -21,6 +21,7 @@ use meilisearch::{ }; use meilisearch_auth::{generate_master_key, AuthController, MASTER_KEY_MIN_SIZE}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; +use tokio::io::{AsyncBufReadExt, BufReader}; use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt as _; use tracing_subscriber::Layer; @@ -89,10 +90,16 @@ async fn main() -> anyhow::Result<()> { } async fn try_main() -> anyhow::Result<()> { - let (opt, config_read_from) = Opt::try_build()?; + let (mut opt, config_read_from) = Opt::try_build()?; std::panic::set_hook(Box::new(on_panic)); + opt.contact_email = match opt.contact_email.as_ref().map(|email| email.as_deref()) { + Some(Some("false")) | None => prompt_for_contact_email().await.map(Some)?, + Some(Some(email)) => Some(Some(email.to_string())), + Some(None) => None, + }; + anyhow::ensure!( !(cfg!(windows) && opt.experimental_reduce_indexing_memory_usage), "The `experimental-reduce-indexing-memory-usage` flag is not supported on Windows" @@ -139,6 +146,27 @@ async fn try_main() -> anyhow::Result<()> { Ok(()) } +/// Prompt the user about the contact email for support and news. +/// It only displays the prompt if the input is an interactive terminal. +async fn prompt_for_contact_email() -> anyhow::Result> { + let stdin = tokio::io::stdin(); + + if !stdin.is_terminal() { + return Ok(None); + } + + println!("Would you mind providing your contact email for support and news?"); + println!("We will use it to contact you with news only."); + print!("contact email> "); + std::io::stdout().flush()?; + + let mut email = String::new(); + let mut stdin = BufReader::new(stdin); + let _ = stdin.read_line(&mut email).await?; + + Ok(Some(email.trim().to_string())) +} + async fn run_http( index_scheduler: Arc, auth_controller: Arc, diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index 6e06b161d..8b34ef8dd 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -66,6 +66,7 @@ const MEILI_EXPERIMENTAL_LIMIT_BATCHED_TASKS_TOTAL_SIZE: &str = const MEILI_EXPERIMENTAL_EMBEDDING_CACHE_ENTRIES: &str = "MEILI_EXPERIMENTAL_EMBEDDING_CACHE_ENTRIES"; const MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION: &str = "MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION"; +const MEILI_CONTACT_EMAIL: &str = "MEILI_CONTACT_EMAIL"; const DEFAULT_CONFIG_FILE_PATH: &str = "./config.toml"; const DEFAULT_DB_PATH: &str = "./data.ms"; const DEFAULT_HTTP_ADDR: &str = "localhost:7700"; @@ -347,6 +348,10 @@ pub struct Opt { #[serde(default)] pub log_level: LogLevel, + /// Sets the email address to contact for support and news. + #[clap(long, env = MEILI_CONTACT_EMAIL)] + pub contact_email: Option>, + /// Experimental contains filter feature. For more information, /// see: /// @@ -556,6 +561,7 @@ impl Opt { ignore_dump_if_db_exists: _, config_file_path: _, no_analytics, + contact_email, experimental_contains_filter, experimental_enable_metrics, experimental_search_queue_size, @@ -588,6 +594,10 @@ impl Opt { } export_to_env_if_not_present(MEILI_NO_ANALYTICS, no_analytics.to_string()); + export_to_env_if_not_present( + MEILI_CONTACT_EMAIL, + contact_email.flatten().unwrap_or_else(|| "false".to_string()), + ); export_to_env_if_not_present( MEILI_HTTP_PAYLOAD_SIZE_LIMIT, http_payload_size_limit.to_string(), From c7cb72a77a213c709ef09d3021b7c310621fb0c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 10:59:06 +0200 Subject: [PATCH 194/292] Make sure we skip empty prompted emails --- crates/meilisearch/src/main.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index cca704df5..87e3bf725 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -155,16 +155,21 @@ async fn prompt_for_contact_email() -> anyhow::Result> { return Ok(None); } - println!("Would you mind providing your contact email for support and news?"); - println!("We will use it to contact you with news only."); + println!("Would you mind providing your contact email for support and news? We will use it to contact you with news only."); + println!("Press enter to skip."); print!("contact email> "); std::io::stdout().flush()?; let mut email = String::new(); let mut stdin = BufReader::new(stdin); let _ = stdin.read_line(&mut email).await?; + let email = email.trim(); - Ok(Some(email.trim().to_string())) + if email.is_empty() { + Ok(None) + } else { + Ok(Some(email.to_string())) + } } async fn run_http( From 60796dfb14de6c452147037eb2eead899184c370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 11:02:30 +0200 Subject: [PATCH 195/292] Disable it by default in our Docker image --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 5a9a4691f..3d706e4c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,7 @@ LABEL org.opencontainers.image.source="https://github.com/meilisearch/meilisea ENV MEILI_HTTP_ADDR 0.0.0.0:7700 ENV MEILI_SERVER_PROVIDER docker +ENV MEILI_CONTACT_EMAIL RUN apk add -q --no-cache libgcc tini curl From 239851046dae4be5dce0e449cd01d0a6a835b708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 12:00:23 +0200 Subject: [PATCH 196/292] Send requests to Hubspot --- crates/meilisearch/src/main.rs | 61 +++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index 87e3bf725..e8bff7997 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -20,12 +20,17 @@ use meilisearch::{ LogStderrType, Opt, SubscriberForSecondLayer, }; use meilisearch_auth::{generate_master_key, AuthController, MASTER_KEY_MIN_SIZE}; +use meilisearch_types::versioning::{VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH}; +use serde_json::json; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use tokio::io::{AsyncBufReadExt, BufReader}; use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt as _; use tracing_subscriber::Layer; +const PORTAL_ID: &str = "25945010"; +const FORM_GUID: &str = "991e2a09-77c2-4428-9242-ebf26bfc6c64"; + #[cfg(not(windows))] #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -96,10 +101,20 @@ async fn try_main() -> anyhow::Result<()> { opt.contact_email = match opt.contact_email.as_ref().map(|email| email.as_deref()) { Some(Some("false")) | None => prompt_for_contact_email().await.map(Some)?, + Some(Some("")) | Some(None) => None, Some(Some(email)) => Some(Some(email.to_string())), - Some(None) => None, }; + if let Some(Some(email)) = opt.contact_email.as_ref() { + let email = email.clone(); + let _ = tokio::spawn(async move { + dbg!(&email); + if let Err(err) = register_contact_email(&email).await { + eprintln!("Failed to register email: {}", err); + } + }); + } + anyhow::ensure!( !(cfg!(windows) && opt.experimental_reduce_indexing_memory_usage), "The `experimental-reduce-indexing-memory-usage` flag is not supported on Windows" @@ -172,6 +187,50 @@ async fn prompt_for_contact_email() -> anyhow::Result> { } } +async fn register_contact_email(email: &str) -> anyhow::Result<()> { + let url = format!( + "https://api.hsforms.com/submissions/v3/integration/submit/{PORTAL_ID}/{FORM_GUID}" + ); + + let page_name = format!( + "Meilisearch terminal prompt v{}.{}.{}", + VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + ); + let response = reqwest::Client::new() + .post(url) + .json(&json!({ + "fields": [{ + "objectTypeId": "0-1", + "name": "email", + "value": email, + }], + "context": { + "pageName": page_name, + }, + "legalConsentOptions": { + "consent": { + "consentToProcess": true, + "text": "I agree to allow Meilisearch to store and process my personal data.", + "communications": [{ + "value": true, + "subscriptionTypeId": 999, + "text": "I agree to receive marketing communications from Meilisearch.", + }], + }, + }, + })) + .send() + .await?; + + let status = response.status(); + if status.is_client_error() || status.is_server_error() { + let response: serde_json::Value = response.json().await?; + eprintln!("Failed to register email: {response:?}"); + } + + Ok(()) +} + async fn run_http( index_scheduler: Arc, auth_controller: Arc, From 7b49c30d8c31bb3c7b71c18be5e3fb3c56dfedf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 12:02:30 +0200 Subject: [PATCH 197/292] Change the email prompting --- crates/meilisearch/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index e8bff7997..b5c9e0792 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -170,8 +170,8 @@ async fn prompt_for_contact_email() -> anyhow::Result> { return Ok(None); } - println!("Would you mind providing your contact email for support and news? We will use it to contact you with news only."); - println!("Press enter to skip."); + println!("Enter your email to receive occasional updates and tips about Meilisearch."); + println!("Leave blank to skip."); print!("contact email> "); std::io::stdout().flush()?; From 8bc8484e95d90d93a98f7c2b8f55c2ddd913ef0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 14:43:05 +0200 Subject: [PATCH 198/292] Skip the prompt when the email was once provided --- crates/meilisearch/src/main.rs | 41 +++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index b5c9e0792..4e2b25ffd 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -28,6 +28,7 @@ use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt as _; use tracing_subscriber::Layer; +const SKIP_EMAIL_FILENAME: &str = "skip-email"; const PORTAL_ID: &str = "25945010"; const FORM_GUID: &str = "991e2a09-77c2-4428-9242-ebf26bfc6c64"; @@ -99,22 +100,6 @@ async fn try_main() -> anyhow::Result<()> { std::panic::set_hook(Box::new(on_panic)); - opt.contact_email = match opt.contact_email.as_ref().map(|email| email.as_deref()) { - Some(Some("false")) | None => prompt_for_contact_email().await.map(Some)?, - Some(Some("")) | Some(None) => None, - Some(Some(email)) => Some(Some(email.to_string())), - }; - - if let Some(Some(email)) = opt.contact_email.as_ref() { - let email = email.clone(); - let _ = tokio::spawn(async move { - dbg!(&email); - if let Err(err) = register_contact_email(&email).await { - eprintln!("Failed to register email: {}", err); - } - }); - } - anyhow::ensure!( !(cfg!(windows) && opt.experimental_reduce_indexing_memory_usage), "The `experimental-reduce-indexing-memory-usage` flag is not supported on Windows" @@ -146,6 +131,30 @@ async fn try_main() -> anyhow::Result<()> { let (index_scheduler, auth_controller) = setup_meilisearch(&opt)?; + // We ask users their emails just after the data.ms is created + let skip_email_path = opt.db_path.join(SKIP_EMAIL_FILENAME); + opt.contact_email = match opt.contact_email.as_ref().map(|email| email.as_deref()) { + Some(Some("false")) | None if !skip_email_path.exists() => { + prompt_for_contact_email().await.map(Some)? + } + Some(Some(email)) if !skip_email_path.exists() => Some(Some(email.to_string())), + _otherwise => None, + }; + + if let Some(Some(email)) = opt.contact_email.as_ref() { + let email = email.clone(); + // We spawn a task to register the email and create the skip email + // file to avoid blocking the Meilisearch launch further. + let _ = tokio::spawn(async move { + if let Err(e) = tokio::fs::File::create_new(skip_email_path).await { + eprintln!("Failed to create skip email file: {e}"); + } + if let Err(err) = register_contact_email(&email).await { + eprintln!("Failed to register email: {}", err); + } + }); + } + let analytics = analytics::Analytics::new(&opt, index_scheduler.clone(), auth_controller.clone()).await; From 4fc24cb6912453d911f27032f3bbf9930a8054b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 14:43:46 +0200 Subject: [PATCH 199/292] Improve prompting again --- crates/meilisearch/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index 4e2b25ffd..022395397 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -179,9 +179,9 @@ async fn prompt_for_contact_email() -> anyhow::Result> { return Ok(None); } - println!("Enter your email to receive occasional updates and tips about Meilisearch."); - println!("Leave blank to skip."); - print!("contact email> "); + println!("Stay up to date! Get monthly updates about new features and tips to get the most out of Meilisearch."); + println!("You can use the `--contact-email` parameter to disable this prompt."); + print!("Enter your email or leave blank to skip> "); std::io::stdout().flush()?; let mut email = String::new(); From e575b5af7460acd6c2432621dfcec37de482c0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 14:49:08 +0200 Subject: [PATCH 200/292] Improve the contact email flag to make it friendly to disable prompt --- crates/meilisearch/src/option.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index 8b34ef8dd..2a5de7011 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -349,6 +349,9 @@ pub struct Opt { pub log_level: LogLevel, /// Sets the email address to contact for support and news. + /// + /// Use this option to disable contact email prompting. Leave + /// blank or without value to disable contact email prompting. #[clap(long, env = MEILI_CONTACT_EMAIL)] pub contact_email: Option>, From 204cf423b28a8bc24749544d4f303209e53b8e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 15:02:09 +0200 Subject: [PATCH 201/292] Fix Docker Image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3d706e4c7..937537728 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ LABEL org.opencontainers.image.source="https://github.com/meilisearch/meilisea ENV MEILI_HTTP_ADDR 0.0.0.0:7700 ENV MEILI_SERVER_PROVIDER docker -ENV MEILI_CONTACT_EMAIL +ENV MEILI_CONTACT_EMAIL "" RUN apk add -q --no-cache libgcc tini curl From 765e76857f4b08982671685e137f371e805ae6a9 Mon Sep 17 00:00:00 2001 From: Tamo Date: Thu, 5 Jun 2025 16:01:30 +0200 Subject: [PATCH 202/292] store the email file in the global config directory instead of the local data.ms so it's shared between all instances --- crates/meilisearch/src/analytics/mod.rs | 2 +- crates/meilisearch/src/main.rs | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/crates/meilisearch/src/analytics/mod.rs b/crates/meilisearch/src/analytics/mod.rs index bd14b0bfa..cd5641375 100644 --- a/crates/meilisearch/src/analytics/mod.rs +++ b/crates/meilisearch/src/analytics/mod.rs @@ -45,7 +45,7 @@ macro_rules! empty_analytics { /// `~/.config/Meilisearch` on *NIX or *BSD. /// `~/Library/ApplicationSupport` on macOS. /// `%APPDATA` (= `C:\Users%USERNAME%\AppData\Roaming`) on windows. -static MEILISEARCH_CONFIG_PATH: Lazy> = +pub static MEILISEARCH_CONFIG_PATH: Lazy> = Lazy::new(|| AppDirs::new(Some("Meilisearch"), false).map(|appdir| appdir.config_dir)); fn config_user_id_path(db_path: &Path) -> Option { diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index 022395397..84742f671 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -12,7 +12,7 @@ use actix_web::web::Data; use actix_web::HttpServer; use index_scheduler::IndexScheduler; use is_terminal::IsTerminal; -use meilisearch::analytics::Analytics; +use meilisearch::analytics::{Analytics, MEILISEARCH_CONFIG_PATH}; use meilisearch::option::LogMode; use meilisearch::search_queue::SearchQueue; use meilisearch::{ @@ -132,12 +132,14 @@ async fn try_main() -> anyhow::Result<()> { let (index_scheduler, auth_controller) = setup_meilisearch(&opt)?; // We ask users their emails just after the data.ms is created - let skip_email_path = opt.db_path.join(SKIP_EMAIL_FILENAME); + let skip_email_path = MEILISEARCH_CONFIG_PATH.as_ref().map(|conf| conf.join(SKIP_EMAIL_FILENAME)); + // If the config path does not exist, it means the user don't have a home directory + let skip_email = skip_email_path.as_ref().map_or(true, |path| path.exists()); opt.contact_email = match opt.contact_email.as_ref().map(|email| email.as_deref()) { - Some(Some("false")) | None if !skip_email_path.exists() => { + Some(Some("false")) | None if !skip_email => { prompt_for_contact_email().await.map(Some)? } - Some(Some(email)) if !skip_email_path.exists() => Some(Some(email.to_string())), + Some(Some(email)) if !skip_email => Some(Some(email.to_string())), _otherwise => None, }; @@ -146,8 +148,14 @@ async fn try_main() -> anyhow::Result<()> { // We spawn a task to register the email and create the skip email // file to avoid blocking the Meilisearch launch further. let _ = tokio::spawn(async move { - if let Err(e) = tokio::fs::File::create_new(skip_email_path).await { - eprintln!("Failed to create skip email file: {e}"); + if let Some(skip_email_path) = skip_email_path { + // If the analytics are disabled the directory might not exist at all + if let Err(e) = tokio::fs::create_dir_all(skip_email_path.parent().unwrap()).await { + eprintln!("Failed to create skip email file: {e}"); + } + if let Err(e) = tokio::fs::File::create_new(skip_email_path).await { + eprintln!("Failed to create skip email file: {e}"); + } } if let Err(err) = register_contact_email(&email).await { eprintln!("Failed to register email: {}", err); From 38b317857d7a97610e9c63a9ec1ac94ed5b81275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 18:19:19 +0200 Subject: [PATCH 203/292] Improve the wording again --- crates/meilisearch/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index 84742f671..cf2379d11 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -187,8 +187,8 @@ async fn prompt_for_contact_email() -> anyhow::Result> { return Ok(None); } - println!("Stay up to date! Get monthly updates about new features and tips to get the most out of Meilisearch."); - println!("You can use the `--contact-email` parameter to disable this prompt."); + println!("Get monthly updates about new features and tips to get the most out of Meilisearch."); + println!("Use the --contact-email option to disable this prompt."); print!("Enter your email or leave blank to skip> "); std::io::stdout().flush()?; From 90d96ee4159f2f380dc8a54baa8446af7f04511b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 5 Jun 2025 18:21:55 +0200 Subject: [PATCH 204/292] Make clippy happy --- crates/meilisearch/src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index cf2379d11..13f76732a 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -132,13 +132,12 @@ async fn try_main() -> anyhow::Result<()> { let (index_scheduler, auth_controller) = setup_meilisearch(&opt)?; // We ask users their emails just after the data.ms is created - let skip_email_path = MEILISEARCH_CONFIG_PATH.as_ref().map(|conf| conf.join(SKIP_EMAIL_FILENAME)); + let skip_email_path = + MEILISEARCH_CONFIG_PATH.as_ref().map(|conf| conf.join(SKIP_EMAIL_FILENAME)); // If the config path does not exist, it means the user don't have a home directory - let skip_email = skip_email_path.as_ref().map_or(true, |path| path.exists()); + let skip_email = skip_email_path.as_ref().is_none_or(|path| path.exists()); opt.contact_email = match opt.contact_email.as_ref().map(|email| email.as_deref()) { - Some(Some("false")) | None if !skip_email => { - prompt_for_contact_email().await.map(Some)? - } + Some(Some("false")) | None if !skip_email => prompt_for_contact_email().await.map(Some)?, Some(Some(email)) if !skip_email => Some(Some(email.to_string())), _otherwise => None, }; @@ -147,7 +146,7 @@ async fn try_main() -> anyhow::Result<()> { let email = email.clone(); // We spawn a task to register the email and create the skip email // file to avoid blocking the Meilisearch launch further. - let _ = tokio::spawn(async move { + let handle = tokio::spawn(async move { if let Some(skip_email_path) = skip_email_path { // If the analytics are disabled the directory might not exist at all if let Err(e) = tokio::fs::create_dir_all(skip_email_path.parent().unwrap()).await { @@ -161,6 +160,7 @@ async fn try_main() -> anyhow::Result<()> { eprintln!("Failed to register email: {}", err); } }); + drop(handle); } let analytics = From 70670c3be4b83d77db58b5f82583217b5ebbc9e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Fri, 6 Jun 2025 12:08:37 +0200 Subject: [PATCH 205/292] Introduce the support of Azure, Gemini, vLLM --- Cargo.lock | 1 + crates/meilisearch-types/src/error.rs | 4 + crates/meilisearch-types/src/features.rs | 127 ++++++++++++++++++ crates/meilisearch/Cargo.toml | 1 + .../src/routes/chats/chat_completions.rs | 22 +-- crates/meilisearch/src/routes/chats/config.rs | 87 ++++++++++++ crates/meilisearch/src/routes/chats/mod.rs | 1 + .../meilisearch/src/routes/chats/settings.rs | 36 +++++ 8 files changed, 261 insertions(+), 18 deletions(-) create mode 100644 crates/meilisearch/src/routes/chats/config.rs diff --git a/Cargo.lock b/Cargo.lock index 4e897e580..8a3942d5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3788,6 +3788,7 @@ dependencies = [ "rustls", "rustls-pemfile", "rustls-pki-types", + "secrecy", "segment", "serde", "serde_json", diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 11bad977d..27f7580e2 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -391,6 +391,10 @@ EditDocumentsByFunctionError , InvalidRequest , BAD_REQU InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ; // Experimental features - Chat Completions ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND ; +InvalidChatCompletionOrgId , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionProjectId , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionApiVersion , InvalidRequest , BAD_REQUEST ; +InvalidChatCompletionDeploymentId , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionSource , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionBaseApi , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionApiKey , InvalidRequest , BAD_REQUEST ; diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 95706fb46..9bcd58347 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -51,6 +51,14 @@ pub struct Network { pub struct ChatCompletionSettings { pub source: ChatCompletionSource, #[serde(default)] + pub org_id: Option, + #[serde(default)] + pub project_id: Option, + #[serde(default)] + pub api_version: Option, + #[serde(default)] + pub deployment_id: Option, + #[serde(default)] pub base_api: Option, #[serde(default)] pub api_key: Option, @@ -88,6 +96,43 @@ impl ChatCompletionSettings { pub enum ChatCompletionSource { #[default] OpenAi, + AzureOpenAi, + Mistral, + Gemini, + VLlm, +} + +impl ChatCompletionSource { + pub fn system_role(&self, model: &str) -> &'static str { + match self { + ChatCompletionSource::OpenAi if Self::old_openai_model(model) => "system", + ChatCompletionSource::OpenAi => "developer", + ChatCompletionSource::AzureOpenAi if Self::old_openai_model(model) => "system", + ChatCompletionSource::AzureOpenAi => "developer", + ChatCompletionSource::Mistral => "system", + ChatCompletionSource::Gemini => "system", + ChatCompletionSource::VLlm => "system", + } + } + + /// Returns true if the model is an old OpenAI model. + /// + /// Old OpenAI models use the system role while new ones use the developer role. + fn old_openai_model(model: &str) -> bool { + ["gpt-3.5", "gpt-4", "gpt-4.1", "gpt-4.5", "gpt-4o", "chatgpt-4o"].iter().any(|old| { + model.starts_with(old) && model.chars().nth(old.len()).is_none_or(|last| last == '-') + }) + } + + pub fn base_url(&self) -> Option<&'static str> { + use ChatCompletionSource::*; + match self { + OpenAi => Some("https://api.openai.com/v1/"), + Mistral => Some("https://api.mistral.ai/v1/"), + Gemini => Some("https://generativelanguage.googleapis.com/v1beta/openai/"), + AzureOpenAi | VLlm => None, + } + } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] @@ -111,3 +156,85 @@ impl Default for ChatCompletionPrompts { } } } + +#[cfg(test)] +mod tests { + use super::*; + + const ALL_OPENAI_MODELS_OLDINESS: &[(&str, bool)] = &[ + ("gpt-4-0613", true), + ("gpt-4", true), + ("gpt-3.5-turbo", true), + ("gpt-4o-audio-preview-2025-06-03", true), + ("gpt-4.1-nano", true), + ("gpt-4o-realtime-preview-2025-06-03", true), + ("gpt-3.5-turbo-instruct", true), + ("gpt-3.5-turbo-instruct-0914", true), + ("gpt-4-1106-preview", true), + ("gpt-3.5-turbo-1106", true), + ("gpt-4-0125-preview", true), + ("gpt-4-turbo-preview", true), + ("gpt-3.5-turbo-0125", true), + ("gpt-4-turbo", true), + ("gpt-4-turbo-2024-04-09", true), + ("gpt-4o", true), + ("gpt-4o-2024-05-13", true), + ("gpt-4o-mini-2024-07-18", true), + ("gpt-4o-mini", true), + ("gpt-4o-2024-08-06", true), + ("chatgpt-4o-latest", true), + ("gpt-4o-realtime-preview-2024-10-01", true), + ("gpt-4o-audio-preview-2024-10-01", true), + ("gpt-4o-audio-preview", true), + ("gpt-4o-realtime-preview", true), + ("gpt-4o-realtime-preview-2024-12-17", true), + ("gpt-4o-audio-preview-2024-12-17", true), + ("gpt-4o-mini-realtime-preview-2024-12-17", true), + ("gpt-4o-mini-audio-preview-2024-12-17", true), + ("gpt-4o-mini-realtime-preview", true), + ("gpt-4o-mini-audio-preview", true), + ("gpt-4o-2024-11-20", true), + ("gpt-4.5-preview", true), + ("gpt-4.5-preview-2025-02-27", true), + ("gpt-4o-search-preview-2025-03-11", true), + ("gpt-4o-search-preview", true), + ("gpt-4o-mini-search-preview-2025-03-11", true), + ("gpt-4o-mini-search-preview", true), + ("gpt-4o-transcribe", true), + ("gpt-4o-mini-transcribe", true), + ("gpt-4o-mini-tts", true), + ("gpt-4.1-2025-04-14", true), + ("gpt-4.1", true), + ("gpt-4.1-mini-2025-04-14", true), + ("gpt-4.1-mini", true), + ("gpt-4.1-nano-2025-04-14", true), + ("gpt-3.5-turbo-16k", true), + // + // new models + ("o1-preview-2024-09-12", false), + ("o1-preview", false), + ("o1-mini-2024-09-12", false), + ("o1-mini", false), + ("o1-2024-12-17", false), + ("o1", false), + ("o3-mini", false), + ("o3-mini-2025-01-31", false), + ("o1-pro-2025-03-19", false), + ("o1-pro", false), + ("o3-2025-04-16", false), + ("o4-mini-2025-04-16", false), + ("o3", false), + ("o4-mini", false), + ]; + + #[test] + fn old_openai_models() { + for (name, is_old) in ALL_OPENAI_MODELS_OLDINESS.iter().copied() { + assert_eq!( + ChatCompletionSource::old_openai_model(name), + is_old, + "Model {name} is not considered old" + ); + } + } +} diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index deea9f803..a40b63a24 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -114,6 +114,7 @@ utoipa = { version = "5.3.1", features = [ ] } utoipa-scalar = { version = "0.3.0", optional = true, features = ["actix-web"] } async-openai = { git = "https://github.com/meilisearch/async-openai", branch = "better-error-handling" } +secrecy = "0.10.3" actix-web-lab = { version = "0.24.1", default-features = false } [dev-dependencies] diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 6f6b50d1c..f588541fa 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -7,7 +7,6 @@ use std::time::Duration; use actix_web::web::{self, Data}; use actix_web::{Either, HttpRequest, HttpResponse, Responder}; use actix_web_lab::sse::{Event, Sse}; -use async_openai::config::{Config, OpenAIConfig}; use async_openai::types::{ ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, @@ -35,6 +34,7 @@ use serde_json::json; use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; +use super::config::Config; use super::errors::StreamErrorEvent; use super::utils::format_documents; use super::{ @@ -312,15 +312,8 @@ async fn non_streamed_chat( } }; - let mut config = OpenAIConfig::default(); - if let Some(api_key) = chat_settings.api_key.as_ref() { - config = config.with_api_key(api_key); - } - if let Some(base_api) = chat_settings.base_api.as_ref() { - config = config.with_api_base(base_api); - } + let config = Config::new(&chat_settings); let client = Client::with_config(config); - let auth_token = extract_token_from_request(&req)?.unwrap(); // TODO do function support later let _function_support = @@ -413,14 +406,7 @@ async fn streamed_chat( }; drop(rtxn); - let mut config = OpenAIConfig::default(); - if let Some(api_key) = chat_settings.api_key.as_ref() { - config = config.with_api_key(api_key); - } - if let Some(base_api) = chat_settings.base_api.as_ref() { - config = config.with_api_base(base_api); - } - + let config = Config::new(&chat_settings); let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); let function_support = setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; @@ -465,7 +451,7 @@ async fn streamed_chat( /// Updates the chat completion with the new messages, streams the LLM tokens, /// and report progress and errors. #[allow(clippy::too_many_arguments)] -async fn run_conversation( +async fn run_conversation( index_scheduler: &GuardedData< ActionPolicy<{ actions::CHAT_COMPLETIONS }>, Data, diff --git a/crates/meilisearch/src/routes/chats/config.rs b/crates/meilisearch/src/routes/chats/config.rs new file mode 100644 index 000000000..9babbd8c9 --- /dev/null +++ b/crates/meilisearch/src/routes/chats/config.rs @@ -0,0 +1,87 @@ +use async_openai::config::{AzureConfig, OpenAIConfig}; +use meilisearch_types::features::ChatCompletionSettings as DbChatSettings; +use reqwest::header::HeaderMap; +use secrecy::SecretString; + +#[derive(Debug, Clone)] +pub enum Config { + OpenAiCompatible(OpenAIConfig), + AzureOpenAiCompatible(AzureConfig), +} + +impl Config { + pub fn new(chat_settings: &DbChatSettings) -> Self { + use meilisearch_types::features::ChatCompletionSource::*; + match chat_settings.source { + OpenAi | Mistral | Gemini | VLlm => { + let mut config = OpenAIConfig::default(); + if let Some(org_id) = chat_settings.org_id.as_ref() { + config = config.with_org_id(org_id); + } + if let Some(project_id) = chat_settings.project_id.as_ref() { + config = config.with_project_id(project_id); + } + if let Some(api_key) = chat_settings.api_key.as_ref() { + config = config.with_api_key(api_key); + } + if let Some(base_api) = chat_settings.base_api.as_ref() { + config = config.with_api_base(base_api); + } + Self::OpenAiCompatible(config) + } + AzureOpenAi => { + let mut config = AzureConfig::default(); + if let Some(version) = chat_settings.api_version.as_ref() { + config = config.with_api_version(version); + } + if let Some(deployment_id) = chat_settings.deployment_id.as_ref() { + config = config.with_deployment_id(deployment_id); + } + if let Some(api_key) = chat_settings.api_key.as_ref() { + config = config.with_api_key(api_key); + } + if let Some(base_api) = chat_settings.base_api.as_ref() { + config = config.with_api_base(base_api); + } + Self::AzureOpenAiCompatible(config) + } + } + } +} + +impl async_openai::config::Config for Config { + fn headers(&self) -> HeaderMap { + match self { + Config::OpenAiCompatible(config) => config.headers(), + Config::AzureOpenAiCompatible(config) => config.headers(), + } + } + + fn url(&self, path: &str) -> String { + match self { + Config::OpenAiCompatible(config) => config.url(path), + Config::AzureOpenAiCompatible(config) => config.url(path), + } + } + + fn query(&self) -> Vec<(&str, &str)> { + match self { + Config::OpenAiCompatible(config) => config.query(), + Config::AzureOpenAiCompatible(config) => config.query(), + } + } + + fn api_base(&self) -> &str { + match self { + Config::OpenAiCompatible(config) => config.api_base(), + Config::AzureOpenAiCompatible(config) => config.api_base(), + } + } + + fn api_key(&self) -> &SecretString { + match self { + Config::OpenAiCompatible(config) => config.api_key(), + Config::AzureOpenAiCompatible(config) => config.api_key(), + } + } +} diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 35afd69c0..ddaf4d80d 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -18,6 +18,7 @@ use crate::extractors::authentication::GuardedData; use crate::routes::PAGINATION_DEFAULT_LIMIT; pub mod chat_completions; +mod config; mod errors; pub mod settings; mod utils; diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 0bb25f30d..c7b89d5bb 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -109,6 +109,26 @@ async fn patch_settings( Setting::Reset => DbChatCompletionSource::default(), Setting::NotSet => old_settings.source, }, + org_id: match new.org_id { + Setting::Set(new_org_id) => Some(new_org_id), + Setting::Reset => None, + Setting::NotSet => old_settings.org_id, + }, + project_id: match new.project_id { + Setting::Set(new_project_id) => Some(new_project_id), + Setting::Reset => None, + Setting::NotSet => old_settings.project_id, + }, + api_version: match new.api_version { + Setting::Set(new_api_version) => Some(new_api_version), + Setting::Reset => None, + Setting::NotSet => old_settings.api_version, + }, + deployment_id: match new.deployment_id { + Setting::Set(new_deployment_id) => Some(new_deployment_id), + Setting::Reset => None, + Setting::NotSet => old_settings.deployment_id, + }, base_api: match new.base_api { Setting::Set(new_base_api) => Some(new_base_api), Setting::Reset => None, @@ -171,6 +191,22 @@ pub struct GlobalChatSettings { #[schema(value_type = Option)] pub source: Setting, #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("dcba4321..."))] + pub org_id: Setting, + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("4321dcba..."))] + pub project_id: Setting, + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("2024-02-01"))] + pub api_version: Setting, + #[serde(default)] + #[deserr(default, error = DeserrJsonError)] + #[schema(value_type = Option, example = json!("1234abcd..."))] + pub deployment_id: Setting, + #[serde(default)] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!("https://api.mistral.ai/v1"))] pub base_api: Setting, From 717a026fddb94dcd0c48bf853fc525bb95030bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Fri, 6 Jun 2025 12:32:40 +0200 Subject: [PATCH 206/292] Make sure to use the system prompt --- crates/meilisearch-types/src/features.rs | 24 ++++++---- .../src/routes/chats/chat_completions.rs | 47 ++++++++++++++----- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 9bcd58347..210a0f0f9 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -102,16 +102,24 @@ pub enum ChatCompletionSource { VLlm, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SystemRole { + System, + Developer, +} + impl ChatCompletionSource { - pub fn system_role(&self, model: &str) -> &'static str { + pub fn system_role(&self, model: &str) -> SystemRole { + use ChatCompletionSource::*; + use SystemRole::*; match self { - ChatCompletionSource::OpenAi if Self::old_openai_model(model) => "system", - ChatCompletionSource::OpenAi => "developer", - ChatCompletionSource::AzureOpenAi if Self::old_openai_model(model) => "system", - ChatCompletionSource::AzureOpenAi => "developer", - ChatCompletionSource::Mistral => "system", - ChatCompletionSource::Gemini => "system", - ChatCompletionSource::VLlm => "system", + OpenAi if Self::old_openai_model(model) => System, + OpenAi => Developer, + AzureOpenAi if Self::old_openai_model(model) => System, + AzureOpenAi => Developer, + Mistral => System, + Gemini => System, + VLlm => System, } } diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index f588541fa..f4e42cae3 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -9,7 +9,8 @@ use actix_web::{Either, HttpRequest, HttpResponse, Responder}; use actix_web_lab::sse::{Event, Sse}; use async_openai::types::{ ChatCompletionMessageToolCall, ChatCompletionMessageToolCallChunk, - ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, + ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestDeveloperMessage, + ChatCompletionRequestDeveloperMessageContent, ChatCompletionRequestMessage, ChatCompletionRequestSystemMessage, ChatCompletionRequestSystemMessageContent, ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, ChatCompletionStreamResponseDelta, ChatCompletionToolArgs, ChatCompletionToolType, @@ -24,6 +25,7 @@ use meilisearch_auth::AuthController; use meilisearch_types::error::{Code, ResponseError}; use meilisearch_types::features::{ ChatCompletionPrompts as DbChatCompletionPrompts, ChatCompletionSettings as DbChatSettings, + SystemRole, }; use meilisearch_types::keys::actions; use meilisearch_types::milli::index::ChatConfig; @@ -117,6 +119,7 @@ fn setup_search_tool( filters: &meilisearch_auth::AuthFilter, chat_completion: &mut CreateChatCompletionRequest, prompts: &DbChatCompletionPrompts, + system_role: SystemRole, ) -> Result { let tools = chat_completion.tools.get_or_insert_default(); if tools.iter().any(|t| t.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME) { @@ -195,13 +198,21 @@ fn setup_search_tool( tools.push(tool); - chat_completion.messages.insert( - 0, - ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { - content: ChatCompletionRequestSystemMessageContent::Text(prompts.system.clone()), - name: None, - }), - ); + let system_message = match system_role { + SystemRole::System => { + ChatCompletionRequestMessage::System(ChatCompletionRequestSystemMessage { + content: ChatCompletionRequestSystemMessageContent::Text(prompts.system.clone()), + name: None, + }) + } + SystemRole::Developer => { + ChatCompletionRequestMessage::Developer(ChatCompletionRequestDeveloperMessage { + content: ChatCompletionRequestDeveloperMessageContent::Text(prompts.system.clone()), + name: None, + }) + } + }; + chat_completion.messages.insert(0, system_message); Ok(FunctionSupport { report_progress, report_sources, append_to_conversation }) } @@ -315,9 +326,15 @@ async fn non_streamed_chat( let config = Config::new(&chat_settings); let client = Client::with_config(config); let auth_token = extract_token_from_request(&req)?.unwrap(); + let system_role = chat_settings.source.system_role(&chat_completion.model); // TODO do function support later - let _function_support = - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; + let _function_support = setup_search_tool( + &index_scheduler, + filters, + &mut chat_completion, + &chat_settings.prompts, + system_role, + )?; let mut response; loop { @@ -408,8 +425,14 @@ async fn streamed_chat( let config = Config::new(&chat_settings); let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); - let function_support = - setup_search_tool(&index_scheduler, filters, &mut chat_completion, &chat_settings.prompts)?; + let system_role = chat_settings.source.system_role(&chat_completion.model); + let function_support = setup_search_tool( + &index_scheduler, + filters, + &mut chat_completion, + &chat_settings.prompts, + system_role, + )?; tracing::debug!("Conversation function support: {function_support:?}"); From 3ebff65ef313b3ef4f54d5ea8c920f924e573654 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:28:30 +0300 Subject: [PATCH 207/292] tests: Faster search::filters IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 62 +++++++++++----------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 49409efa6..1e2fac998 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -10,17 +10,17 @@ use crate::{ #[actix_rt::test] async fn search_with_filter_string_notation() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (_, code) = index.update_settings(json!({"filterableAttributes": ["title"]})).await; - meili_snap::snapshot!(code, @"202 Accepted"); + snapshot!(code, @"202 Accepted"); let documents = DOCUMENTS.clone(); let (task, code) = index.add_documents(documents, None).await; - meili_snap::snapshot!(code, @"202 Accepted"); - let res = index.wait_task(task.uid()).await; - meili_snap::snapshot!(res["status"], @r###""succeeded""###); + snapshot!(code, @"202 Accepted"); + let res = index.wait_task(task.uid()).await.succeeded(); + snapshot!(res["status"], @r###""succeeded""###); index .search( @@ -28,44 +28,44 @@ async fn search_with_filter_string_notation() { "filter": "title = Gläss" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }, ) .await; - let index = server.index("nested"); + let nested_index = server.unique_index(); let (_, code) = - index.update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})).await; - meili_snap::snapshot!(code, @"202 Accepted"); + nested_index.update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})).await; + snapshot!(code, @"202 Accepted"); let documents = NESTED_DOCUMENTS.clone(); - let (task, code) = index.add_documents(documents, None).await; - meili_snap::snapshot!(code, @"202 Accepted"); - let res = index.wait_task(task.uid()).await; - meili_snap::snapshot!(res["status"], @r###""succeeded""###); + let (task, code) = nested_index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let res = nested_index.wait_task(task.uid()).await.succeeded(); + snapshot!(res["status"], @r###""succeeded""###); - index + nested_index .search( json!({ "filter": "cattos = pésti" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); assert_eq!(response["hits"][0]["id"], json!(852)); }, ) .await; - index + nested_index .search( json!({ "filter": "doggos.age > 5" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 2); assert_eq!(response["hits"][0]["id"], json!(654)); assert_eq!(response["hits"][1]["id"], json!(951)); @@ -82,7 +82,7 @@ async fn search_with_filter_array_notation() { "filter": ["title = Gläss"] })) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); let (response, code) = index @@ -90,7 +90,7 @@ async fn search_with_filter_array_notation() { "filter": [["title = Gläss", "title = \"Shazam!\"", "title = \"Escape Room\""]] })) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 3); } @@ -116,7 +116,7 @@ async fn search_with_contains_filter() { "filter": "title CONTAINS cap" })) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 2); } @@ -276,8 +276,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { let index = server.index("test"); let (task, code) = index.add_documents(NESTED_DOCUMENTS.clone(), None).await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); let (task, code) = index @@ -289,8 +289,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter works @@ -355,8 +355,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter works @@ -467,8 +467,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter returns an error @@ -567,8 +567,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter works From b41af0d0f6cb1e315d002b2fd70bb472274d56c0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:57:43 +0300 Subject: [PATCH 208/292] Formatting Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 1e2fac998..19a6ad775 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -36,8 +36,9 @@ async fn search_with_filter_string_notation() { let nested_index = server.unique_index(); - let (_, code) = - nested_index.update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})).await; + let (_, code) = nested_index + .update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})) + .await; snapshot!(code, @"202 Accepted"); let documents = NESTED_DOCUMENTS.clone(); From 3f256a79592e4e6527da67855eaf6cad9b5650a0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 4 Jun 2025 13:51:34 +0300 Subject: [PATCH 209/292] Use the shared index with DOCUMENTS where possible Remove useless assertion that is covered by the earlier call of .succeeded() Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 32 ++++++---------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 19a6ad775..f6ce5d0b7 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,6 +3,7 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; +use crate::common::shared_index_with_nested_documents; use crate::{ common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, json, @@ -10,17 +11,7 @@ use crate::{ #[actix_rt::test] async fn search_with_filter_string_notation() { - let server = Server::new_shared(); - let index = server.unique_index(); - - let (_, code) = index.update_settings(json!({"filterableAttributes": ["title"]})).await; - snapshot!(code, @"202 Accepted"); - - let documents = DOCUMENTS.clone(); - let (task, code) = index.add_documents(documents, None).await; - snapshot!(code, @"202 Accepted"); - let res = index.wait_task(task.uid()).await.succeeded(); - snapshot!(res["status"], @r###""succeeded""###); + let index = shared_index_with_documents().await; index .search( @@ -34,6 +25,7 @@ async fn search_with_filter_string_notation() { ) .await; + let server = Server::new_shared(); let nested_index = server.unique_index(); let (_, code) = nested_index @@ -44,8 +36,7 @@ async fn search_with_filter_string_notation() { let documents = NESTED_DOCUMENTS.clone(); let (task, code) = nested_index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - let res = nested_index.wait_task(task.uid()).await.succeeded(); - snapshot!(res["status"], @r###""succeeded""###); + nested_index.wait_task(task.uid()).await.succeeded(); nested_index .search( @@ -278,8 +269,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { let (task, code) = index.add_documents(NESTED_DOCUMENTS.clone(), None).await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); let (task, code) = index .update_settings(json!({"filterableAttributes": [{ @@ -291,8 +281,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter works index @@ -357,8 +346,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter works index @@ -469,8 +457,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter returns an error index @@ -569,8 +556,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter works index From a15ebb283f2b7087be3c5247698a6176d200d864 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 4 Jun 2025 14:17:01 +0300 Subject: [PATCH 210/292] Remove unused import Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index f6ce5d0b7..26f7c88e4 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,7 +3,6 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; -use crate::common::shared_index_with_nested_documents; use crate::{ common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, json, From e497008161b4f1e4f213d1baa0088c40fb98e239 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 5 Jun 2025 11:28:29 +0300 Subject: [PATCH 211/292] Add `cattos` to the shared_index_with_nested_documents() as a filterable attribute This allows to make some more search::filters IT tests using shared server + unique/shared indices Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/mod.rs | 2 +- crates/meilisearch/tests/search/filters.rs | 25 ++++++---------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/crates/meilisearch/tests/common/mod.rs b/crates/meilisearch/tests/common/mod.rs index 00e4732d0..373f89f78 100644 --- a/crates/meilisearch/tests/common/mod.rs +++ b/crates/meilisearch/tests/common/mod.rs @@ -352,7 +352,7 @@ pub async fn shared_index_with_nested_documents() -> &'static Index<'static, Sha index.wait_task(response.uid()).await.succeeded(); let (response, _code) = index ._update_settings( - json!({"filterableAttributes": ["father", "doggos"], "sortableAttributes": ["doggos"]}), + json!({"filterableAttributes": ["father", "doggos", "cattos"], "sortableAttributes": ["doggos"]}), ) .await; index.wait_task(response.uid()).await.succeeded(); diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 26f7c88e4..3df80b90c 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,6 +3,7 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; +use crate::common::shared_index_with_nested_documents; use crate::{ common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, json, @@ -24,18 +25,7 @@ async fn search_with_filter_string_notation() { ) .await; - let server = Server::new_shared(); - let nested_index = server.unique_index(); - - let (_, code) = nested_index - .update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})) - .await; - snapshot!(code, @"202 Accepted"); - - let documents = NESTED_DOCUMENTS.clone(); - let (task, code) = nested_index.add_documents(documents, None).await; - snapshot!(code, @"202 Accepted"); - nested_index.wait_task(task.uid()).await.succeeded(); + let nested_index = shared_index_with_nested_documents().await; nested_index .search( @@ -260,11 +250,10 @@ async fn search_with_pattern_filter_settings() { #[actix_rt::test] async fn search_with_pattern_filter_settings_scenario_1() { - let temp = TempDir::new().unwrap(); - let server = Server::new_with_options(Opt { ..default_settings(temp.path()) }).await.unwrap(); + let server = Server::new_shared(); eprintln!("Documents -> Settings -> test"); - let index = server.index("test"); + let index = server.unique_index(); let (task, code) = index.add_documents(NESTED_DOCUMENTS.clone(), None).await; assert_eq!(code, 202, "{task}"); @@ -324,7 +313,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -468,7 +457,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -599,7 +588,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" From 3770e705818cce2735ba4fa544249d78a752c80b Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 5 Jun 2025 11:30:39 +0300 Subject: [PATCH 212/292] Optimize the imports Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 3df80b90c..9670a036c 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,9 +3,11 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; -use crate::common::shared_index_with_nested_documents; use crate::{ - common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, + common::{ + default_settings, shared_index_with_documents, shared_index_with_nested_documents, Server, + DOCUMENTS, NESTED_DOCUMENTS, + }, json, }; From 89c0cf9b12159932951914bffa9b3d7eb6020bb0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 09:51:18 +0300 Subject: [PATCH 213/292] temporary: Dump the threads stack traces when .wait_task() times out Signed-off-by: Martin Tzvetanov Grigorov --- .cargo/config.toml | 3 +++ .github/workflows/test-suite.yml | 2 ++ crates/meilisearch/tests/common/server.rs | 16 ++++++++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index e11d56a31..b172ee2af 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,5 @@ [alias] xtask = "run --release --package xtask --" + +[build] +rustflags = ["--cfg", "tokio_unstable", "--cfg", "tokio_taskdump"] diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 6cf8bfa0f..100068965 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -158,6 +158,8 @@ jobs: uses: Swatinem/rust-cache@v2.7.8 - name: Run tests in debug uses: actions-rs/cargo@v1 + env: + RUSTFLAGS: "--cfg tokio_unstable --cfg tokio_taskdump" with: command: test args: --locked --all diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 7e30c5d17..02ea2f79a 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -400,12 +400,8 @@ impl Server { // try several times to get status, or panic to not wait forever let url = format!("/tasks/{}", update_id); // Increase timeout for vector-related tests - let max_attempts = if url.contains("/tasks/") { - if update_id > 1000 { - 400 // 200 seconds for vector tests - } else { - 100 // 50 seconds for other tests - } + let max_attempts = if update_id > 1000 { + 400 // 200 seconds for vector tests } else { 100 // 50 seconds for other tests }; @@ -421,6 +417,14 @@ impl Server { // wait 0.5 second. sleep(Duration::from_millis(500)).await; } + let handle = tokio::runtime::Handle::current(); + if let Ok(dump) = tokio::time::timeout(Duration::from_secs(2), handle.dump()).await { + for (i, task) in dump.tasks().iter().enumerate() { + let trace = task.trace(); + println!("TASK {i}:"); + println!("{trace}\n"); + } + } panic!("Timeout waiting for update id"); } From 1b4d344e18bf58f3202bcbe706863f16598ca558 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 11:42:54 +0300 Subject: [PATCH 214/292] Increase the wait time in the tests Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 02ea2f79a..1bfbf7641 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -403,7 +403,7 @@ impl Server { let max_attempts = if update_id > 1000 { 400 // 200 seconds for vector tests } else { - 100 // 50 seconds for other tests + 1000 // 50 seconds for other tests }; for _ in 0..max_attempts { From 63ccd19ab16ac7b336531d7485f06d749185987c Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 13:45:05 +0300 Subject: [PATCH 215/292] Use Server::wait_task() instead of Index::wait_task() for tasks IT tests Revert the debugging helper that dumped the thread stack traces. Try with 400 max attempts for the task success/failure (200 secs) Signed-off-by: Martin Tzvetanov Grigorov --- .cargo/config.toml | 3 -- .github/workflows/test-suite.yml | 2 - crates/meilisearch/tests/common/server.rs | 19 ++----- crates/meilisearch/tests/tasks/mod.rs | 66 ++++++++++++----------- 4 files changed, 39 insertions(+), 51 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index b172ee2af..e11d56a31 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,2 @@ [alias] xtask = "run --release --package xtask --" - -[build] -rustflags = ["--cfg", "tokio_unstable", "--cfg", "tokio_taskdump"] diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 100068965..6cf8bfa0f 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -158,8 +158,6 @@ jobs: uses: Swatinem/rust-cache@v2.7.8 - name: Run tests in debug uses: actions-rs/cargo@v1 - env: - RUSTFLAGS: "--cfg tokio_unstable --cfg tokio_taskdump" with: command: test args: --locked --all diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 1bfbf7641..431972983 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -399,14 +399,9 @@ impl Server { pub async fn wait_task(&self, update_id: u64) -> Value { // try several times to get status, or panic to not wait forever let url = format!("/tasks/{}", update_id); - // Increase timeout for vector-related tests - let max_attempts = if update_id > 1000 { - 400 // 200 seconds for vector tests - } else { - 1000 // 50 seconds for other tests - }; + let max_attempts = 400; // 200 seconds total, 0.5s per attempt - for _ in 0..max_attempts { + for i in 0..max_attempts { let (response, status_code) = self.service.get(&url).await; assert_eq!(200, status_code, "response: {}", response); @@ -416,13 +411,9 @@ impl Server { // wait 0.5 second. sleep(Duration::from_millis(500)).await; - } - let handle = tokio::runtime::Handle::current(); - if let Ok(dump) = tokio::time::timeout(Duration::from_secs(2), handle.dump()).await { - for (i, task) in dump.tasks().iter().enumerate() { - let trace = task.trace(); - println!("TASK {i}:"); - println!("{trace}\n"); + + if i == max_attempts - 1 { + dbg!(response); } } panic!("Timeout waiting for update id"); diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index c31e43883..064b52a1f 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -39,7 +39,7 @@ async fn get_task_status() { None, ) .await; - index.wait_task(create_task.uid()).await.succeeded(); + server.wait_task(create_task.uid()).await.succeeded(); let (_response, code) = index.get_task(add_task.uid()).await; assert_eq!(code, 200); // TODO check response format, as per #48 @@ -51,7 +51,7 @@ async fn list_tasks() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -105,7 +105,7 @@ async fn list_tasks_with_star_filters() { // Do not use a unique index here, as we want to test the `indexUids=*` filter. let index = server.index("test"); let (task, _code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -154,9 +154,9 @@ async fn list_tasks_status_filtered() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (response, code) = index.filtered_tasks(&[], &["succeeded"], &[]).await; assert_eq!(code, 200, "{response}"); @@ -177,7 +177,7 @@ async fn list_tasks_type_filtered() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -197,10 +197,12 @@ async fn list_tasks_invalid_canceled_by_filter() { let server = Server::new_shared(); let index = server.unique_index(); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); + let (task, _code) = index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; + server.wait_task(task.uid()).await.succeeded(); let (response, code) = index.filtered_tasks(&[], &[], &[format!("{}", task.uid()).as_str()]).await; @@ -214,7 +216,7 @@ async fn list_tasks_status_and_type_filtered() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -284,7 +286,7 @@ async fn test_summarized_document_addition_or_update() { let index = server.unique_index(); let (task, _status_code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -309,7 +311,7 @@ async fn test_summarized_document_addition_or_update() { let (task, _status_code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -343,7 +345,7 @@ async fn test_summarized_delete_documents_by_batch() { let (task, _status_code) = index .delete_batch(vec![non_existing_task_id1, non_existing_task_id2, non_existing_task_id3]) .await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -374,7 +376,7 @@ async fn test_summarized_delete_documents_by_batch() { index.create(None).await; let (del_task, _status_code) = index.delete_batch(vec![42]).await; - index.wait_task(del_task.uid()).await.succeeded(); + server.wait_task(del_task.uid()).await.succeeded(); let (task, _) = index.get_task(del_task.uid()).await; snapshot!(task, @r###" @@ -406,7 +408,7 @@ async fn test_summarized_delete_documents_by_filter() { let (task, _status_code) = index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -438,7 +440,7 @@ async fn test_summarized_delete_documents_by_filter() { index.create(None).await; let (task, _status_code) = index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -470,7 +472,7 @@ async fn test_summarized_delete_documents_by_filter() { index.update_settings(json!({ "filterableAttributes": ["doggo"] })).await; let (task, _status_code) = index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -500,7 +502,7 @@ async fn test_summarized_delete_document_by_id() { let server = Server::new_shared(); let index = server.unique_index(); let (task, _status_code) = index.delete_document(1).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -531,7 +533,7 @@ async fn test_summarized_delete_document_by_id() { index.create(None).await; let (task, _status_code) = index.delete_document(42).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -573,7 +575,7 @@ async fn test_summarized_settings_update() { "###); let (task,_status_code) = index.update_settings(json!({ "displayedAttributes": ["doggos", "name"], "filterableAttributes": ["age", "nb_paw_pads"], "sortableAttributes": ["iq"] })).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -611,7 +613,7 @@ async fn test_summarized_index_creation() { let server = Server::new_shared(); let index = server.unique_index(); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -634,7 +636,7 @@ async fn test_summarized_index_creation() { "###); let (task, _status_code) = index.create(Some("doggos")).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -667,7 +669,7 @@ async fn test_summarized_index_deletion() { let server = Server::new_shared(); let index = server.unique_index(); let (ret, _code) = index.delete().await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -698,7 +700,7 @@ async fn test_summarized_index_deletion() { // both tasks may get autobatched and the deleted documents count will be wrong. let (ret, _code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -721,7 +723,7 @@ async fn test_summarized_index_deletion() { "###); let (ret, _code) = index.delete().await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -744,7 +746,7 @@ async fn test_summarized_index_deletion() { // What happens when you delete an index that doesn't exists. let (ret, _code) = index.delete().await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -777,7 +779,7 @@ async fn test_summarized_index_update() { let index = server.unique_index(); // If the index doesn't exist yet, we should get errors with or without the primary key. let (task, _status_code) = index.update(None).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -805,7 +807,7 @@ async fn test_summarized_index_update() { "###); let (task, _status_code) = index.update(Some("bones")).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -836,7 +838,7 @@ async fn test_summarized_index_update() { index.create(None).await; let (task, _status_code) = index.update(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -859,7 +861,7 @@ async fn test_summarized_index_update() { "###); let (task, _status_code) = index.update(Some("bones")).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -973,9 +975,9 @@ async fn test_summarized_task_cancelation() { // to avoid being flaky we're only going to cancel an already finished task :( let (task, _status_code) = index.create(None).await; let task_uid = task.uid(); - index.wait_task(task_uid).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = server.cancel_tasks(format!("uids={task_uid}").as_str()).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(json_string!(task, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".**.originalFilter" => "[of]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @@ -1007,9 +1009,9 @@ async fn test_summarized_task_deletion() { let index = server.unique_index(); // to avoid being flaky we're only going to delete an already finished task :( let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = server.delete_tasks("uids=0").await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" From 10028515acca965be2b37c6d488c2231edb15205 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 14:52:05 +0300 Subject: [PATCH 216/292] Use a unique server for the summarized dump creation test Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/server.rs | 2 +- crates/meilisearch/tests/tasks/mod.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 431972983..e6f2aca2c 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -399,7 +399,7 @@ impl Server { pub async fn wait_task(&self, update_id: u64) -> Value { // try several times to get status, or panic to not wait forever let url = format!("/tasks/{}", update_id); - let max_attempts = 400; // 200 seconds total, 0.5s per attempt + let max_attempts = 100; // 50 seconds total, 0.5s per attempt for i in 0..max_attempts { let (response, status_code) = self.service.get(&url).await; diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 064b52a1f..09700d3c5 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -1038,7 +1038,8 @@ async fn test_summarized_task_deletion() { #[actix_web::test] async fn test_summarized_dump_creation() { - let server = Server::new_shared(); + // Do not use a shared server because it takes too long to create a dump + let server = Server::new().await; let (task, _status_code) = server.create_dump().await; server.wait_task(task.uid()).await; let (task, _) = server.get_task(task.uid()).await; From f5c3dad3ed270401dbbaf8d0c73c8073cc0a2de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Mon, 9 Jun 2025 10:47:21 +0200 Subject: [PATCH 217/292] Revert "Prompt for Email" --- Dockerfile | 1 - crates/meilisearch/src/analytics/mod.rs | 2 +- .../src/analytics/segment_analytics.rs | 1 - crates/meilisearch/src/main.rs | 113 +----------------- crates/meilisearch/src/option.rs | 13 -- 5 files changed, 3 insertions(+), 127 deletions(-) diff --git a/Dockerfile b/Dockerfile index 937537728..5a9a4691f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,6 @@ LABEL org.opencontainers.image.source="https://github.com/meilisearch/meilisea ENV MEILI_HTTP_ADDR 0.0.0.0:7700 ENV MEILI_SERVER_PROVIDER docker -ENV MEILI_CONTACT_EMAIL "" RUN apk add -q --no-cache libgcc tini curl diff --git a/crates/meilisearch/src/analytics/mod.rs b/crates/meilisearch/src/analytics/mod.rs index cd5641375..bd14b0bfa 100644 --- a/crates/meilisearch/src/analytics/mod.rs +++ b/crates/meilisearch/src/analytics/mod.rs @@ -45,7 +45,7 @@ macro_rules! empty_analytics { /// `~/.config/Meilisearch` on *NIX or *BSD. /// `~/Library/ApplicationSupport` on macOS. /// `%APPDATA` (= `C:\Users%USERNAME%\AppData\Roaming`) on windows. -pub static MEILISEARCH_CONFIG_PATH: Lazy> = +static MEILISEARCH_CONFIG_PATH: Lazy> = Lazy::new(|| AppDirs::new(Some("Meilisearch"), false).map(|appdir| appdir.config_dir)); fn config_user_id_path(db_path: &Path) -> Option { diff --git a/crates/meilisearch/src/analytics/segment_analytics.rs b/crates/meilisearch/src/analytics/segment_analytics.rs index 2c0121ffc..ee8a9ee20 100644 --- a/crates/meilisearch/src/analytics/segment_analytics.rs +++ b/crates/meilisearch/src/analytics/segment_analytics.rs @@ -277,7 +277,6 @@ impl Infos { log_level, indexer_options, config_file_path, - contact_email: _, no_analytics: _, } = options; diff --git a/crates/meilisearch/src/main.rs b/crates/meilisearch/src/main.rs index 13f76732a..b16dda097 100644 --- a/crates/meilisearch/src/main.rs +++ b/crates/meilisearch/src/main.rs @@ -12,7 +12,7 @@ use actix_web::web::Data; use actix_web::HttpServer; use index_scheduler::IndexScheduler; use is_terminal::IsTerminal; -use meilisearch::analytics::{Analytics, MEILISEARCH_CONFIG_PATH}; +use meilisearch::analytics::Analytics; use meilisearch::option::LogMode; use meilisearch::search_queue::SearchQueue; use meilisearch::{ @@ -20,18 +20,11 @@ use meilisearch::{ LogStderrType, Opt, SubscriberForSecondLayer, }; use meilisearch_auth::{generate_master_key, AuthController, MASTER_KEY_MIN_SIZE}; -use meilisearch_types::versioning::{VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH}; -use serde_json::json; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; -use tokio::io::{AsyncBufReadExt, BufReader}; use tracing::level_filters::LevelFilter; use tracing_subscriber::layer::SubscriberExt as _; use tracing_subscriber::Layer; -const SKIP_EMAIL_FILENAME: &str = "skip-email"; -const PORTAL_ID: &str = "25945010"; -const FORM_GUID: &str = "991e2a09-77c2-4428-9242-ebf26bfc6c64"; - #[cfg(not(windows))] #[global_allocator] static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -96,7 +89,7 @@ async fn main() -> anyhow::Result<()> { } async fn try_main() -> anyhow::Result<()> { - let (mut opt, config_read_from) = Opt::try_build()?; + let (opt, config_read_from) = Opt::try_build()?; std::panic::set_hook(Box::new(on_panic)); @@ -131,38 +124,6 @@ async fn try_main() -> anyhow::Result<()> { let (index_scheduler, auth_controller) = setup_meilisearch(&opt)?; - // We ask users their emails just after the data.ms is created - let skip_email_path = - MEILISEARCH_CONFIG_PATH.as_ref().map(|conf| conf.join(SKIP_EMAIL_FILENAME)); - // If the config path does not exist, it means the user don't have a home directory - let skip_email = skip_email_path.as_ref().is_none_or(|path| path.exists()); - opt.contact_email = match opt.contact_email.as_ref().map(|email| email.as_deref()) { - Some(Some("false")) | None if !skip_email => prompt_for_contact_email().await.map(Some)?, - Some(Some(email)) if !skip_email => Some(Some(email.to_string())), - _otherwise => None, - }; - - if let Some(Some(email)) = opt.contact_email.as_ref() { - let email = email.clone(); - // We spawn a task to register the email and create the skip email - // file to avoid blocking the Meilisearch launch further. - let handle = tokio::spawn(async move { - if let Some(skip_email_path) = skip_email_path { - // If the analytics are disabled the directory might not exist at all - if let Err(e) = tokio::fs::create_dir_all(skip_email_path.parent().unwrap()).await { - eprintln!("Failed to create skip email file: {e}"); - } - if let Err(e) = tokio::fs::File::create_new(skip_email_path).await { - eprintln!("Failed to create skip email file: {e}"); - } - } - if let Err(err) = register_contact_email(&email).await { - eprintln!("Failed to register email: {}", err); - } - }); - drop(handle); - } - let analytics = analytics::Analytics::new(&opt, index_scheduler.clone(), auth_controller.clone()).await; @@ -178,76 +139,6 @@ async fn try_main() -> anyhow::Result<()> { Ok(()) } -/// Prompt the user about the contact email for support and news. -/// It only displays the prompt if the input is an interactive terminal. -async fn prompt_for_contact_email() -> anyhow::Result> { - let stdin = tokio::io::stdin(); - - if !stdin.is_terminal() { - return Ok(None); - } - - println!("Get monthly updates about new features and tips to get the most out of Meilisearch."); - println!("Use the --contact-email option to disable this prompt."); - print!("Enter your email or leave blank to skip> "); - std::io::stdout().flush()?; - - let mut email = String::new(); - let mut stdin = BufReader::new(stdin); - let _ = stdin.read_line(&mut email).await?; - let email = email.trim(); - - if email.is_empty() { - Ok(None) - } else { - Ok(Some(email.to_string())) - } -} - -async fn register_contact_email(email: &str) -> anyhow::Result<()> { - let url = format!( - "https://api.hsforms.com/submissions/v3/integration/submit/{PORTAL_ID}/{FORM_GUID}" - ); - - let page_name = format!( - "Meilisearch terminal prompt v{}.{}.{}", - VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH - ); - let response = reqwest::Client::new() - .post(url) - .json(&json!({ - "fields": [{ - "objectTypeId": "0-1", - "name": "email", - "value": email, - }], - "context": { - "pageName": page_name, - }, - "legalConsentOptions": { - "consent": { - "consentToProcess": true, - "text": "I agree to allow Meilisearch to store and process my personal data.", - "communications": [{ - "value": true, - "subscriptionTypeId": 999, - "text": "I agree to receive marketing communications from Meilisearch.", - }], - }, - }, - })) - .send() - .await?; - - let status = response.status(); - if status.is_client_error() || status.is_server_error() { - let response: serde_json::Value = response.json().await?; - eprintln!("Failed to register email: {response:?}"); - } - - Ok(()) -} - async fn run_http( index_scheduler: Arc, auth_controller: Arc, diff --git a/crates/meilisearch/src/option.rs b/crates/meilisearch/src/option.rs index 2a5de7011..6e06b161d 100644 --- a/crates/meilisearch/src/option.rs +++ b/crates/meilisearch/src/option.rs @@ -66,7 +66,6 @@ const MEILI_EXPERIMENTAL_LIMIT_BATCHED_TASKS_TOTAL_SIZE: &str = const MEILI_EXPERIMENTAL_EMBEDDING_CACHE_ENTRIES: &str = "MEILI_EXPERIMENTAL_EMBEDDING_CACHE_ENTRIES"; const MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION: &str = "MEILI_EXPERIMENTAL_NO_SNAPSHOT_COMPACTION"; -const MEILI_CONTACT_EMAIL: &str = "MEILI_CONTACT_EMAIL"; const DEFAULT_CONFIG_FILE_PATH: &str = "./config.toml"; const DEFAULT_DB_PATH: &str = "./data.ms"; const DEFAULT_HTTP_ADDR: &str = "localhost:7700"; @@ -348,13 +347,6 @@ pub struct Opt { #[serde(default)] pub log_level: LogLevel, - /// Sets the email address to contact for support and news. - /// - /// Use this option to disable contact email prompting. Leave - /// blank or without value to disable contact email prompting. - #[clap(long, env = MEILI_CONTACT_EMAIL)] - pub contact_email: Option>, - /// Experimental contains filter feature. For more information, /// see: /// @@ -564,7 +556,6 @@ impl Opt { ignore_dump_if_db_exists: _, config_file_path: _, no_analytics, - contact_email, experimental_contains_filter, experimental_enable_metrics, experimental_search_queue_size, @@ -597,10 +588,6 @@ impl Opt { } export_to_env_if_not_present(MEILI_NO_ANALYTICS, no_analytics.to_string()); - export_to_env_if_not_present( - MEILI_CONTACT_EMAIL, - contact_email.flatten().unwrap_or_else(|| "false".to_string()), - ); export_to_env_if_not_present( MEILI_HTTP_PAYLOAD_SIZE_LIMIT, http_payload_size_limit.to_string(), From 2ec966487850e8327d2a8c48895d9b4c77cca543 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 13:49:29 +0300 Subject: [PATCH 218/292] chore: Fix English grammar in SearchQueue's comments No functional changes! Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/src/search_queue.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/meilisearch/src/search_queue.rs b/crates/meilisearch/src/search_queue.rs index 6ab910164..9ff8da36c 100644 --- a/crates/meilisearch/src/search_queue.rs +++ b/crates/meilisearch/src/search_queue.rs @@ -1,5 +1,5 @@ //! This file implements a queue of searches to process and the ability to control how many searches can be run in parallel. -//! We need this because we don't want to process more search requests than we have cores. +//! We need this because we don't want to process more search requests than the available CPU cores. //! That slows down everything and consumes RAM for no reason. //! The steps to do a search are to get the `SearchQueue` data structure and try to get a search permit. //! This can fail if the queue is full, and we need to drop your search request to register a new one. @@ -8,7 +8,7 @@ //! //! In order to do a search request you should try to get a search permit. //! Retrieve the `SearchQueue` structure from actix-web (`search_queue: Data`) -//! and right before processing the search, calls the `SearchQueue::try_get_search_permit` method: `search_queue.try_get_search_permit().await?;` +//! and right before processing the search, call the `SearchQueue::try_get_search_permit` method: `search_queue.try_get_search_permit().await?;` //! //! What is going to happen at this point is that you're going to send a oneshot::Sender over an async mpsc channel. //! Then, the queue/scheduler is going to either: @@ -121,12 +121,12 @@ impl SearchQueue { let mut queue: Vec> = Default::default(); let mut rng: StdRng = StdRng::from_entropy(); let mut searches_running: usize = 0; - // By having a capacity of parallelism we ensures that every time a search finish it can release its RAM asap + // By having a capacity of parallelism we ensure that every time a search finish it can release its RAM asap let (sender, mut search_finished) = mpsc::channel(parallelism.into()); loop { tokio::select! { - // biased select because we wants to free up space before trying to register new tasks + // biased select because we want to free up space before trying to register new tasks biased; _ = search_finished.recv() => { searches_running = searches_running.saturating_sub(1); @@ -148,11 +148,11 @@ impl SearchQueue { if searches_running < usize::from(parallelism) && queue.is_empty() { searches_running += 1; - // if the search requests die it's not a hard error on our side + // if the search requests die, it's not a hard error on our side let _ = search_request.send(Permit { sender: sender.clone() }); continue; } else if capacity == 0 { - // in the very specific case where we have a capacity of zero + // in the very specific case where we have a capacity of zero, // we must refuse the request straight away without going through // the queue stuff. drop(search_request); @@ -183,7 +183,7 @@ impl SearchQueue { .map_err(|_| MeilisearchHttpError::TooManySearchRequests(self.capacity))?; // If we've been for more than one minute to get a search permit, it's better to simply - // abort the search request than spending time processing something were the client + // abort the search request than spending time processing something where the client // most certainly exited or got a timeout a long time ago. // We may find a better solution in https://github.com/actix/actix-web/issues/3462. if now.elapsed() > self.time_to_abort { From 8f96724adf54ef6da06dae274ddef414a58ec1c8 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Mon, 9 Jun 2025 14:03:49 +0300 Subject: [PATCH 219/292] Set max_attempts to 400 for Server::wait_task() Co-authored-by: Tamo --- crates/meilisearch/tests/common/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index e6f2aca2c..431972983 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -399,7 +399,7 @@ impl Server { pub async fn wait_task(&self, update_id: u64) -> Value { // try several times to get status, or panic to not wait forever let url = format!("/tasks/{}", update_id); - let max_attempts = 100; // 50 seconds total, 0.5s per attempt + let max_attempts = 400; // 200 seconds total, 0.5s per attempt for i in 0..max_attempts { let (response, status_code) = self.service.get(&url).await; From 1fda05c2fd625965f8097baece5c2713120e86de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Mon, 9 Jun 2025 15:26:13 +0200 Subject: [PATCH 220/292] Delete chat.rs --- crates/meilisearch/src/routes/chat.rs | 291 -------------------------- 1 file changed, 291 deletions(-) delete mode 100644 crates/meilisearch/src/routes/chat.rs diff --git a/crates/meilisearch/src/routes/chat.rs b/crates/meilisearch/src/routes/chat.rs deleted file mode 100644 index ad46d91c8..000000000 --- a/crates/meilisearch/src/routes/chat.rs +++ /dev/null @@ -1,291 +0,0 @@ -use std::mem; - -use actix_web::web::{self, Data}; -use actix_web::{Either, HttpResponse, Responder}; -use actix_web_lab::sse::{self, Event}; -use async_openai::config::OpenAIConfig; -use async_openai::types::{ - ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, - ChatCompletionRequestToolMessage, ChatCompletionRequestToolMessageContent, - ChatCompletionToolArgs, ChatCompletionToolType, CreateChatCompletionRequest, FinishReason, - FunctionObjectArgs, -}; -use async_openai::Client; -use futures::StreamExt; -use index_scheduler::IndexScheduler; -use meilisearch_types::error::ResponseError; -use meilisearch_types::keys::actions; -use meilisearch_types::milli::index::IndexEmbeddingConfig; -use meilisearch_types::milli::prompt::PromptData; -use meilisearch_types::milli::vector::EmbeddingConfig; -use meilisearch_types::{Document, Index}; -use serde::{Deserialize, Serialize}; -use serde_json::json; - -use crate::extractors::authentication::policies::ActionPolicy; -use crate::extractors::authentication::GuardedData; -use crate::metrics::MEILISEARCH_DEGRADED_SEARCH_REQUESTS; -use crate::routes::indexes::search::search_kind; -use crate::search::{ - add_search_rules, perform_search, HybridQuery, RetrieveVectors, SearchQuery, SemanticRatio, -}; -use crate::search_queue::SearchQueue; - -/// The default description of the searchInIndex tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION: &str = - "Search the database for relevant JSON documents using an optional query."; -/// The default description of the searchInIndex `q` parameter tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION: &str = - "The search query string used to find relevant documents in the index. \ -This should contain keywords or phrases that best represent what the user is looking for. \ -More specific queries will yield more precise results."; -/// The default description of the searchInIndex `index` parameter tool provided to OpenAI. -const DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION: &str = -"The name of the index to search within. An index is a collection of documents organized for search. \ -Selecting the right index ensures the most relevant results for the user query"; - -const EMBEDDER_NAME: &str = "openai"; - -pub fn configure(cfg: &mut web::ServiceConfig) { - cfg.service(web::resource("").route(web::post().to(chat))); -} - -/// Get a chat completion -async fn chat( - index_scheduler: GuardedData, Data>, - search_queue: web::Data, - web::Json(mut chat_completion): web::Json, -) -> impl Responder { - // To enable later on, when the feature will be experimental - // index_scheduler.features().check_chat("Using the /chat route")?; - - if chat_completion.stream.unwrap_or(false) { - Either::Right(streamed_chat(index_scheduler, search_queue, chat_completion).await) - } else { - Either::Left(non_streamed_chat(index_scheduler, search_queue, chat_completion).await) - } -} - -async fn non_streamed_chat( - index_scheduler: GuardedData, Data>, - search_queue: web::Data, - mut chat_completion: CreateChatCompletionRequest, -) -> Result { - let api_key = std::env::var("MEILI_OPENAI_API_KEY") - .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); - let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base - let client = Client::with_config(config); - - assert_eq!( - chat_completion.n.unwrap_or(1), - 1, - "Meilisearch /chat only support one completion at a time (n = 1, n = null)" - ); - - let rtxn = index_scheduler.read_txn().unwrap(); - let search_in_index_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_TOOL_DESCRIPTION) - .to_string(); - let search_in_index_q_param_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-q-param-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_Q_PARAMETER_TOOL_DESCRIPTION) - .to_string(); - let search_in_index_index_description = index_scheduler - .chat_prompts(&rtxn, "searchInIndex-index-param-description") - .unwrap() - .unwrap_or(DEFAULT_SEARCH_IN_INDEX_INDEX_PARAMETER_TOOL_DESCRIPTION) - .to_string(); - drop(rtxn); - - let mut response; - loop { - let tools = chat_completion.tools.get_or_insert_default(); - tools.push( - ChatCompletionToolArgs::default() - .r#type(ChatCompletionToolType::Function) - .function( - FunctionObjectArgs::default() - .name("searchInIndex") - .description(&search_in_index_description) - .parameters(json!({ - "type": "object", - "properties": { - "index_uid": { - "type": "string", - "enum": ["main"], - "description": search_in_index_index_description, - }, - "q": { - "type": ["string", "null"], - "description": search_in_index_q_param_description, - } - }, - "required": ["index_uid", "q"], - "additionalProperties": false, - })) - .strict(true) - .build() - .unwrap(), - ) - .build() - .unwrap(), - ); - response = client.chat().create(chat_completion.clone()).await.unwrap(); - - let choice = &mut response.choices[0]; - match choice.finish_reason { - Some(FinishReason::ToolCalls) => { - let tool_calls = mem::take(&mut choice.message.tool_calls).unwrap_or_default(); - - let (meili_calls, other_calls): (Vec<_>, Vec<_>) = - tool_calls.into_iter().partition(|call| call.function.name == "searchInIndex"); - - chat_completion.messages.push( - ChatCompletionRequestAssistantMessageArgs::default() - .tool_calls(meili_calls.clone()) - .build() - .unwrap() - .into(), - ); - - for call in meili_calls { - let SearchInIndexParameters { index_uid, q } = - serde_json::from_str(&call.function.arguments).unwrap(); - - let mut query = SearchQuery { - q, - hybrid: Some(HybridQuery { - semantic_ratio: SemanticRatio::default(), - embedder: EMBEDDER_NAME.to_string(), - }), - limit: 20, - ..Default::default() - }; - - // Tenant token search_rules. - if let Some(search_rules) = - index_scheduler.filters().get_index_search_rules(&index_uid) - { - add_search_rules(&mut query.filter, search_rules); - } - - // TBD - // let mut aggregate = SearchAggregator::::from_query(&query); - - let index = index_scheduler.index(&index_uid)?; - let search_kind = search_kind( - &query, - index_scheduler.get_ref(), - index_uid.to_string(), - &index, - )?; - - let permit = search_queue.try_get_search_permit().await?; - let features = index_scheduler.features(); - let index_cloned = index.clone(); - let search_result = tokio::task::spawn_blocking(move || { - perform_search( - index_uid.to_string(), - &index_cloned, - query, - search_kind, - RetrieveVectors::new(false), - features, - ) - }) - .await; - permit.drop().await; - - let search_result = search_result?; - if let Ok(ref search_result) = search_result { - // aggregate.succeed(search_result); - if search_result.degraded { - MEILISEARCH_DEGRADED_SEARCH_REQUESTS.inc(); - } - } - // analytics.publish(aggregate, &req); - - let search_result = search_result?; - let formatted = format_documents( - &index, - search_result.hits.into_iter().map(|doc| doc.document), - ); - let text = formatted.join("\n"); - chat_completion.messages.push(ChatCompletionRequestMessage::Tool( - ChatCompletionRequestToolMessage { - tool_call_id: call.id, - content: ChatCompletionRequestToolMessageContent::Text(text), - }, - )); - } - - // Let the client call other tools by themselves - if !other_calls.is_empty() { - response.choices[0].message.tool_calls = Some(other_calls); - break; - } - } - _ => break, - } - } - - Ok(HttpResponse::Ok().json(response)) -} - -async fn streamed_chat( - index_scheduler: GuardedData, Data>, - search_queue: web::Data, - mut chat_completion: CreateChatCompletionRequest, -) -> impl Responder { - assert!(chat_completion.stream.unwrap_or(false)); - - let api_key = std::env::var("MEILI_OPENAI_API_KEY") - .expect("cannot find OpenAI API Key (MEILI_OPENAI_API_KEY)"); - let config = OpenAIConfig::default().with_api_key(&api_key); // we can also change the API base - let client = Client::with_config(config); - let response = client.chat().create_stream(chat_completion).await.unwrap(); - actix_web_lab::sse::Sse::from_stream(response.map(|response| { - response - .map(|mut r| Event::Data(sse::Data::new_json(r.choices.pop().unwrap().delta).unwrap())) - })) -} - -#[derive(Deserialize)] -struct SearchInIndexParameters { - /// The index uid to search in. - index_uid: String, - /// The query parameter to use. - q: Option, -} - -fn format_documents(index: &Index, documents: impl Iterator) -> Vec { - let rtxn = index.read_txn().unwrap(); - let IndexEmbeddingConfig { name: _, config, user_provided: _ } = index - .embedding_configs(&rtxn) - .unwrap() - .into_iter() - .find(|conf| conf.name == EMBEDDER_NAME) - .unwrap(); - - let EmbeddingConfig { - embedder_options: _, - prompt: PromptData { template, max_bytes }, - quantized: _, - } = config; - - #[derive(Serialize)] - struct Doc { - doc: T, - } - - let template = liquid::ParserBuilder::with_stdlib().build().unwrap().parse(&template).unwrap(); - documents - .map(|doc| { - let object = liquid::to_object(&Doc { doc }).unwrap(); - template.render(&object).unwrap() - }) - .collect() -} From 48e8356a16ccd074be781febd55208ab5ff76d81 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 09:18:36 +0200 Subject: [PATCH 221/292] Mark the non-streaming chat completions route unimplemented --- crates/meilisearch-types/src/error.rs | 1 + .../meilisearch/src/routes/chats/chat_completions.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 27f7580e2..17c28acc3 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -390,6 +390,7 @@ InvalidDocumentEditionFunctionFilter , InvalidRequest , BAD_REQU EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST ; InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ; // Experimental features - Chat Completions +UnimplementedNonStreamingChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND ; InvalidChatCompletionOrgId , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionProjectId , InvalidRequest , BAD_REQUEST ; diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index f4e42cae3..e89129f18 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -301,17 +301,23 @@ async fn process_search_request( Ok((index, documents, text)) } +#[allow(unreachable_code, unused_variables)] // will be correctly implemented in the future async fn non_streamed_chat( index_scheduler: GuardedData, Data>, auth_ctrl: web::Data, search_queue: web::Data, workspace_uid: &str, req: HttpRequest, - mut chat_completion: CreateChatCompletionRequest, + chat_completion: CreateChatCompletionRequest, ) -> Result { index_scheduler.features().check_chat_completions("using the /chats chat completions route")?; - let filters = index_scheduler.filters(); + return Err(ResponseError::from_msg( + format!("Non-streamed chat completions is not implemented"), + Code::UnimplementedNonStreamingChatCompletions, + )); + + let filters = index_scheduler.filters(); let rtxn = index_scheduler.read_txn()?; let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid).unwrap() { Some(settings) => settings, From a7f5d3bb7a711df25d29630c6623a6f12a4bfba6 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 09:21:45 +0200 Subject: [PATCH 222/292] Redact the API Key when patching chat workspace settings --- crates/meilisearch/src/routes/chats/settings.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index c7b89d5bb..07ed4dea6 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -103,7 +103,7 @@ async fn patch_settings( Setting::NotSet => old_settings.prompts, }; - let settings = ChatCompletionSettings { + let mut settings = ChatCompletionSettings { source: match new.source { Setting::Set(new_source) => new_source.into(), Setting::Reset => DbChatCompletionSource::default(), @@ -154,6 +154,8 @@ async fn patch_settings( index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &settings)?; wtxn.commit()?; + settings.hide_secrets(); + Ok(HttpResponse::Ok().json(settings)) } From 29d82ade5646f7fec5f19b7618ea2beaec39d273 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 09:24:07 +0200 Subject: [PATCH 223/292] Rename base_api into base_rul --- crates/meilisearch-types/src/features.rs | 2 +- crates/meilisearch/src/routes/chats/config.rs | 8 ++++---- crates/meilisearch/src/routes/chats/settings.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 210a0f0f9..5cc066afd 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -59,7 +59,7 @@ pub struct ChatCompletionSettings { #[serde(default)] pub deployment_id: Option, #[serde(default)] - pub base_api: Option, + pub base_url: Option, #[serde(default)] pub api_key: Option, #[serde(default)] diff --git a/crates/meilisearch/src/routes/chats/config.rs b/crates/meilisearch/src/routes/chats/config.rs index 9babbd8c9..182eff735 100644 --- a/crates/meilisearch/src/routes/chats/config.rs +++ b/crates/meilisearch/src/routes/chats/config.rs @@ -24,8 +24,8 @@ impl Config { if let Some(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - if let Some(base_api) = chat_settings.base_api.as_ref() { - config = config.with_api_base(base_api); + if let Some(base_url) = chat_settings.base_url.as_ref() { + config = config.with_api_base(base_url); } Self::OpenAiCompatible(config) } @@ -40,8 +40,8 @@ impl Config { if let Some(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - if let Some(base_api) = chat_settings.base_api.as_ref() { - config = config.with_api_base(base_api); + if let Some(base_url) = chat_settings.base_url.as_ref() { + config = config.with_api_base(base_url); } Self::AzureOpenAiCompatible(config) } diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 07ed4dea6..dae2826fe 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -129,10 +129,10 @@ async fn patch_settings( Setting::Reset => None, Setting::NotSet => old_settings.deployment_id, }, - base_api: match new.base_api { - Setting::Set(new_base_api) => Some(new_base_api), + base_url: match new.base_url { + Setting::Set(new_base_url) => Some(new_base_url), Setting::Reset => None, - Setting::NotSet => old_settings.base_api, + Setting::NotSet => old_settings.base_url, }, api_key: match new.api_key { Setting::Set(new_api_key) => Some(new_api_key), @@ -211,7 +211,7 @@ pub struct GlobalChatSettings { #[serde(default)] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!("https://api.mistral.ai/v1"))] - pub base_api: Setting, + pub base_url: Setting, #[serde(default)] #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!("abcd1234..."))] From bc56087a1725ec1eee3fd4fe089961d2edb7838f Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:08:01 +0200 Subject: [PATCH 224/292] Fix the chatCompletions key --- crates/meilisearch-types/src/keys.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 5634d585f..fe6005796 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -323,9 +323,8 @@ pub enum Action { #[serde(rename = "network.update")] #[deserr(rename = "network.update")] NetworkUpdate, - // TODO should we rename it chatCompletions.get ? - #[serde(rename = "chatCompletion")] - #[deserr(rename = "chatCompletion")] + #[serde(rename = "chatCompletions")] + #[deserr(rename = "chatCompletions")] ChatCompletions, #[serde(rename = "chats.get")] #[deserr(rename = "chats.get")] From e654eddf56f2890c5caea5d5be3465ffd9e203ab Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:21:34 +0200 Subject: [PATCH 225/292] Improve the chat workspace REST endpoints --- crates/index-scheduler/src/lib.rs | 8 +++- crates/meilisearch-auth/src/store.rs | 9 ++-- crates/meilisearch-types/src/keys.rs | 15 ++++--- crates/meilisearch/src/routes/chats/mod.rs | 45 ++++++++++++++++++- .../meilisearch/src/routes/chats/settings.rs | 14 +++--- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 3860ef5cb..3ad342bea 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -55,7 +55,7 @@ use meilisearch_types::features::{ ChatCompletionSettings, InstanceTogglableFeatures, Network, RuntimeTogglableFeatures, }; use meilisearch_types::heed::byteorder::BE; -use meilisearch_types::heed::types::{SerdeJson, Str, I128}; +use meilisearch_types::heed::types::{DecodeIgnore, SerdeJson, Str, I128}; use meilisearch_types::heed::{self, Database, Env, RoTxn, RwTxn, WithoutTls}; use meilisearch_types::milli::index::IndexEmbeddingConfig; use meilisearch_types::milli::update::IndexerConfig; @@ -904,6 +904,12 @@ impl IndexScheduler { self.chat_settings.get(rtxn, uid).map_err(Into::into) } + /// Return true if chat workspace exists. + pub fn chat_workspace_exists(&self, name: &str) -> Result { + let rtxn = self.env.read_txn()?; + Ok(self.chat_settings.remap_data_type::().get(&rtxn, name)?.is_some()) + } + pub fn put_chat_settings( &self, wtxn: &mut RwTxn, diff --git a/crates/meilisearch-auth/src/store.rs b/crates/meilisearch-auth/src/store.rs index e20f259ee..bae27afe4 100644 --- a/crates/meilisearch-auth/src/store.rs +++ b/crates/meilisearch-auth/src/store.rs @@ -125,12 +125,11 @@ impl HeedAuthStore { Action::MetricsAll => { actions.insert(Action::MetricsGet); } + Action::ChatsAll => { + actions.extend([Action::ChatsGet, Action::ChatsDelete]); + } Action::ChatsSettingsAll => { - actions.extend([ - Action::ChatsSettingsGet, - Action::ChatsSettingsUpdate, - Action::ChatsSettingsDelete, - ]); + actions.extend([Action::ChatsSettingsGet, Action::ChatsSettingsUpdate]); } other => { actions.insert(*other); diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index fe6005796..df2810727 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -326,9 +326,15 @@ pub enum Action { #[serde(rename = "chatCompletions")] #[deserr(rename = "chatCompletions")] ChatCompletions, + #[serde(rename = "chats.*")] + #[deserr(rename = "chats.*")] + ChatsAll, #[serde(rename = "chats.get")] #[deserr(rename = "chats.get")] ChatsGet, + #[serde(rename = "chats.delete")] + #[deserr(rename = "chats.delete")] + ChatsDelete, #[serde(rename = "chatsSettings.*")] #[deserr(rename = "chatsSettings.*")] ChatsSettingsAll, @@ -338,9 +344,6 @@ pub enum Action { #[serde(rename = "chatsSettings.update")] #[deserr(rename = "chatsSettings.update")] ChatsSettingsUpdate, - #[serde(rename = "chatsSettings.delete")] - #[deserr(rename = "chatsSettings.delete")] - ChatsSettingsDelete, } impl Action { @@ -367,11 +370,12 @@ impl Action { SETTINGS_GET => Some(Self::SettingsGet), SETTINGS_UPDATE => Some(Self::SettingsUpdate), CHAT_COMPLETIONS => Some(Self::ChatCompletions), + CHATS_ALL => Some(Self::ChatsAll), CHATS_GET => Some(Self::ChatsGet), + CHATS_DELETE => Some(Self::ChatsDelete), CHATS_SETTINGS_ALL => Some(Self::ChatsSettingsAll), CHATS_SETTINGS_GET => Some(Self::ChatsSettingsGet), CHATS_SETTINGS_UPDATE => Some(Self::ChatsSettingsUpdate), - CHATS_SETTINGS_DELETE => Some(Self::ChatsSettingsDelete), STATS_ALL => Some(Self::StatsAll), STATS_GET => Some(Self::StatsGet), METRICS_ALL => Some(Self::MetricsAll), @@ -438,9 +442,10 @@ pub mod actions { pub const NETWORK_UPDATE: u8 = NetworkUpdate.repr(); pub const CHAT_COMPLETIONS: u8 = ChatCompletions.repr(); + pub const CHATS_ALL: u8 = ChatsAll.repr(); pub const CHATS_GET: u8 = ChatsGet.repr(); + pub const CHATS_DELETE: u8 = ChatsDelete.repr(); pub const CHATS_SETTINGS_ALL: u8 = ChatsSettingsAll.repr(); pub const CHATS_SETTINGS_GET: u8 = ChatsSettingsGet.repr(); pub const CHATS_SETTINGS_UPDATE: u8 = ChatsSettingsUpdate.repr(); - pub const CHATS_SETTINGS_DELETE: u8 = ChatsSettingsDelete.repr(); } diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index ddaf4d80d..8c8c9bc32 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -6,9 +6,11 @@ use index_scheduler::IndexScheduler; use meilisearch_types::deserr::query_params::Param; use meilisearch_types::deserr::DeserrQueryParamError; use meilisearch_types::error::deserr_codes::{InvalidIndexLimit, InvalidIndexOffset}; -use meilisearch_types::error::ResponseError; +use meilisearch_types::error::{Code, ResponseError}; +use meilisearch_types::index_uid::IndexUid; use meilisearch_types::keys::actions; use serde::{Deserialize, Serialize}; +use serde_json::json; use tracing::debug; use utoipa::{IntoParams, ToSchema}; @@ -40,11 +42,52 @@ pub struct ChatsParam { pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(web::resource("").route(web::get().to(list_workspaces))).service( web::scope("/{workspace_uid}") + .service( + web::resource("") + .route(web::get().to(get_chat)) + .route(web::delete().to(delete_chat)), + ) .service(web::scope("/chat/completions").configure(chat_completions::configure)) .service(web::scope("/settings").configure(settings::configure)), ); } +pub async fn get_chat( + index_scheduler: GuardedData, Data>, + workspace_uid: web::Path, +) -> Result { + index_scheduler.features().check_chat_completions("displaying a chat")?; + + let workspace_uid = IndexUid::try_from(workspace_uid.into_inner())?; + if index_scheduler.chat_workspace_exists(&workspace_uid)? { + Ok(HttpResponse::Ok().json(json!({ "uid": workspace_uid }))) + } else { + Err(ResponseError::from_msg( + format!("chat {workspace_uid} not found"), + Code::ChatWorkspaceNotFound, + )) + } +} + +pub async fn delete_chat( + index_scheduler: GuardedData, Data>, + workspace_uid: web::Path, +) -> Result { + index_scheduler.features().check_chat_completions("deleting a chat")?; + + let mut wtxn = index_scheduler.write_txn()?; + let workspace_uid = workspace_uid.into_inner(); + if index_scheduler.delete_chat_settings(&mut wtxn, &workspace_uid)? { + wtxn.commit()?; + Ok(HttpResponse::NoContent().finish()) + } else { + Err(ResponseError::from_msg( + format!("chat {workspace_uid} not found"), + Code::ChatWorkspaceNotFound, + )) + } +} + #[derive(Deserr, Debug, Clone, Copy, IntoParams)] #[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] #[into_params(rename_all = "camelCase", parameter_in = Query)] diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index dae2826fe..329732e75 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -26,7 +26,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { web::resource("") .route(web::get().to(SeqHandler(get_settings))) .route(web::patch().to(SeqHandler(patch_settings))) - .route(web::delete().to(SeqHandler(delete_settings))), + .route(web::delete().to(SeqHandler(reset_settings))), ); } @@ -159,9 +159,9 @@ async fn patch_settings( Ok(HttpResponse::Ok().json(settings)) } -async fn delete_settings( +async fn reset_settings( index_scheduler: GuardedData< - ActionPolicy<{ actions::CHATS_SETTINGS_DELETE }>, + ActionPolicy<{ actions::CHATS_SETTINGS_UPDATE }>, Data, >, chats_param: web::Path, @@ -169,12 +169,12 @@ async fn delete_settings( index_scheduler.features().check_chat_completions("using the /chats/settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); - - // TODO do a spawn_blocking here let mut wtxn = index_scheduler.write_txn()?; - if index_scheduler.delete_chat_settings(&mut wtxn, &workspace_uid)? { + if index_scheduler.chat_settings(&wtxn, &workspace_uid)?.is_some() { + let settings = Default::default(); + index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &settings)?; wtxn.commit()?; - Ok(HttpResponse::NoContent().finish()) + Ok(HttpResponse::Ok().json(settings)) } else { Err(ResponseError::from_msg( format!("Chat `{workspace_uid}` not found"), From 85939ae8ad4a7632864131040b57360cd30ba51a Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:25:22 +0200 Subject: [PATCH 226/292] Add support for missing sources --- crates/meilisearch/src/routes/chats/settings.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 329732e75..c3cdde74a 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -62,7 +62,7 @@ async fn patch_settings( Data, >, chats_param: web::Path, - web::Json(new): web::Json, + web::Json(new): web::Json, ) -> Result { index_scheduler.features().check_chat_completions("using the /chats/settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); @@ -187,7 +187,7 @@ async fn reset_settings( #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[schema(rename_all = "camelCase")] -pub struct GlobalChatSettings { +pub struct ChatWorkspaceSettings { #[serde(default)] #[deserr(default)] #[schema(value_type = Option)] @@ -228,12 +228,21 @@ pub struct GlobalChatSettings { pub enum ChatCompletionSource { #[default] OpenAi, + Mistral, + Gemini, + AzureOpenAi, + VLlm, } impl From for DbChatCompletionSource { fn from(source: ChatCompletionSource) -> Self { + use ChatCompletionSource::*; match source { - ChatCompletionSource::OpenAi => DbChatCompletionSource::OpenAi, + OpenAi => DbChatCompletionSource::OpenAi, + Mistral => DbChatCompletionSource::Mistral, + Gemini => DbChatCompletionSource::Gemini, + AzureOpenAi => DbChatCompletionSource::AzureOpenAi, + VLlm => DbChatCompletionSource::VLlm, } } } From 6433e498829e91cd760f085b871e7e32cbb1ba12 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:27:22 +0200 Subject: [PATCH 227/292] Remove useless code --- crates/milli/src/update/settings.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index 70a190b19..ae46cb5d9 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -124,15 +124,6 @@ impl Setting { *self = new; true } - - #[track_caller] - pub fn unwrap(self) -> T { - match self { - Setting::Set(value) => value, - Setting::Reset => panic!("Setting::Reset unwrapped"), - Setting::NotSet => panic!("Setting::NotSet unwrapped"), - } - } } impl Serialize for Setting { From 416fcf47f17259f096f3f8f561e8769b83fd971f Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:28:06 +0200 Subject: [PATCH 228/292] Use the same units --- crates/meilisearch-types/src/features.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 5cc066afd..322ca74d1 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -128,7 +128,8 @@ impl ChatCompletionSource { /// Old OpenAI models use the system role while new ones use the developer role. fn old_openai_model(model: &str) -> bool { ["gpt-3.5", "gpt-4", "gpt-4.1", "gpt-4.5", "gpt-4o", "chatgpt-4o"].iter().any(|old| { - model.starts_with(old) && model.chars().nth(old.len()).is_none_or(|last| last == '-') + model.starts_with(old) + && model.chars().nth(old.chars().count()).is_none_or(|last| last == '-') }) } From 95d4775d4a780dc0565fa0811abd1dfd22b447cc Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:32:58 +0200 Subject: [PATCH 229/292] Remove the preQuery chat setting --- crates/meilisearch-types/src/features.rs | 3 --- .../src/routes/chats/chat_completions.rs | 15 +++------------ crates/meilisearch/src/routes/chats/settings.rs | 15 +++------------ 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 322ca74d1..bada14fe2 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -7,7 +7,6 @@ pub const DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT: &str = "Search the database for relevant JSON documents using an optional query."; pub const DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT: &str = "The search query string used to find relevant documents in the index. This should contain keywords or phrases that best represent what the user is looking for. More specific queries will yield more precise results."; pub const DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT: &str = "The name of the index to search within. An index is a collection of documents organized for search. Selecting the right index ensures the most relevant results for the user query. You have access to two indexes: movies, steam. The movies index contains movies with overviews. The steam index contains steam games from the Steam platform with their prices"; -pub const DEFAULT_CHAT_PRE_QUERY_PROMPT: &str = ""; #[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)] #[serde(rename_all = "camelCase", default)] @@ -151,7 +150,6 @@ pub struct ChatCompletionPrompts { pub search_description: String, pub search_q_param: String, pub search_index_uid_param: String, - pub pre_query: String, } impl Default for ChatCompletionPrompts { @@ -161,7 +159,6 @@ impl Default for ChatCompletionPrompts { search_description: DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT.to_string(), search_q_param: DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT.to_string(), search_index_uid_param: DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT.to_string(), - pre_query: DEFAULT_CHAT_PRE_QUERY_PROMPT.to_string(), } } } diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index e89129f18..d467a8fe9 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -23,10 +23,7 @@ use futures::StreamExt; use index_scheduler::IndexScheduler; use meilisearch_auth::AuthController; use meilisearch_types::error::{Code, ResponseError}; -use meilisearch_types::features::{ - ChatCompletionPrompts as DbChatCompletionPrompts, ChatCompletionSettings as DbChatSettings, - SystemRole, -}; +use meilisearch_types::features::{ChatCompletionPrompts as DbChatCompletionPrompts, SystemRole}; use meilisearch_types::keys::actions; use meilisearch_types::milli::index::ChatConfig; use meilisearch_types::milli::{all_obkv_to_json, obkv_to_json, TimeBudget}; @@ -379,12 +376,11 @@ async fn non_streamed_chat( }; // TODO report documents sources later - let text = match result { + let answer = match result { Ok((_, _documents, text)) => text, Err(err) => err, }; - let answer = format!("{}\n\n{text}", chat_settings.prompts.pre_query); chat_completion.messages.push(ChatCompletionRequestMessage::Tool( ChatCompletionRequestToolMessage { tool_call_id: call.id.clone(), @@ -456,7 +452,6 @@ async fn streamed_chat( &search_queue, &auth_token, &client, - &chat_settings, &mut chat_completion, &tx, &mut global_tool_calls, @@ -489,7 +484,6 @@ async fn run_conversation( search_queue: &web::Data, auth_token: &str, client: &Client, - chat_settings: &DbChatSettings, chat_completion: &mut CreateChatCompletionRequest, tx: &SseEventSender, global_tool_calls: &mut HashMap, @@ -579,7 +573,6 @@ async fn run_conversation( auth_ctrl, search_queue, auth_token, - chat_settings, tx, meili_calls, chat_completion, @@ -617,7 +610,6 @@ async fn handle_meili_tools( auth_ctrl: &web::Data, search_queue: &web::Data, auth_token: &str, - chat_settings: &DbChatSettings, tx: &SseEventSender, meili_calls: Vec, chat_completion: &mut CreateChatCompletionRequest, @@ -659,7 +651,7 @@ async fn handle_meili_tools( Err(err) => Err(err.to_string()), }; - let text = match result { + let answer = match result { Ok((_index, documents, text)) => { if report_sources { tx.report_sources(resp.clone(), &call.id, &documents).await?; @@ -670,7 +662,6 @@ async fn handle_meili_tools( Err(err) => err, }; - let answer = format!("{}\n\n{text}", chat_settings.prompts.pre_query); let tool = ChatCompletionRequestMessage::Tool(ChatCompletionRequestToolMessage { tool_call_id: call.id.clone(), content: ChatCompletionRequestToolMessageContent::Text(answer), diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index c3cdde74a..4bf323dbd 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -7,9 +7,9 @@ use meilisearch_types::error::deserr_codes::*; use meilisearch_types::error::{Code, ResponseError}; use meilisearch_types::features::{ ChatCompletionPrompts as DbChatCompletionPrompts, ChatCompletionSettings, - ChatCompletionSource as DbChatCompletionSource, DEFAULT_CHAT_PRE_QUERY_PROMPT, - DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT, DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT, - DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT, DEFAULT_CHAT_SYSTEM_PROMPT, + ChatCompletionSource as DbChatCompletionSource, DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT, + DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT, DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT, + DEFAULT_CHAT_SYSTEM_PROMPT, }; use meilisearch_types::keys::actions; use meilisearch_types::milli::update::Setting; @@ -93,11 +93,6 @@ async fn patch_settings( Setting::Reset => DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT.to_string(), Setting::NotSet => old_settings.prompts.search_index_uid_param, }, - pre_query: match new_prompts.pre_query { - Setting::Set(new_description) => new_description, - Setting::Reset => DEFAULT_CHAT_PRE_QUERY_PROMPT.to_string(), - Setting::NotSet => old_settings.prompts.pre_query, - }, }, Setting::Reset => DbChatCompletionPrompts::default(), Setting::NotSet => old_settings.prompts, @@ -268,8 +263,4 @@ pub struct ChatPrompts { #[deserr(default, error = DeserrJsonError)] #[schema(value_type = Option, example = json!("This is index you want to search in..."))] pub search_index_uid_param: Setting, - #[serde(default)] - #[deserr(default, error = DeserrJsonError)] - #[schema(value_type = Option)] - pub pre_query: Setting, } From 605dea4f858ccc4a707f20a638a173c865628f2e Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:34:30 +0200 Subject: [PATCH 230/292] Do not leak the chat "workspace" term --- crates/meilisearch-types/src/error.rs | 2 +- crates/meilisearch/src/routes/chats/chat_completions.rs | 4 ++-- crates/meilisearch/src/routes/chats/mod.rs | 4 ++-- crates/meilisearch/src/routes/chats/settings.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 17c28acc3..bdf9bb162 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -391,7 +391,7 @@ EditDocumentsByFunctionError , InvalidRequest , BAD_REQU InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ; // Experimental features - Chat Completions UnimplementedNonStreamingChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; -ChatWorkspaceNotFound , InvalidRequest , NOT_FOUND ; +ChatNotFound , InvalidRequest , NOT_FOUND ; InvalidChatCompletionOrgId , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionProjectId , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionApiVersion , InvalidRequest , BAD_REQUEST ; diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index d467a8fe9..bf336f224 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -321,7 +321,7 @@ async fn non_streamed_chat( None => { return Err(ResponseError::from_msg( format!("Chat `{workspace_uid}` not found"), - Code::ChatWorkspaceNotFound, + Code::ChatNotFound, )) } }; @@ -419,7 +419,7 @@ async fn streamed_chat( None => { return Err(ResponseError::from_msg( format!("Chat `{workspace_uid}` not found"), - Code::ChatWorkspaceNotFound, + Code::ChatNotFound, )) } }; diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 8c8c9bc32..6379aa83b 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -64,7 +64,7 @@ pub async fn get_chat( } else { Err(ResponseError::from_msg( format!("chat {workspace_uid} not found"), - Code::ChatWorkspaceNotFound, + Code::ChatNotFound, )) } } @@ -83,7 +83,7 @@ pub async fn delete_chat( } else { Err(ResponseError::from_msg( format!("chat {workspace_uid} not found"), - Code::ChatWorkspaceNotFound, + Code::ChatNotFound, )) } } diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 4bf323dbd..039655841 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -48,7 +48,7 @@ async fn get_settings( None => { return Err(ResponseError::from_msg( format!("Chat `{workspace_uid}` not found"), - Code::ChatWorkspaceNotFound, + Code::ChatNotFound, )) } }; @@ -173,7 +173,7 @@ async fn reset_settings( } else { Err(ResponseError::from_msg( format!("Chat `{workspace_uid}` not found"), - Code::ChatWorkspaceNotFound, + Code::ChatNotFound, )) } } From 985b892b7a8a4571714c2e7598ed0e925468d381 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 10:57:43 +0200 Subject: [PATCH 231/292] Add a basic chat setting validation --- crates/meilisearch-types/src/features.rs | 17 +++++++++++++++++ crates/meilisearch/src/routes/chats/settings.rs | 1 + 2 files changed, 18 insertions(+) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index bada14fe2..e30ce3b55 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -2,6 +2,8 @@ use std::collections::BTreeMap; use serde::{Deserialize, Serialize}; +use crate::error::{Code, ResponseError}; + pub const DEFAULT_CHAT_SYSTEM_PROMPT: &str = "You are a highly capable research assistant with access to powerful search tools. IMPORTANT INSTRUCTIONS:1. When answering questions, you MUST make multiple tool calls (at least 2-3) to gather comprehensive information.2. Use different search queries for each tool call - vary keywords, rephrase questions, and explore different semantic angles to ensure broad coverage.3. Always explicitly announce BEFORE making each tool call by saying: \"I'll search for [specific information] now.\"4. Combine information from ALL tool calls to provide complete, nuanced answers rather than relying on a single source.5. For complex topics, break down your research into multiple targeted queries rather than using a single generic search."; pub const DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT: &str = "Search the database for relevant JSON documents using an optional query."; @@ -88,6 +90,21 @@ impl ChatCompletionSettings { } } } + + pub fn validate(&self) -> Result<(), ResponseError> { + use ChatCompletionSource::*; + match self { + Self { source: AzureOpenAi, base_url, deployment_id, api_version, .. } if base_url.is_none() || deployment_id.is_none() || api_version.is_none() => Err(ResponseError::from_msg( + format!("azureOpenAi requires setting a valid `baseUrl`, `deploymentId`, and `apiVersion`"), + Code::BadRequest, + )), + Self { source: VLlm, base_url, .. } if base_url.is_none() => Err(ResponseError::from_msg( + format!("vLlm requires setting a valid `baseUrl`"), + Code::BadRequest, + )), + _otherwise => Ok(()), + } + } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index 039655841..ab696f68a 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -146,6 +146,7 @@ async fn patch_settings( // &req, // ); + settings.validate()?; index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &settings)?; wtxn.commit()?; From 4a0ec15ad2f72ffdc9302180875d290a07e399bb Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 11:00:14 +0200 Subject: [PATCH 232/292] Make cargo fmt happy --- crates/meilisearch/src/routes/chats/mod.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 6379aa83b..7a868fd45 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -62,10 +62,7 @@ pub async fn get_chat( if index_scheduler.chat_workspace_exists(&workspace_uid)? { Ok(HttpResponse::Ok().json(json!({ "uid": workspace_uid }))) } else { - Err(ResponseError::from_msg( - format!("chat {workspace_uid} not found"), - Code::ChatNotFound, - )) + Err(ResponseError::from_msg(format!("chat {workspace_uid} not found"), Code::ChatNotFound)) } } @@ -81,10 +78,7 @@ pub async fn delete_chat( wtxn.commit()?; Ok(HttpResponse::NoContent().finish()) } else { - Err(ResponseError::from_msg( - format!("chat {workspace_uid} not found"), - Code::ChatNotFound, - )) + Err(ResponseError::from_msg(format!("chat {workspace_uid} not found"), Code::ChatNotFound)) } } From 9cab754942087f46d943a95c2e77502dfda306e8 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 11:11:34 +0200 Subject: [PATCH 233/292] Update insta snapshots --- crates/meilisearch/tests/auth/api_keys.rs | 4 ++-- crates/meilisearch/tests/auth/errors.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/meilisearch/tests/auth/api_keys.rs b/crates/meilisearch/tests/auth/api_keys.rs index 69a1ccb53..84ed24217 100644 --- a/crates/meilisearch/tests/auth/api_keys.rs +++ b/crates/meilisearch/tests/auth/api_keys.rs @@ -421,7 +421,7 @@ async fn error_add_api_key_invalid_parameters_actions() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Unknown value `doc.add` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`, `chatCompletion`, `chats.get`, `chatsSettings.*`, `chatsSettings.get`, `chatsSettings.update`, `chatsSettings.delete`", + "message": "Unknown value `doc.add` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`, `chatCompletions`, `chats.*`, `chats.get`, `chats.delete`, `chatsSettings.*`, `chatsSettings.get`, `chatsSettings.update`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" @@ -856,7 +856,7 @@ async fn list_api_keys() { "key": "[ignored]", "uid": "[ignored]", "actions": [ - "chatCompletion", + "chatCompletions", "search" ], "indexes": [ diff --git a/crates/meilisearch/tests/auth/errors.rs b/crates/meilisearch/tests/auth/errors.rs index 6d4c17e19..ebe2e53fa 100644 --- a/crates/meilisearch/tests/auth/errors.rs +++ b/crates/meilisearch/tests/auth/errors.rs @@ -93,7 +93,7 @@ async fn create_api_key_bad_actions() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Unknown value `doggo` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`, `chatCompletion`, `chats.get`, `chatsSettings.*`, `chatsSettings.get`, `chatsSettings.update`, `chatsSettings.delete`", + "message": "Unknown value `doggo` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `snapshots.*`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `network.get`, `network.update`, `chatCompletions`, `chats.*`, `chats.get`, `chats.delete`, `chatsSettings.*`, `chatsSettings.get`, `chatsSettings.update`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" From 1a1317ab0f0fd2a39d242eaec89af4443238df7f Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 11:12:27 +0200 Subject: [PATCH 234/292] Make clippy happy --- crates/meilisearch-types/src/features.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index e30ce3b55..1cb0fa244 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -95,11 +95,11 @@ impl ChatCompletionSettings { use ChatCompletionSource::*; match self { Self { source: AzureOpenAi, base_url, deployment_id, api_version, .. } if base_url.is_none() || deployment_id.is_none() || api_version.is_none() => Err(ResponseError::from_msg( - format!("azureOpenAi requires setting a valid `baseUrl`, `deploymentId`, and `apiVersion`"), + "azureOpenAi requires setting a valid `baseUrl`, `deploymentId`, and `apiVersion`".to_string(), Code::BadRequest, )), Self { source: VLlm, base_url, .. } if base_url.is_none() => Err(ResponseError::from_msg( - format!("vLlm requires setting a valid `baseUrl`"), + "vLlm requires setting a valid `baseUrl`".to_string(), Code::BadRequest, )), _otherwise => Ok(()), From c640856cc18807ca4567acfa2aa0657871bffeea Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 11:13:32 +0200 Subject: [PATCH 235/292] Improve code comments --- crates/meilisearch/src/routes/chats/utils.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/utils.rs b/crates/meilisearch/src/routes/chats/utils.rs index b29747bc9..34bfebcc7 100644 --- a/crates/meilisearch/src/routes/chats/utils.rs +++ b/crates/meilisearch/src/routes/chats/utils.rs @@ -41,7 +41,7 @@ impl SseEventSender { function_name: String, function_arguments: String, ) -> Result<(), SendError> { - #[allow(deprecated)] + #[allow(deprecated)] // function_call let message = ChatCompletionRequestMessage::Assistant(ChatCompletionRequestAssistantMessage { content: None, @@ -78,7 +78,7 @@ impl SseEventSender { resp.choices[0] = ChatChoiceStream { index: 0, - #[allow(deprecated)] + #[allow(deprecated)] // function_call delta: ChatCompletionStreamResponseDelta { content: None, function_call: None, @@ -125,7 +125,7 @@ impl SseEventSender { resp.choices[0] = ChatChoiceStream { index: 0, - #[allow(deprecated)] + #[allow(deprecated)] // function_call delta: ChatCompletionStreamResponseDelta { content: None, function_call: None, @@ -170,7 +170,7 @@ impl SseEventSender { resp.choices[0] = ChatChoiceStream { index: 0, - #[allow(deprecated)] + #[allow(deprecated)] // function_call delta: ChatCompletionStreamResponseDelta { content: None, function_call: None, From 8fa6e8670ac49da984080fd6eecfc27de6ebb52b Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 29 May 2025 14:36:51 +0300 Subject: [PATCH 236/292] tests: Faster search::multi IT tests Use shared server + unique indices where possible Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 27 +- crates/meilisearch/tests/common/mod.rs | 2 +- crates/meilisearch/tests/search/multi/mod.rs | 1710 ++++++++---------- 3 files changed, 787 insertions(+), 952 deletions(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 1641a6335..e9fa94159 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -43,23 +43,20 @@ pub fn default_snapshot_settings_for_test<'a>( } } + fn uuid_in_index_uid_redaction(content: Content, _content_path: ContentPath) -> Content { + match &content { + Content::String(s) => match uuid::Uuid::parse_str(s) { + Ok(_) => Content::String("[uuid]".to_owned()), + Err(_) => content, + }, + _ => content, + } + } + settings.add_dynamic_redaction(".message", uuid_in_message_redaction); settings.add_dynamic_redaction(".error.message", uuid_in_message_redaction); - settings.add_dynamic_redaction(".indexUid", |content, _content_path| match &content { - Content::String(s) => match uuid::Uuid::parse_str(s) { - Ok(_) => Content::String("[uuid]".to_owned()), - Err(_) => content, - }, - _ => content, - }); - - settings.add_dynamic_redaction(".error.message", |content, _content_path| match &content { - Content::String(s) => { - let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "$before[uuid]$after"); - Content::String(uuid_replaced.to_string()) - } - _ => content, - }); + settings.add_dynamic_redaction(".indexUid", uuid_in_index_uid_redaction); + settings.add_dynamic_redaction(".**.indexUid", uuid_in_index_uid_redaction); let test_name = test_name.strip_suffix("::{{closure}}").unwrap_or(test_name); let test_name = test_name.rsplit("::").next().unwrap().to_owned(); diff --git a/crates/meilisearch/tests/common/mod.rs b/crates/meilisearch/tests/common/mod.rs index 373f89f78..1a73a7532 100644 --- a/crates/meilisearch/tests/common/mod.rs +++ b/crates/meilisearch/tests/common/mod.rs @@ -269,7 +269,7 @@ pub async fn shared_index_with_score_documents() -> &'static Index<'static, Shar static INDEX: OnceCell> = OnceCell::const_new(); INDEX.get_or_init(|| async { let server = Server::new_shared(); - let index = server._index("SCORE_DOCUMENTS").to_shared(); + let index = server._index("SHARED_SCORE_DOCUMENTS").to_shared(); let documents = SCORE_DOCUMENTS.clone(); let (response, _code) = index._add_documents(documents, None).await; index.wait_task(response.uid()).await.succeeded(); diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 8a83fd3c0..8eea27792 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -1,7 +1,10 @@ use meili_snap::{json_string, snapshot}; use super::{DOCUMENTS, FRUITS_DOCUMENTS, NESTED_DOCUMENTS}; -use crate::common::Server; +use crate::common::{ + shared_index_with_documents, shared_index_with_nested_documents, + shared_index_with_score_documents, Server, +}; use crate::json; use crate::search::{SCORE_DOCUMENTS, VECTOR_DOCUMENTS}; @@ -9,7 +12,7 @@ mod proxy; #[actix_rt::test] async fn search_empty_list() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, code) = server.multi_search(json!({"queries": []})).await; snapshot!(code, @"200 OK"); @@ -22,7 +25,7 @@ async fn search_empty_list() { #[actix_rt::test] async fn federation_empty_list() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, code) = server.multi_search(json!({"federation": {}, "queries": []})).await; snapshot!(code, @"200 OK"); @@ -39,7 +42,7 @@ async fn federation_empty_list() { #[actix_rt::test] async fn search_json_object() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, code) = server.multi_search(json!({})).await; snapshot!(code, @"400 Bad Request"); @@ -55,7 +58,7 @@ async fn search_json_object() { #[actix_rt::test] async fn federation_no_queries() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, code) = server.multi_search(json!({"federation": {}})).await; snapshot!(code, @"400 Bad Request"); @@ -71,7 +74,7 @@ async fn federation_no_queries() { #[actix_rt::test] async fn search_json_array() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, code) = server.multi_search(json!([])).await; snapshot!(code, @"400 Bad Request"); @@ -87,24 +90,20 @@ async fn search_json_array() { #[actix_rt::test] async fn simple_search_single_index() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid": "test", "q": "glass"}, - {"indexUid": "test", "q": "captain"}, + {"indexUid": index.uid, "q": "glass"}, + {"indexUid": index.uid, "q": "captain"}, ]})) .await; snapshot!(code, @"200 OK"); insta::assert_json_snapshot!(response["results"], { "[].processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" [ { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "hits": [ { "title": "Gläss", @@ -122,7 +121,7 @@ async fn simple_search_single_index() { "estimatedTotalHits": 1 }, { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "hits": [ { "title": "Captain Marvel", @@ -145,16 +144,12 @@ async fn simple_search_single_index() { #[actix_rt::test] async fn federation_single_search_single_index() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, + {"indexUid" : index.uid, "q": "glass"}, ]})) .await; snapshot!(code, @"200 OK"); @@ -169,7 +164,7 @@ async fn federation_single_search_single_index() { "red" ], "_federation": { - "indexUid": "test", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -185,19 +180,15 @@ async fn federation_single_search_single_index() { #[actix_rt::test] async fn federation_multiple_search_single_index() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = SCORE_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid": "test", "q": "the bat"}, - {"indexUid": "test", "q": "badman returns"}, - {"indexUid" : "test", "q": "batman"}, - {"indexUid": "test", "q": "batman returns"}, + {"indexUid": index.uid, "q": "the bat"}, + {"indexUid": index.uid, "q": "badman returns"}, + {"indexUid" : index.uid, "q": "batman"}, + {"indexUid": index.uid, "q": "batman returns"}, ]})) .await; snapshot!(code, @"200 OK"); @@ -260,17 +251,13 @@ async fn federation_multiple_search_single_index() { #[actix_rt::test] async fn federation_two_search_single_index() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "test", "q": "captain"}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid": index.uid, "q": "captain"}, ]})) .await; snapshot!(code, @"200 OK"); @@ -285,7 +272,7 @@ async fn federation_two_search_single_index() { "red" ], "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -298,7 +285,7 @@ async fn federation_two_search_single_index() { "blue" ], "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 } @@ -314,12 +301,7 @@ async fn federation_two_search_single_index() { #[actix_rt::test] async fn simple_search_missing_index_uid() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); let (response, code) = server .multi_search(json!({"queries": [ @@ -339,12 +321,7 @@ async fn simple_search_missing_index_uid() { #[actix_rt::test] async fn federation_simple_search_missing_index_uid() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ @@ -364,12 +341,7 @@ async fn federation_simple_search_missing_index_uid() { #[actix_rt::test] async fn simple_search_illegal_index_uid() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); let (response, code) = server .multi_search(json!({"queries": [ @@ -389,12 +361,7 @@ async fn simple_search_illegal_index_uid() { #[actix_rt::test] async fn federation_search_illegal_index_uid() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ @@ -414,29 +381,22 @@ async fn federation_search_illegal_index_uid() { #[actix_rt::test] async fn simple_search_two_indexes() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (add_task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(add_task.uid()).await.succeeded(); + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti"}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid": nested_index.uid, "q": "pésti"}, ]})) .await; snapshot!(code, @"200 OK"); insta::assert_json_snapshot!(response["results"], { "[].processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" [ { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "hits": [ { "title": "Gläss", @@ -454,7 +414,7 @@ async fn simple_search_two_indexes() { "estimatedTotalHits": 1 }, { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "hits": [ { "id": 852, @@ -500,22 +460,14 @@ async fn simple_search_two_indexes() { #[actix_rt::test] async fn federation_two_search_two_indexes() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti"}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid": nested_index.uid, "q": "pésti"}, ]})) .await; snapshot!(code, @"200 OK"); @@ -530,7 +482,7 @@ async fn federation_two_search_two_indexes() { "red" ], "_federation": { - "indexUid": "test", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -551,7 +503,7 @@ async fn federation_two_search_two_indexes() { ], "cattos": "pésti", "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -571,7 +523,7 @@ async fn federation_two_search_two_indexes() { "pestiféré" ], "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.7803030303030303 } @@ -587,36 +539,26 @@ async fn federation_two_search_two_indexes() { #[actix_rt::test] async fn federation_multiple_search_multiple_indexes() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let nested_index = shared_index_with_nested_documents().await; - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("score"); - let documents = SCORE_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let score_index = shared_index_with_score_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid" : "test", "q": "captain"}, - {"indexUid": "nested", "q": "pésti"}, - {"indexUid" : "test", "q": "Escape"}, - {"indexUid": "nested", "q": "jean"}, - {"indexUid": "score", "q": "jean"}, - {"indexUid": "test", "q": "the bat"}, - {"indexUid": "score", "q": "the bat"}, - {"indexUid": "score", "q": "badman returns"}, - {"indexUid" : "score", "q": "batman"}, - {"indexUid": "score", "q": "batman returns"}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid" : index.uid, "q": "captain"}, + {"indexUid": nested_index.uid, "q": "pésti"}, + {"indexUid" : index.uid, "q": "Escape"}, + {"indexUid": nested_index.uid, "q": "jean"}, + {"indexUid": score_index.uid, "q": "jean"}, + {"indexUid": index.uid, "q": "the bat"}, + {"indexUid": score_index.uid, "q": "the bat"}, + {"indexUid": score_index.uid, "q": "badman returns"}, + {"indexUid" : score_index.uid, "q": "batman"}, + {"indexUid": score_index.uid, "q": "batman returns"}, ]})) .await; snapshot!(code, @"200 OK"); @@ -631,7 +573,7 @@ async fn federation_multiple_search_multiple_indexes() { "red" ], "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -652,7 +594,7 @@ async fn federation_multiple_search_multiple_indexes() { ], "cattos": "pésti", "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -661,7 +603,7 @@ async fn federation_multiple_search_multiple_indexes() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 1.0 } @@ -670,7 +612,7 @@ async fn federation_multiple_search_multiple_indexes() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 10, "weightedRankingScore": 1.0 } @@ -683,7 +625,7 @@ async fn federation_multiple_search_multiple_indexes() { "blue" ], "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 } @@ -696,7 +638,7 @@ async fn federation_multiple_search_multiple_indexes() { "red" ], "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 3, "weightedRankingScore": 0.9848484848484848 } @@ -720,7 +662,7 @@ async fn federation_multiple_search_multiple_indexes() { "gomez" ], "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 4, "weightedRankingScore": 0.9848484848484848 } @@ -729,7 +671,7 @@ async fn federation_multiple_search_multiple_indexes() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -738,7 +680,7 @@ async fn federation_multiple_search_multiple_indexes() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -758,7 +700,7 @@ async fn federation_multiple_search_multiple_indexes() { "pestiféré" ], "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.7803030303030303 } @@ -767,7 +709,7 @@ async fn federation_multiple_search_multiple_indexes() { "title": "Badman", "id": "E", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 8, "weightedRankingScore": 0.5 } @@ -780,7 +722,7 @@ async fn federation_multiple_search_multiple_indexes() { "red" ], "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 6, "weightedRankingScore": 0.4166666666666667 } @@ -796,16 +738,12 @@ async fn federation_multiple_search_multiple_indexes() { #[actix_rt::test] async fn search_one_index_doesnt_exist() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass"}, + {"indexUid" : index.uid, "q": "glass"}, {"indexUid": "nested", "q": "pésti"}, ]})) .await; @@ -822,16 +760,12 @@ async fn search_one_index_doesnt_exist() { #[actix_rt::test] async fn federation_one_index_doesnt_exist() { - let server = Server::new().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, + {"indexUid" : index.uid, "q": "glass"}, {"indexUid": "nested", "q": "pésti"}, ]})) .await; @@ -848,7 +782,7 @@ async fn federation_one_index_doesnt_exist() { #[actix_rt::test] async fn search_multiple_indexes_dont_exist() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, code) = server .multi_search(json!({"queries": [ @@ -869,7 +803,7 @@ async fn search_multiple_indexes_dont_exist() { #[actix_rt::test] async fn federation_multiple_indexes_dont_exist() { - let server = Server::new().await; + let server = Server::new_shared(); let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ @@ -892,25 +826,17 @@ async fn federation_multiple_indexes_dont_exist() { #[actix_rt::test] async fn search_one_query_error() { - let server = Server::new().await; - - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass", "facets": ["title"]}, - {"indexUid": "nested", "q": "pésti"}, + {"indexUid" : index.uid, "q": "glass", "facets": ["title"]}, + {"indexUid": nested_index.uid, "q": "pésti"}, ]})) .await; + dbg!(&response); snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { @@ -924,29 +850,21 @@ async fn search_one_query_error() { #[actix_rt::test] async fn federation_one_query_error() { - let server = Server::new().await; + let server = Server::new_shared(); + let index = shared_index_with_documents().await; - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti", "filter": ["title = toto"]}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid": nested_index.uid, "q": "pésti", "filter": ["title = toto"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `nested`: Attribute `title` is not filterable. This index does not have configured filterable attributes.\n1:6 title = toto", + "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `title` is not filterable. This index does not have configured filterable attributes.\n1:6 title = toto", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -956,23 +874,14 @@ async fn federation_one_query_error() { #[actix_rt::test] async fn federation_one_query_sort_error() { - let server = Server::new().await; - - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti", "sort": ["doggos:desc"]}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid": nested_index.uid, "q": "pésti", "sort": ["doggos:desc"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -988,25 +897,17 @@ async fn federation_one_query_sort_error() { #[actix_rt::test] async fn search_multiple_query_errors() { - let server = Server::new().await; - - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass", "facets": ["title"]}, - {"indexUid": "nested", "q": "pésti", "facets": ["doggos"]}, + {"indexUid" : index.uid, "q": "glass", "facets": ["title"]}, + {"indexUid": nested_index.uid, "q": "pésti", "facets": ["doggos"]}, ]})) .await; + dbg!(&response); snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { @@ -1020,23 +921,14 @@ async fn search_multiple_query_errors() { #[actix_rt::test] async fn federation_multiple_query_errors() { - let server = Server::new().await; - - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass", "filter": ["title = toto"]}, - {"indexUid": "nested", "q": "pésti", "filter": ["doggos IN [intel, kefir]"]}, + {"indexUid" : index.uid, "q": "glass", "filter": ["title = toto"]}, + {"indexUid": nested_index.uid, "q": "pésti", "filter": ["doggos IN [intel, kefir]"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -1052,29 +944,20 @@ async fn federation_multiple_query_errors() { #[actix_rt::test] async fn federation_multiple_query_sort_errors() { - let server = Server::new().await; - - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass", "sort": ["title:desc"]}, - {"indexUid": "nested", "q": "pésti", "sort": ["doggos:desc"]}, + {"indexUid" : index.uid, "q": "glass", "sort": ["title:desc"]}, + {"indexUid": nested_index.uid, "q": "pésti", "sort": ["doggos:desc"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: Index `test`: Attribute `title` is not sortable. This index does not have configured sortable attributes.", + "message": "Inside `.queries[0]`: Index `SHARED_DOCUMENTS`: Attribute `title` is not sortable. This index does not have configured sortable attributes.", "code": "invalid_search_sort", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_sort" @@ -1084,30 +967,21 @@ async fn federation_multiple_query_sort_errors() { #[actix_rt::test] async fn federation_multiple_query_errors_interleaved() { - let server = Server::new().await; - - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti", "filter": ["doggos IN [intel, kefir]"]}, - {"indexUid" : "test", "q": "glass", "filter": ["title = toto"]}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid": nested_index.uid, "q": "pésti", "filter": ["doggos IN [intel, kefir]"]}, + {"indexUid" : index.uid, "q": "glass", "filter": ["title = toto"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `nested`: Attribute `doggos` is not filterable. This index does not have configured filterable attributes.\n1:7 doggos IN [intel, kefir]", + "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `doggos` is not filterable. This index does not have configured filterable attributes.\n1:7 doggos IN [intel, kefir]", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -1117,30 +991,21 @@ async fn federation_multiple_query_errors_interleaved() { #[actix_rt::test] async fn federation_multiple_query_sort_errors_interleaved() { - let server = Server::new().await; - - let index = server.index("test"); - - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let server = Server::new_shared(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti", "sort": ["doggos:desc"]}, - {"indexUid" : "test", "q": "glass", "sort": ["title:desc"]}, + {"indexUid" : index.uid, "q": "glass"}, + {"indexUid": nested_index.uid, "q": "pésti", "sort": ["doggos:desc"]}, + {"indexUid" : index.uid, "q": "glass", "sort": ["title:desc"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `nested`: Attribute `doggos` is not sortable. This index does not have configured sortable attributes.", + "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `doggos` is not sortable. This index does not have configured sortable attributes.", "code": "invalid_search_sort", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_sort" @@ -1150,9 +1015,8 @@ async fn federation_multiple_query_sort_errors_interleaved() { #[actix_rt::test] async fn federation_filter() { - let server = Server::new().await; - - let index = server.index("fruits"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = FRUITS_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -1167,12 +1031,12 @@ async fn federation_filter() { let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red", "filter": "BOOST = true", "showRankingScore": true, "federationOptions": {"weight": 3.0}}, - {"indexUid": "fruits", "q": "apple red", "showRankingScore": true}, + {"indexUid" : index.uid, "q": "apple red", "filter": "BOOST = true", "showRankingScore": true, "federationOptions": {"weight": 3.0}}, + {"indexUid": index.uid, "q": "apple red", "showRankingScore": true}, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { @@ -1180,7 +1044,7 @@ async fn federation_filter() { "id": "red-delicious-boosted", "BOOST": true, "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 2.7281746031746033 }, @@ -1191,7 +1055,7 @@ async fn federation_filter() { "id": "green-apple-boosted", "BOOST": true, "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.318181818181818 }, @@ -1201,7 +1065,7 @@ async fn federation_filter() { "name": "Red apple gala", "id": "red-apple-gala", "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.953042328042328 }, @@ -1218,9 +1082,8 @@ async fn federation_filter() { #[actix_rt::test] async fn federation_sort_same_indexes_same_criterion_same_direction() { - let server = Server::new().await; - - let index = server.index("nested"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -1244,12 +1107,12 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { // two identical placeholder search should have all results from first query let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "", "sort": ["mother:asc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { @@ -1268,7 +1131,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { ], "cattos": "pésti", "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1282,7 +1145,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { "enigma" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1303,7 +1166,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { "pestiféré" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1328,7 +1191,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { "gomez" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1345,12 +1208,12 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { // mix and match query let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "pésti", "sort": ["mother:asc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "jean", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "pésti", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "jean", "sort": ["mother:asc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { @@ -1369,7 +1232,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { ], "cattos": "pésti", "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1390,7 +1253,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { "pestiféré" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.7803030303030303 }, @@ -1415,7 +1278,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { "gomez" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 }, @@ -1432,9 +1295,8 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { #[actix_rt::test] async fn federation_sort_same_indexes_same_criterion_opposite_direction() { - let server = Server::new().await; - - let index = server.index("nested"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -1458,14 +1320,14 @@ async fn federation_sort_same_indexes_same_criterion_opposite_direction() { // two identical placeholder search should have all results from first query let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "", "sort": ["mother:asc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "", "sort": ["mother:desc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["mother:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested.rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested.rankingRules[0]`: descending sort rule(s) on field `mother`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `mother`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -1475,14 +1337,14 @@ async fn federation_sort_same_indexes_same_criterion_opposite_direction() { // mix and match query: should be ranked by ranking score let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "pésti", "sort": ["mother:asc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "jean", "sort": ["mother:desc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "pésti", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "jean", "sort": ["mother:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested.rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested.rankingRules[0]`: descending sort rule(s) on field `mother`\n - cannot compare two sort rules in opposite directions\n", + "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `mother`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -1492,9 +1354,8 @@ async fn federation_sort_same_indexes_same_criterion_opposite_direction() { #[actix_rt::test] async fn federation_sort_same_indexes_different_criterion_same_direction() { - let server = Server::new().await; - - let index = server.index("nested"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -1518,12 +1379,12 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { // return mothers and fathers ordered accross fields. let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "", "sort": ["mother:asc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "", "sort": ["father:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["father:asc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { @@ -1542,7 +1403,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { ], "cattos": "pésti", "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1567,7 +1428,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { "gomez" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1581,7 +1442,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { "enigma" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1602,7 +1463,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { "pestiféré" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1619,13 +1480,13 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { // mix and match query: will be sorted across mother and father names let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "pésti", "sort": ["mother:desc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "jean-bap", "sort": ["father:desc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "jea", "sort": ["father:desc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "pésti", "sort": ["mother:desc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "jean-bap", "sort": ["father:desc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "jea", "sort": ["father:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { @@ -1643,7 +1504,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { "pestiféré" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.7803030303030303 }, @@ -1665,7 +1526,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { ], "cattos": "pésti", "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1690,7 +1551,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { "gomez" ], "_federation": { - "indexUid": "nested", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9991181657848324 }, @@ -1707,9 +1568,8 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { #[actix_rt::test] async fn federation_sort_same_indexes_different_criterion_opposite_direction() { - let server = Server::new().await; - - let index = server.index("nested"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -1733,14 +1593,14 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { // two identical placeholder search should have all results from first query let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "", "sort": ["mother:asc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "", "sort": ["father:desc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "", "sort": ["father:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested.rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested.rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -1750,8 +1610,8 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { // mix and match query: should be ranked by ranking score let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "nested", "q": "pésti", "sort": ["mother:asc"], "showRankingScore": true }, - {"indexUid" : "nested", "q": "jean", "sort": ["father:desc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "pésti", "sort": ["mother:asc"], "showRankingScore": true }, + {"indexUid" : index.uid, "q": "jean", "sort": ["father:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -1767,15 +1627,14 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { #[actix_rt::test] async fn federation_sort_different_indexes_same_criterion_same_direction() { - let server = Server::new().await; - - let index = server.index("movies"); + let server = Server::new_shared(); + let movies_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -1788,15 +1647,15 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman"); + let batman_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -1809,24 +1668,24 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_index.wait_task(value.uid()).await.succeeded(); // return titles ordered accross indexes let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { "title": "Badman", "id": "E", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1836,7 +1695,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1846,7 +1705,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1856,7 +1715,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1866,7 +1725,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1880,7 +1739,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1894,7 +1753,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1908,7 +1767,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1922,7 +1781,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1936,7 +1795,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1953,13 +1812,13 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { // mix and match query: will be sorted across indexes let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "batman", "q": "badman returns", "sort": ["title:desc"], "showRankingScore": true }, - {"indexUid" : "movies", "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "the bat", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "badman returns", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "the bat", "sort": ["title:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { @@ -1970,7 +1829,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 }, @@ -1980,7 +1839,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, @@ -1990,7 +1849,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, @@ -2000,7 +1859,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8317901234567902 }, @@ -2010,7 +1869,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.23106060606060605 }, @@ -2020,7 +1879,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Badman", "id": "E", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.5 }, @@ -2037,15 +1896,15 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { #[actix_rt::test] async fn federation_sort_different_ranking_rules() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("movies"); + let movies_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -2058,15 +1917,15 @@ async fn federation_sort_different_ranking_rules() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman"); + let batman_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -2079,24 +1938,24 @@ async fn federation_sort_different_ranking_rules() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_index.wait_task(value.uid()).await.succeeded(); // return titles ordered accross indexes let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { "title": "Badman", "id": "E", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2106,7 +1965,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2116,7 +1975,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2126,7 +1985,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2136,7 +1995,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2150,7 +2009,7 @@ async fn federation_sort_different_ranking_rules() { "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2164,7 +2023,7 @@ async fn federation_sort_different_ranking_rules() { "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2178,7 +2037,7 @@ async fn federation_sort_different_ranking_rules() { "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2192,7 +2051,7 @@ async fn federation_sort_different_ranking_rules() { "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2206,7 +2065,7 @@ async fn federation_sort_different_ranking_rules() { "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2223,15 +2082,15 @@ async fn federation_sort_different_ranking_rules() { // mix and match query: order difficult to understand let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "batman", "q": "badman returns", "sort": ["title:desc"], "showRankingScore": true }, - {"indexUid" : "movies", "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "the bat", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "badman returns", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "the bat", "sort": ["title:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `batman.rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `movies.rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `[uuid].rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2241,15 +2100,15 @@ async fn federation_sort_different_ranking_rules() { #[actix_rt::test] async fn federation_sort_different_indexes_same_criterion_opposite_direction() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("movies"); + let movies_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -2262,15 +2121,15 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman"); + let batman_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -2283,19 +2142,19 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_index.wait_task(value.uid()).await.succeeded(); // all results from query 0 let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "", "sort": ["title:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman.rankingRules[0]`: descending sort rule(s) on field `title`\n 2. `queries[0].sort[0]`, `movies.rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n 2. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2305,15 +2164,15 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { // mix and match query: will be sorted by ranking score let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "batman", "q": "badman returns", "sort": ["title:asc"], "showRankingScore": true }, - {"indexUid" : "movies", "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "the bat", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "badman returns", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "the bat", "sort": ["title:asc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `batman.rankingRules[0]`: ascending sort rule(s) on field `title`\n 2. `queries[1].sort[0]`, `movies.rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2323,15 +2182,15 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { #[actix_rt::test] async fn federation_sort_different_indexes_different_criterion_same_direction() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("movies"); + let movies_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -2344,15 +2203,15 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman"); + let batman_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_index .update_settings(json!({ "sortableAttributes": ["id"], "rankingRules": [ @@ -2365,24 +2224,24 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_index.wait_task(value.uid()).await.succeeded(); // return titles ordered accross indexes let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "", "sort": ["id:asc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "", "sort": ["id:asc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2392,7 +2251,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2402,7 +2261,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2416,7 +2275,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2426,7 +2285,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman", "id": "D", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2436,7 +2295,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Badman", "id": "E", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2450,7 +2309,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2464,7 +2323,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2478,7 +2337,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "red" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2492,7 +2351,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2509,20 +2368,20 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() // mix and match query: will be sorted across indexes and criterion let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "batman", "q": "badman returns", "sort": ["id:desc"], "showRankingScore": true }, - {"indexUid" : "movies", "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "the bat", "sort": ["id:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "badman returns", "sort": ["id:desc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "captain", "sort": ["title:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "the bat", "sort": ["id:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Badman", "id": "E", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.5 }, @@ -2532,7 +2391,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman", "id": "D", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.23106060606060605 }, @@ -2546,7 +2405,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "blue" ], "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 }, @@ -2556,7 +2415,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8317901234567902 }, @@ -2566,7 +2425,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, @@ -2576,7 +2435,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, @@ -2593,15 +2452,15 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() #[actix_rt::test] async fn federation_sort_different_indexes_different_criterion_opposite_direction() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("movies"); + let movies_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies_index .update_settings(json!({ "sortableAttributes": ["title"], "rankingRules": [ @@ -2614,15 +2473,15 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman"); + let batman_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_index .update_settings(json!({ "sortableAttributes": ["id"], "rankingRules": [ @@ -2635,19 +2494,19 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_index.wait_task(value.uid()).await.succeeded(); // all results from query 0 first let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "", "sort": ["id:desc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "", "sort": ["id:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman.rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[0].sort[0]`, `movies.rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2657,15 +2516,15 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio // mix and match query: more or less by ranking score let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "batman", "q": "badman returns", "sort": ["id:desc"], "showRankingScore": true }, - {"indexUid" : "movies", "q": "captain", "sort": ["title:asc"], "showRankingScore": true }, - {"indexUid" : "batman", "q": "the bat", "sort": ["id:desc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "badman returns", "sort": ["id:desc"], "showRankingScore": true }, + {"indexUid" : movies_index.uid, "q": "captain", "sort": ["title:asc"], "showRankingScore": true }, + {"indexUid" : batman_index.uid, "q": "the bat", "sort": ["id:desc"], "showRankingScore": true }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `batman.rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[1].sort[0]`, `movies.rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2675,36 +2534,25 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio #[actix_rt::test] async fn federation_limit_offset() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); + let nested_index = shared_index_with_nested_documents().await; + let score_index = shared_index_with_score_documents().await; - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("score"); - let documents = SCORE_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); { let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -2714,7 +2562,7 @@ async fn federation_limit_offset() { { "title": "Gläss", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -2722,7 +2570,7 @@ async fn federation_limit_offset() { { "id": 852, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -2730,7 +2578,7 @@ async fn federation_limit_offset() { { "title": "Batman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 1.0 } @@ -2738,7 +2586,7 @@ async fn federation_limit_offset() { { "title": "Batman Returns", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 10, "weightedRankingScore": 1.0 } @@ -2746,7 +2594,7 @@ async fn federation_limit_offset() { { "title": "Captain Marvel", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 } @@ -2754,7 +2602,7 @@ async fn federation_limit_offset() { { "title": "Escape Room", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 3, "weightedRankingScore": 0.9848484848484848 } @@ -2762,7 +2610,7 @@ async fn federation_limit_offset() { { "id": 951, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 4, "weightedRankingScore": 0.9848484848484848 } @@ -2770,7 +2618,7 @@ async fn federation_limit_offset() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -2778,7 +2626,7 @@ async fn federation_limit_offset() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -2786,7 +2634,7 @@ async fn federation_limit_offset() { { "id": 654, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.7803030303030303 } @@ -2794,7 +2642,7 @@ async fn federation_limit_offset() { { "title": "Badman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 8, "weightedRankingScore": 0.5 } @@ -2802,7 +2650,7 @@ async fn federation_limit_offset() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 6, "weightedRankingScore": 0.4166666666666667 } @@ -2819,17 +2667,17 @@ async fn federation_limit_offset() { { let (response, code) = server .multi_search(json!({"federation": {"limit": 1}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -2839,7 +2687,7 @@ async fn federation_limit_offset() { { "title": "Gläss", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -2856,17 +2704,17 @@ async fn federation_limit_offset() { { let (response, code) = server .multi_search(json!({"federation": {"offset": 2}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -2876,7 +2724,7 @@ async fn federation_limit_offset() { { "title": "Batman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 1.0 } @@ -2884,7 +2732,7 @@ async fn federation_limit_offset() { { "title": "Batman Returns", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 10, "weightedRankingScore": 1.0 } @@ -2892,7 +2740,7 @@ async fn federation_limit_offset() { { "title": "Captain Marvel", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 } @@ -2900,7 +2748,7 @@ async fn federation_limit_offset() { { "title": "Escape Room", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 3, "weightedRankingScore": 0.9848484848484848 } @@ -2908,7 +2756,7 @@ async fn federation_limit_offset() { { "id": 951, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 4, "weightedRankingScore": 0.9848484848484848 } @@ -2916,7 +2764,7 @@ async fn federation_limit_offset() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -2924,7 +2772,7 @@ async fn federation_limit_offset() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -2932,7 +2780,7 @@ async fn federation_limit_offset() { { "id": 654, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.7803030303030303 } @@ -2940,7 +2788,7 @@ async fn federation_limit_offset() { { "title": "Badman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 8, "weightedRankingScore": 0.5 } @@ -2948,7 +2796,7 @@ async fn federation_limit_offset() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 6, "weightedRankingScore": 0.4166666666666667 } @@ -2965,17 +2813,17 @@ async fn federation_limit_offset() { { let (response, code) = server .multi_search(json!({"federation": {"offset": 12}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -2993,36 +2841,26 @@ async fn federation_limit_offset() { #[actix_rt::test] async fn federation_formatting() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); - let documents = DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); + let nested_index = server.unique_index(); + let score_index = server.unique_index(); - let index = server.index("nested"); - let documents = NESTED_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); - - let index = server.index("score"); - let documents = SCORE_DOCUMENTS.clone(); - let (task, _status_code) = index.add_documents(documents, None).await; - index.wait_task(task.uid()).await.succeeded(); { let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"], "attributesToHighlight": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -3032,7 +2870,7 @@ async fn federation_formatting() { { "title": "Gläss", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -3043,7 +2881,7 @@ async fn federation_formatting() { { "id": 852, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -3051,7 +2889,7 @@ async fn federation_formatting() { { "title": "Batman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 1.0 }, @@ -3062,7 +2900,7 @@ async fn federation_formatting() { { "title": "Batman Returns", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 10, "weightedRankingScore": 1.0 }, @@ -3073,7 +2911,7 @@ async fn federation_formatting() { { "title": "Captain Marvel", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 }, @@ -3084,7 +2922,7 @@ async fn federation_formatting() { { "title": "Escape Room", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 3, "weightedRankingScore": 0.9848484848484848 }, @@ -3095,7 +2933,7 @@ async fn federation_formatting() { { "id": 951, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 4, "weightedRankingScore": 0.9848484848484848 } @@ -3103,7 +2941,7 @@ async fn federation_formatting() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 }, @@ -3114,7 +2952,7 @@ async fn federation_formatting() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 }, @@ -3125,7 +2963,7 @@ async fn federation_formatting() { { "id": 654, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.7803030303030303 } @@ -3133,7 +2971,7 @@ async fn federation_formatting() { { "title": "Badman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 8, "weightedRankingScore": 0.5 }, @@ -3144,7 +2982,7 @@ async fn federation_formatting() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 6, "weightedRankingScore": 0.4166666666666667 }, @@ -3164,17 +3002,17 @@ async fn federation_formatting() { { let (response, code) = server .multi_search(json!({"federation": {"limit": 1}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -3184,7 +3022,7 @@ async fn federation_formatting() { { "title": "Gläss", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -3201,17 +3039,17 @@ async fn federation_formatting() { { let (response, code) = server .multi_search(json!({"federation": {"offset": 2}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -3221,7 +3059,7 @@ async fn federation_formatting() { { "title": "Batman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 1.0 } @@ -3229,7 +3067,7 @@ async fn federation_formatting() { { "title": "Batman Returns", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 10, "weightedRankingScore": 1.0 } @@ -3237,7 +3075,7 @@ async fn federation_formatting() { { "title": "Captain Marvel", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 } @@ -3245,7 +3083,7 @@ async fn federation_formatting() { { "title": "Escape Room", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 3, "weightedRankingScore": 0.9848484848484848 } @@ -3253,7 +3091,7 @@ async fn federation_formatting() { { "id": 951, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 4, "weightedRankingScore": 0.9848484848484848 } @@ -3261,7 +3099,7 @@ async fn federation_formatting() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -3269,7 +3107,7 @@ async fn federation_formatting() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 9, "weightedRankingScore": 0.9848484848484848 } @@ -3277,7 +3115,7 @@ async fn federation_formatting() { { "id": 654, "_federation": { - "indexUid": "nested", + "indexUid": "SHARED_NESTED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.7803030303030303 } @@ -3285,7 +3123,7 @@ async fn federation_formatting() { { "title": "Badman", "_federation": { - "indexUid": "score", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 8, "weightedRankingScore": 0.5 } @@ -3293,7 +3131,7 @@ async fn federation_formatting() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 6, "weightedRankingScore": 0.4166666666666667 } @@ -3310,17 +3148,17 @@ async fn federation_formatting() { { let (response, code) = server .multi_search(json!({"federation": {"offset": 12}, "queries": [ - {"indexUid" : "test", "q": "glass", "attributesToRetrieve": ["title"]}, - {"indexUid" : "test", "q": "captain", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "pésti", "attributesToRetrieve": ["id"]}, - {"indexUid" : "test", "q": "Escape", "attributesToRetrieve": ["title"]}, - {"indexUid": "nested", "q": "jean", "attributesToRetrieve": ["id"]}, - {"indexUid": "score", "q": "jean", "attributesToRetrieve": ["title"]}, - {"indexUid": "test", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "the bat", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "badman returns", "attributesToRetrieve": ["title"]}, - {"indexUid" : "score", "q": "batman", "attributesToRetrieve": ["title"]}, - {"indexUid": "score", "q": "batman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "captain", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "pésti", "attributesToRetrieve": ["id"]}, + {"indexUid" : index.uid, "q": "Escape", "attributesToRetrieve": ["title"]}, + {"indexUid" : nested_index.uid, "q": "jean", "attributesToRetrieve": ["id"]}, + {"indexUid" : score_index.uid, "q": "jean", "attributesToRetrieve": ["title"]}, + {"indexUid" : index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "the bat", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "badman returns", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman", "attributesToRetrieve": ["title"]}, + {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; snapshot!(code, @"200 OK"); @@ -3338,9 +3176,8 @@ async fn federation_formatting() { #[actix_rt::test] async fn federation_invalid_weight() { - let server = Server::new().await; - - let index = server.index("fruits"); + let server = Server::new_shared(); + let index = server.unique_index(); let documents = FRUITS_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -3355,8 +3192,8 @@ async fn federation_invalid_weight() { let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red", "filter": "BOOST = true", "showRankingScore": true, "federationOptions": {"weight": 3.0}}, - {"indexUid": "fruits", "q": "apple red", "showRankingScore": true, "federationOptions": {"weight": -12}}, + {"indexUid" : index.uid, "q": "apple red", "filter": "BOOST = true", "showRankingScore": true, "federationOptions": {"weight": 3.0}}, + {"indexUid": index.uid, "q": "apple red", "showRankingScore": true, "federationOptions": {"weight": -12}}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3372,9 +3209,9 @@ async fn federation_invalid_weight() { #[actix_rt::test] async fn federation_null_weight() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("fruits"); + let index = server.unique_index(); let documents = FRUITS_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -3389,12 +3226,12 @@ async fn federation_null_weight() { let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red", "filter": "BOOST = true", "showRankingScore": true, "federationOptions": {"weight": 3.0}}, - {"indexUid": "fruits", "q": "apple red", "showRankingScore": true, "federationOptions": {"weight": 0.0} }, + {"indexUid" : index.uid, "q": "apple red", "filter": "BOOST = true", "showRankingScore": true, "federationOptions": {"weight": 3.0}}, + {"indexUid": index.uid, "q": "apple red", "showRankingScore": true, "federationOptions": {"weight": 0.0} }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { @@ -3402,7 +3239,7 @@ async fn federation_null_weight() { "id": "red-delicious-boosted", "BOOST": true, "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 2.7281746031746033 }, @@ -3413,7 +3250,7 @@ async fn federation_null_weight() { "id": "green-apple-boosted", "BOOST": true, "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.318181818181818 }, @@ -3423,7 +3260,7 @@ async fn federation_null_weight() { "name": "Red apple gala", "id": "red-apple-gala", "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.0 }, @@ -3440,9 +3277,9 @@ async fn federation_null_weight() { #[actix_rt::test] async fn federation_federated_contains_pagination() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("fruits"); + let index = server.unique_index(); let documents = FRUITS_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -3451,8 +3288,8 @@ async fn federation_federated_contains_pagination() { // fail when a federated query contains "limit" let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red", "limit": 5}, + {"indexUid" : index.uid, "q": "apple red"}, + {"indexUid": index.uid, "q": "apple red", "limit": 5}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3467,8 +3304,8 @@ async fn federation_federated_contains_pagination() { // fail when a federated query contains "offset" let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red", "offset": 5}, + {"indexUid" : index.uid, "q": "apple red"}, + {"indexUid": index.uid, "q": "apple red", "offset": 5}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3483,8 +3320,8 @@ async fn federation_federated_contains_pagination() { // fail when a federated query contains "page" let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red", "page": 2}, + {"indexUid" : index.uid, "q": "apple red"}, + {"indexUid": index.uid, "q": "apple red", "page": 2}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3499,8 +3336,8 @@ async fn federation_federated_contains_pagination() { // fail when a federated query contains "hitsPerPage" let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red", "hitsPerPage": 5}, + {"indexUid" : index.uid, "q": "apple red"}, + {"indexUid": index.uid, "q": "apple red", "hitsPerPage": 5}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3516,9 +3353,9 @@ async fn federation_federated_contains_pagination() { #[actix_rt::test] async fn federation_federated_contains_facets() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("fruits"); + let index = server.unique_index(); let (value, _) = index .update_settings( @@ -3535,8 +3372,8 @@ async fn federation_federated_contains_facets() { // empty facets are actually OK let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red", "facets": []}, + {"indexUid" : index.uid, "q": "apple red"}, + {"indexUid": index.uid, "q": "apple red", "facets": []}, ]})) .await; snapshot!(code, @"200 OK"); @@ -3547,7 +3384,7 @@ async fn federation_federated_contains_facets() { "name": "Red apple gala", "id": "red-apple-gala", "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.953042328042328 } @@ -3557,7 +3394,7 @@ async fn federation_federated_contains_facets() { "id": "red-delicious-boosted", "BOOST": true, "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9093915343915344 } @@ -3567,7 +3404,7 @@ async fn federation_federated_contains_facets() { "id": "green-apple-boosted", "BOOST": true, "_federation": { - "indexUid": "fruits", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.4393939393939394 } @@ -3583,8 +3420,8 @@ async fn federation_federated_contains_facets() { // fails let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red", "facets": ["BOOSTED"]}, + {"indexUid": index.uid, "q": "apple red"}, + {"indexUid": index.uid, "q": "apple red", "facets": ["BOOSTED"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3600,48 +3437,49 @@ async fn federation_federated_contains_facets() { #[actix_rt::test] async fn federation_non_faceted_for_an_index() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("fruits"); + let fruits_index = server.unique_index(); - let (value, _) = index + let (value, _) = fruits_index .update_settings( json!({"searchableAttributes": ["name"], "filterableAttributes": ["BOOST", "id", "name"]}), ) .await; - index.wait_task(value.uid()).await.succeeded(); + fruits_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("fruits-no-name"); + let fruits_no_name_index = server.unique_index(); - let (value, _) = index + let (value, _) = fruits_no_name_index .update_settings( json!({"searchableAttributes": ["name"], "filterableAttributes": ["BOOST", "id"]}), ) .await; - index.wait_task(value.uid()).await.succeeded(); + fruits_no_name_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("fruits-no-facets"); + let fruits_no_facets_index = server.unique_index(); - let (value, _) = index.update_settings(json!({"searchableAttributes": ["name"]})).await; + let (value, _) = + fruits_no_facets_index.update_settings(json!({"searchableAttributes": ["name"]})).await; - index.wait_task(value.uid()).await.succeeded(); + fruits_no_facets_index.wait_task(value.uid()).await.succeeded(); let documents = FRUITS_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = fruits_no_facets_index.add_documents(documents, None).await; + fruits_no_facets_index.wait_task(value.uid()).await.succeeded(); // fails let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "fruits": ["BOOST", "id", "name"], - "fruits-no-name": ["BOOST", "id", "name"], + fruits_index.uid.clone(): ["BOOST", "id", "name"], + fruits_no_name_index.uid.clone(): ["BOOST", "id", "name"], } }, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits-no-name", "q": "apple red"}, + {"indexUid" : fruits_index.uid.clone(), "q": "apple red"}, + {"indexUid": fruits_no_name_index.uid.clone(), "q": "apple red"}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3658,12 +3496,12 @@ async fn federation_non_faceted_for_an_index() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "fruits": ["BOOST", "id", "name"], - "fruits-no-name": ["BOOST", "id", "name"], + fruits_index.uid.clone(): ["BOOST", "id", "name"], + fruits_no_name_index.uid.clone(): ["BOOST", "id", "name"], } }, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red"}, + {"indexUid" : fruits_index.uid.clone(), "q": "apple red"}, + {"indexUid": fruits_index.uid.clone(), "q": "apple red"}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3680,13 +3518,13 @@ async fn federation_non_faceted_for_an_index() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "fruits": ["BOOST", "id", "name"], - "fruits-no-name": ["BOOST", "id"], - "fruits-no-facets": ["BOOST", "id"], + fruits_index.uid.clone(): ["BOOST", "id", "name"], + fruits_no_name_index.uid.clone(): ["BOOST", "id"], + fruits_no_facets_index.uid.clone(): ["BOOST", "id"], } }, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red"}, + {"indexUid" : fruits_index.uid.clone(), "q": "apple red"}, + {"indexUid": fruits_index.uid.clone(), "q": "apple red"}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3704,11 +3542,11 @@ async fn federation_non_faceted_for_an_index() { .multi_search(json!({"federation": { "facetsByIndex": { "zorglub": ["BOOST", "id", "name"], - "fruits": ["BOOST", "id", "name"], + fruits_index.uid.clone(): ["BOOST", "id", "name"], } }, "queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red"}, + {"indexUid" : fruits_index.uid.clone(), "q": "apple red"}, + {"indexUid": fruits_index.uid.clone(), "q": "apple red"}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3724,9 +3562,9 @@ async fn federation_non_faceted_for_an_index() { #[actix_rt::test] async fn federation_non_federated_contains_federation_option() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("fruits"); + let index = server.unique_index(); let documents = FRUITS_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -3735,8 +3573,8 @@ async fn federation_non_federated_contains_federation_option() { // fail when a non-federated query contains "federationOptions" let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "fruits", "q": "apple red"}, - {"indexUid": "fruits", "q": "apple red", "federationOptions": {}}, + {"indexUid" : index.uid.clone(), "q": "apple red"}, + {"indexUid": index.uid.clone(), "q": "apple red", "federationOptions": {}}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -3752,9 +3590,9 @@ async fn federation_non_federated_contains_federation_option() { #[actix_rt::test] async fn federation_vector_single_index() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("vectors"); + let index = server.unique_index(); let (value, _) = index .update_settings(json!({"embedders": { @@ -3778,19 +3616,19 @@ async fn federation_vector_single_index() { // same embedder let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "vectors", "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}}, - {"indexUid": "vectors", "vector": [0.5, 0.5, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}}, + {"indexUid" : index.uid.clone(), "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}}, + {"indexUid": index.uid.clone(), "vector": [0.5, 0.5, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}}, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { "id": "B", "description": "the kitten scratched the beagle", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9870882034301758 } @@ -3799,7 +3637,7 @@ async fn federation_vector_single_index() { "id": "D", "description": "the little boy pets the puppy", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9728479385375975 } @@ -3808,7 +3646,7 @@ async fn federation_vector_single_index() { "id": "C", "description": "the dog had to stay alone today", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 } @@ -3817,7 +3655,7 @@ async fn federation_vector_single_index() { "id": "A", "description": "the dog barks at the cat", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9191691875457764 } @@ -3834,20 +3672,20 @@ async fn federation_vector_single_index() { // distinct embedder let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "vectors", "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}}, + {"indexUid" : index.uid.clone(), "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}}, // joyful and energetic first - {"indexUid": "vectors", "vector": [0.8, 0.6], "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"}}, + {"indexUid": index.uid.clone(), "vector": [0.8, 0.6], "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"}}, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { "id": "D", "description": "the little boy pets the puppy", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.979868710041046 } @@ -3856,7 +3694,7 @@ async fn federation_vector_single_index() { "id": "C", "description": "the dog had to stay alone today", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 } @@ -3865,7 +3703,7 @@ async fn federation_vector_single_index() { "id": "B", "description": "the kitten scratched the beagle", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8601469993591309 } @@ -3874,7 +3712,7 @@ async fn federation_vector_single_index() { "id": "A", "description": "the dog barks at the cat", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8432406187057495 } @@ -3891,21 +3729,21 @@ async fn federation_vector_single_index() { // hybrid search, distinct embedder let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "vectors", "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}, "showRankingScore": true}, + {"indexUid" : index.uid, "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}, "showRankingScore": true}, // joyful and energetic first - {"indexUid": "vectors", "vector": [0.8, 0.6], "q": "beagle", "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"},"showRankingScore": true}, - {"indexUid": "vectors", "q": "dog", "showRankingScore": true}, + {"indexUid": index.uid, "vector": [0.8, 0.6], "q": "beagle", "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"},"showRankingScore": true}, + {"indexUid": index.uid, "q": "dog", "showRankingScore": true}, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { "id": "D", "description": "the little boy pets the puppy", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.979868710041046 }, @@ -3915,7 +3753,7 @@ async fn federation_vector_single_index() { "id": "C", "description": "the dog had to stay alone today", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 }, @@ -3925,7 +3763,7 @@ async fn federation_vector_single_index() { "id": "A", "description": "the dog barks at the cat", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9242424242424242 }, @@ -3935,7 +3773,7 @@ async fn federation_vector_single_index() { "id": "B", "description": "the kitten scratched the beagle", "_federation": { - "indexUid": "vectors", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8601469993591309 }, @@ -3953,11 +3791,11 @@ async fn federation_vector_single_index() { #[actix_rt::test] async fn federation_vector_two_indexes() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("vectors-animal"); + let vectors_animal_index = server.unique_index(); - let (value, _) = index + let (value, _) = vectors_animal_index .update_settings(json!({"embedders": { "animal": { "source": "userProvided", @@ -3965,16 +3803,16 @@ async fn federation_vector_two_indexes() { }, }})) .await; - index.wait_task(value.uid()).await.succeeded(); + vectors_animal_index.wait_task(value.uid()).await.succeeded(); let documents = VECTOR_DOCUMENTS.clone(); - let (value, code) = index.add_documents(documents, None).await; + let (value, code) = vectors_animal_index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - index.wait_task(value.uid()).await.succeeded(); + vectors_animal_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("vectors-sentiment"); + let vectors_sentiment_index = server.unique_index(); - let (value, _) = index + let (value, _) = vectors_sentiment_index .update_settings(json!({"embedders": { "sentiment": { "source": "userProvided", @@ -3982,23 +3820,23 @@ async fn federation_vector_two_indexes() { } }})) .await; - index.wait_task(value.uid()).await.succeeded(); + vectors_sentiment_index.wait_task(value.uid()).await.succeeded(); let documents = VECTOR_DOCUMENTS.clone(); - let (value, code) = index.add_documents(documents, None).await; + let (value, code) = vectors_sentiment_index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - index.wait_task(value.uid()).await.succeeded(); + vectors_sentiment_index.wait_task(value.uid()).await.succeeded(); let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "vectors-animal", "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}, "retrieveVectors": true}, + {"indexUid" : vectors_animal_index.uid, "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}, "retrieveVectors": true}, // joyful and energetic first - {"indexUid": "vectors-sentiment", "vector": [0.8, 0.6], "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"}, "retrieveVectors": true}, - {"indexUid": "vectors-sentiment", "q": "dog", "retrieveVectors": true}, + {"indexUid": vectors_sentiment_index.uid, "vector": [0.8, 0.6], "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"}, "retrieveVectors": true}, + {"indexUid": vectors_sentiment_index.uid, "q": "dog", "retrieveVectors": true}, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -4021,7 +3859,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.979868710041046 } @@ -4046,7 +3884,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9728479385375975 } @@ -4071,7 +3909,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 } @@ -4096,7 +3934,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9242424242424242 } @@ -4121,7 +3959,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9242424242424242 } @@ -4146,7 +3984,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8601469993591309 } @@ -4171,7 +4009,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8432406187057495 } @@ -4196,7 +4034,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.6690993905067444 } @@ -4213,12 +4051,12 @@ async fn federation_vector_two_indexes() { // hybrid search, distinct embedder let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "vectors-animal", "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}, "showRankingScore": true, "retrieveVectors": true}, - {"indexUid": "vectors-sentiment", "vector": [-1, 0.6], "q": "beagle", "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"}, "showRankingScore": true, "retrieveVectors": true,}, + {"indexUid" : vectors_animal_index.uid, "vector": [1.0, 0.0, 0.5], "hybrid": {"semanticRatio": 1.0, "embedder": "animal"}, "showRankingScore": true, "retrieveVectors": true}, + {"indexUid": vectors_sentiment_index.uid, "vector": [-1, 0.6], "q": "beagle", "hybrid": {"semanticRatio": 1.0, "embedder": "sentiment"}, "showRankingScore": true, "retrieveVectors": true,}, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -4241,7 +4079,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9728479385375975 }, @@ -4267,7 +4105,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 }, @@ -4293,7 +4131,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9522157907485962 }, @@ -4319,7 +4157,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.8719604015350342 }, @@ -4345,7 +4183,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8601469993591309 }, @@ -4371,7 +4209,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-animal", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8432406187057495 }, @@ -4397,7 +4235,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.8297949433326721 }, @@ -4423,7 +4261,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.18887794017791748 }, @@ -4441,15 +4279,15 @@ async fn federation_vector_two_indexes() { #[actix_rt::test] async fn federation_facets_different_indexes_same_facet() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("movies"); + let movies_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies_index .update_settings(json!({ "sortableAttributes": ["title"], "filterableAttributes": ["title", "color"], @@ -4463,15 +4301,15 @@ async fn federation_facets_different_indexes_same_facet() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman"); + let batman_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_index .update_settings(json!({ "sortableAttributes": ["title"], "filterableAttributes": ["title"], @@ -4485,15 +4323,15 @@ async fn federation_facets_different_indexes_same_facet() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman-2"); + let batman_2_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_2_index.add_documents(documents, None).await; + batman_2_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_2_index .update_settings(json!({ "sortableAttributes": ["title"], "filterableAttributes": ["title"], @@ -4507,30 +4345,30 @@ async fn federation_facets_different_indexes_same_facet() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_2_index.wait_task(value.uid()).await.succeeded(); // return titles ordered accross indexes let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "movies": ["title", "color"], - "batman": ["title"], - "batman-2": ["title"], + movies_index.uid.clone(): ["title", "color"], + batman_index.uid.clone(): ["title"], + batman_2_index.uid.clone(): ["title"], } }, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman-2", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_2_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4538,7 +4376,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4546,7 +4384,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4554,7 +4392,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4562,7 +4400,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4570,7 +4408,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4578,7 +4416,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4586,7 +4424,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4594,7 +4432,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4602,7 +4440,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4610,7 +4448,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4618,7 +4456,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Escape Room", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4626,7 +4464,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Gläss", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4634,7 +4472,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4642,7 +4480,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Shazam!", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4702,25 +4540,25 @@ async fn federation_facets_different_indexes_same_facet() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "movies": ["title"], - "batman": ["title"], - "batman-2": ["title"] + movies_index.uid.clone(): ["title"], + batman_index.uid.clone(): ["title"], + batman_2_index.uid.clone(): ["title"] }, "mergeFacets": {} }, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman-2", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_2_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4728,7 +4566,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4736,7 +4574,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4744,7 +4582,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4752,7 +4590,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4760,7 +4598,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4768,7 +4606,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4776,7 +4614,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4784,7 +4622,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4792,7 +4630,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4800,7 +4638,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4808,7 +4646,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Escape Room", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4816,7 +4654,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Gläss", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4824,7 +4662,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4832,7 +4670,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Shazam!", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4864,25 +4702,25 @@ async fn federation_facets_different_indexes_same_facet() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "movies": [], - "batman": ["title"], - "batman-2": ["title"] + movies_index.uid.clone(): [], + batman_index.uid.clone(): ["title"], + batman_2_index.uid.clone(): ["title"] } }, "queries": [ - {"indexUid" : "batman", "q": "badman returns", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman-2", "q": "badman returns", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "movies", "q": "captain", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman", "q": "the bat", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_index.uid.clone(), "q": "badman returns", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_2_index.uid.clone(), "q": "badman returns", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies_index.uid.clone(), "q": "captain", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_index.uid.clone(), "q": "the bat", "sort": ["title:desc"], "attributesToRetrieve": ["title"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Captain Marvel", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9848484848484848 } @@ -4890,7 +4728,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 3, "weightedRankingScore": 0.9528218694885362 } @@ -4898,7 +4736,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.7028218694885362 } @@ -4906,7 +4744,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 3, "weightedRankingScore": 0.9528218694885362 } @@ -4914,7 +4752,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.7028218694885362 } @@ -4922,7 +4760,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8317901234567902 } @@ -4930,7 +4768,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.8317901234567902 } @@ -4938,7 +4776,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.23106060606060605 } @@ -4946,7 +4784,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.23106060606060605 } @@ -4954,7 +4792,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.5 } @@ -4962,7 +4800,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "batman-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.5 } @@ -5008,15 +4846,15 @@ async fn federation_facets_different_indexes_same_facet() { #[actix_rt::test] async fn federation_facets_same_indexes() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("doggos"); + let doggos_index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = doggos_index.add_documents(documents, None).await; + doggos_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = doggos_index .update_settings(json!({ "filterableAttributes": ["father", "mother", "doggos.age"], "rankingRules": [ @@ -5029,15 +4867,15 @@ async fn federation_facets_same_indexes() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + doggos_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("doggos-2"); + let doggos2_index = server.unique_index(); let documents = NESTED_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = doggos2_index.add_documents(documents, None).await; + doggos2_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = doggos2_index .update_settings(json!({ "filterableAttributes": ["father", "mother", "doggos.age"], "rankingRules": [ @@ -5050,26 +4888,26 @@ async fn federation_facets_same_indexes() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + doggos2_index.wait_task(value.uid()).await.succeeded(); let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "doggos": ["father", "mother", "doggos.age"] + doggos_index.uid.clone(): ["father", "mother", "doggos.age"] } }, "queries": [ - {"indexUid" : "doggos", "q": "je", "attributesToRetrieve": ["id"] }, - {"indexUid" : "doggos", "q": "michel", "attributesToRetrieve": ["id"] }, + {"indexUid" : doggos_index.uid.clone(), "q": "je", "attributesToRetrieve": ["id"] }, + {"indexUid" : doggos_index.uid.clone(), "q": "michel", "attributesToRetrieve": ["id"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "id": 852, "_federation": { - "indexUid": "doggos", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5077,7 +4915,7 @@ async fn federation_facets_same_indexes() { { "id": 951, "_federation": { - "indexUid": "doggos", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5085,7 +4923,7 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "doggos", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5128,22 +4966,22 @@ async fn federation_facets_same_indexes() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "doggos": ["father", "mother", "doggos.age"], - "doggos-2": ["father", "mother", "doggos.age"] + doggos_index.uid.clone(): ["father", "mother", "doggos.age"], + doggos2_index.uid.clone(): ["father", "mother", "doggos.age"] } }, "queries": [ - {"indexUid" : "doggos", "q": "je", "attributesToRetrieve": ["id"] }, - {"indexUid" : "doggos-2", "q": "michel", "attributesToRetrieve": ["id"] }, + {"indexUid" : doggos_index.uid.clone(), "q": "je", "attributesToRetrieve": ["id"] }, + {"indexUid" : doggos2_index.uid.clone(), "q": "michel", "attributesToRetrieve": ["id"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "id": 852, "_federation": { - "indexUid": "doggos", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5151,7 +4989,7 @@ async fn federation_facets_same_indexes() { { "id": 951, "_federation": { - "indexUid": "doggos", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5159,7 +4997,7 @@ async fn federation_facets_same_indexes() { { "id": 852, "_federation": { - "indexUid": "doggos-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5167,7 +5005,7 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "doggos-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5230,23 +5068,23 @@ async fn federation_facets_same_indexes() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "doggos": ["father", "mother", "doggos.age"], - "doggos-2": ["father", "mother", "doggos.age"] + doggos_index.uid.clone(): ["father", "mother", "doggos.age"], + doggos2_index.uid.clone(): ["father", "mother", "doggos.age"] }, "mergeFacets": {}, }, "queries": [ - {"indexUid" : "doggos", "q": "je", "attributesToRetrieve": ["id"] }, - {"indexUid" : "doggos-2", "q": "michel", "attributesToRetrieve": ["id"] }, + {"indexUid" : doggos_index.uid.clone(), "q": "je", "attributesToRetrieve": ["id"] }, + {"indexUid" : doggos2_index.uid.clone(), "q": "michel", "attributesToRetrieve": ["id"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "id": 852, "_federation": { - "indexUid": "doggos", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5254,7 +5092,7 @@ async fn federation_facets_same_indexes() { { "id": 951, "_federation": { - "indexUid": "doggos", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5262,7 +5100,7 @@ async fn federation_facets_same_indexes() { { "id": 852, "_federation": { - "indexUid": "doggos-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5270,7 +5108,7 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "doggos-2", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5309,15 +5147,15 @@ async fn federation_facets_same_indexes() { #[actix_rt::test] async fn federation_inconsistent_merge_order() { - let server = Server::new().await; + let server = Server::new_shared(); - let index = server.index("movies"); + let movies_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies_index .update_settings(json!({ "sortableAttributes": ["title"], "filterableAttributes": ["title", "color"], @@ -5331,15 +5169,15 @@ async fn federation_inconsistent_merge_order() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("movies-2"); + let movies2_index = server.unique_index(); let documents = DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = movies2_index.add_documents(documents, None).await; + movies2_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = movies2_index .update_settings(json!({ "sortableAttributes": ["title"], "filterableAttributes": ["title", "color"], @@ -5356,15 +5194,15 @@ async fn federation_inconsistent_merge_order() { } })) .await; - index.wait_task(value.uid()).await.succeeded(); + movies2_index.wait_task(value.uid()).await.succeeded(); - let index = server.index("batman"); + let batman_index = server.unique_index(); let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = index.add_documents(documents, None).await; - index.wait_task(value.uid()).await.succeeded(); + let (value, _) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(value.uid()).await.succeeded(); - let (value, _) = index + let (value, _) = batman_index .update_settings(json!({ "sortableAttributes": ["title"], "filterableAttributes": ["title"], @@ -5378,30 +5216,30 @@ async fn federation_inconsistent_merge_order() { ] })) .await; - index.wait_task(value.uid()).await.succeeded(); + batman_index.wait_task(value.uid()).await.succeeded(); // without merging, it works let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "movies": ["title", "color"], - "batman": ["title"], - "movies-2": ["title", "color"], + movies_index.uid.clone(): ["title", "color"], + batman_index.uid.clone(): ["title"], + movies2_index.uid.clone(): ["title", "color"], } }, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "movies-2", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies2_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5409,7 +5247,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5417,7 +5255,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5425,7 +5263,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5433,7 +5271,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5441,7 +5279,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5449,7 +5287,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5457,7 +5295,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5465,7 +5303,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5473,7 +5311,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5481,7 +5319,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5489,7 +5327,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5497,7 +5335,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5505,7 +5343,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5513,7 +5351,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5580,21 +5418,21 @@ async fn federation_inconsistent_merge_order() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "movies": ["title", "color"], - "batman": ["title"], - "movies-2": ["title", "color"], + movies_index.uid.clone(): ["title", "color"], + batman_index.uid.clone(): ["title"], + movies2_index.uid.clone(): ["title", "color"], }, "mergeFacets": {} }, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "movies-2", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies2_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { - "message": "Inside `.federation.facetsByIndex.movies-2`: Inconsistent order for values in facet `color`: index `movies` orders alphabetically, but index `movies-2` orders by count.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `movies-2` used in `.queries[2]`", + "message": "Inside `.federation.facetsByIndex.movies-2`: Inconsistent order for values in facet `color`: index `[uuid]` orders alphabetically, but index `[uuid]` orders by count.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `[uuid]` used in `.queries[2]`", "code": "invalid_multi_search_facet_order", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_facet_order" @@ -5605,27 +5443,27 @@ async fn federation_inconsistent_merge_order() { let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { - "movies": ["title", "color"], - "batman": ["title"], - "movies-2": ["title"], + movies_index.uid.clone(): ["title", "color"], + batman_index.uid.clone(): ["title"], + movies2_index.uid.clone(): ["title"], }, "mergeFacets": { "maxValuesPerFacet": 3, } }, "queries": [ - {"indexUid" : "movies", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "batman", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, - {"indexUid" : "movies-2", "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : batman_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, + {"indexUid" : movies2_index.uid.clone(), "q": "", "sort": ["title:asc"], "attributesToRetrieve": ["title"] }, ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5633,7 +5471,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5641,7 +5479,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5649,7 +5487,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5657,7 +5495,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman", + "indexUid": "[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5665,7 +5503,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5673,7 +5511,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5681,7 +5519,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5689,7 +5527,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5697,7 +5535,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5705,7 +5543,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5713,7 +5551,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5721,7 +5559,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5729,7 +5567,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "movies", + "indexUid": "[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5737,7 +5575,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "movies-2", + "indexUid": "[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } From 34d8a54c4b93e8b424030c1b5156b8fef8cba0f6 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 10 Jun 2025 14:48:59 +0300 Subject: [PATCH 237/292] Fix typos in comments and update assertions Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 8eea27792..d10836177 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -164,7 +164,7 @@ async fn federation_single_search_single_index() { "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -1104,7 +1104,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { .await; index.wait_task(value.uid()).await.succeeded(); - // two identical placeholder search should have all results from first query + // two identical placeholder searches should have all results from the first query let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, @@ -1317,7 +1317,7 @@ async fn federation_sort_same_indexes_same_criterion_opposite_direction() { .await; index.wait_task(value.uid()).await.succeeded(); - // two identical placeholder search should have all results from first query + // two identical placeholder searches should have all results from the first query let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, @@ -1376,7 +1376,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { .await; index.wait_task(value.uid()).await.succeeded(); - // return mothers and fathers ordered accross fields. + // return mothers and fathers ordered across fields. let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, @@ -1590,7 +1590,7 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { .await; index.wait_task(value.uid()).await.succeeded(); - // two identical placeholder search should have all results from first query + // two identical placeholder searches should have all results from the first query let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : index.uid, "q": "", "sort": ["mother:asc"], "showRankingScore": true }, @@ -1670,7 +1670,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { .await; batman_index.wait_task(value.uid()).await.succeeded(); - // return titles ordered accross indexes + // return titles ordered across indexes let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, @@ -1940,7 +1940,7 @@ async fn federation_sort_different_ranking_rules() { .await; batman_index.wait_task(value.uid()).await.succeeded(); - // return titles ordered accross indexes + // return titles ordered across indexes let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, @@ -2226,7 +2226,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() .await; batman_index.wait_task(value.uid()).await.succeeded(); - // return titles ordered accross indexes + // return titles ordered across indexes let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : movies_index.uid, "q": "", "sort": ["title:asc"], "showRankingScore": true }, @@ -3377,7 +3377,7 @@ async fn federation_federated_contains_facets() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" { "hits": [ { @@ -4347,7 +4347,7 @@ async fn federation_facets_different_indexes_same_facet() { .await; batman_2_index.wait_task(value.uid()).await.succeeded(); - // return titles ordered accross indexes + // return titles ordered across indexes let (response, code) = server .multi_search(json!({"federation": { "facetsByIndex": { From 1824fbd1b513c1b00f68f45cebdcd2c6f4252fbe Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 10 Jun 2025 14:49:18 +0300 Subject: [PATCH 238/292] Introduce Index::unique_index_with_prefix(&str) It could be used when we want to see the index name in the assertions, e.g. `movies-[uuid]` Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 16 +++--------- crates/meilisearch/tests/common/server.rs | 10 ++++++++ crates/meilisearch/tests/search/multi/mod.rs | 26 ++++++++++---------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index e9fa94159..7ef72ed06 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -43,20 +43,10 @@ pub fn default_snapshot_settings_for_test<'a>( } } - fn uuid_in_index_uid_redaction(content: Content, _content_path: ContentPath) -> Content { - match &content { - Content::String(s) => match uuid::Uuid::parse_str(s) { - Ok(_) => Content::String("[uuid]".to_owned()), - Err(_) => content, - }, - _ => content, - } - } - settings.add_dynamic_redaction(".message", uuid_in_message_redaction); - settings.add_dynamic_redaction(".error.message", uuid_in_message_redaction); - settings.add_dynamic_redaction(".indexUid", uuid_in_index_uid_redaction); - settings.add_dynamic_redaction(".**.indexUid", uuid_in_index_uid_redaction); + settings.add_dynamic_redaction(".**.message", uuid_in_message_redaction); + settings.add_dynamic_redaction(".indexUid", uuid_in_message_redaction); + settings.add_dynamic_redaction(".**.indexUid", uuid_in_message_redaction); let test_name = test_name.strip_suffix("::{{closure}}").unwrap_or(test_name); let test_name = test_name.rsplit("::").next().unwrap().to_owned(); diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 431972983..fecdc5f16 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -347,6 +347,16 @@ impl Server { } } + pub fn unique_index_with_prefix(&self, prefix: &str) -> Index<'_> { + let uuid = Uuid::new_v4(); + Index { + uid: format!("{prefix}-{}", uuid.to_string()), + service: &self.service, + encoder: Encoder::Plain, + marker: PhantomData, + } + } + pub fn unique_index_with_encoder(&self, encoder: Encoder) -> Index<'_> { let uuid = Uuid::new_v4(); Index { uid: uuid.to_string(), service: &self.service, encoder, marker: PhantomData } diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index d10836177..3914e7c9d 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -1628,7 +1628,7 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { #[actix_rt::test] async fn federation_sort_different_indexes_same_criterion_same_direction() { let server = Server::new_shared(); - let movies_index = server.unique_index(); + let movies_index = server.unique_index_with_prefix("movies"); let documents = DOCUMENTS.clone(); let (value, _) = movies_index.add_documents(documents, None).await; @@ -1649,7 +1649,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { .await; movies_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index(); + let batman_index = server.unique_index_with_prefix("batman"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_index.add_documents(documents, None).await; @@ -1678,14 +1678,14 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" { "hits": [ { "title": "Badman", "id": "E", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1695,7 +1695,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1705,7 +1705,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1715,7 +1715,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1725,7 +1725,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1739,7 +1739,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1753,7 +1753,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1767,7 +1767,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1781,7 +1781,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -1795,7 +1795,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, From ae115cee7853c60d00b498b3a06feaf28508d7aa Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 13:51:04 +0200 Subject: [PATCH 239/292] Make clippy happy --- crates/meilisearch/src/routes/chats/chat_completions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index bf336f224..f65c958ee 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -310,7 +310,7 @@ async fn non_streamed_chat( index_scheduler.features().check_chat_completions("using the /chats chat completions route")?; return Err(ResponseError::from_msg( - format!("Non-streamed chat completions is not implemented"), + "Non-streamed chat completions is not implemented".to_string(), Code::UnimplementedNonStreamingChatCompletions, )); From b32e30ad27f25159c6ecfc7ec259764090d54675 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 14:02:43 +0200 Subject: [PATCH 240/292] Make the chat setting db name a const --- crates/index-scheduler/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 3ad342bea..3a2bea40b 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -77,6 +77,7 @@ use crate::utils::clamp_to_page_size; pub(crate) type BEI128 = I128; const TASK_SCHEDULER_SIZE_THRESHOLD_PERCENT_INT: u64 = 40; +const CHAT_SETTINGS_DB_NAME: &str = "chat-settings"; #[derive(Debug)] pub struct IndexSchedulerOptions { @@ -279,7 +280,7 @@ impl IndexScheduler { let features = features::FeatureData::new(&env, &mut wtxn, options.instance_features)?; let queue = Queue::new(&env, &mut wtxn, &options)?; let index_mapper = IndexMapper::new(&env, &mut wtxn, &options, budget)?; - let chat_settings = env.create_database(&mut wtxn, Some("chat-settings"))?; + let chat_settings = env.create_database(&mut wtxn, Some(CHAT_SETTINGS_DB_NAME))?; wtxn.commit()?; // allow unreachable_code to get rids of the warning in the case of a test build. From bbe802c6565d55c02c816512e67dd27807ce885e Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 14:03:05 +0200 Subject: [PATCH 241/292] Remove the write txn method from the index scheduler --- crates/index-scheduler/src/lib.rs | 32 +++++++++---------- .../src/routes/chats/chat_completions.rs | 7 ++-- crates/meilisearch/src/routes/chats/mod.rs | 4 +-- .../meilisearch/src/routes/chats/settings.rs | 15 +++------ 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 3a2bea40b..639facd44 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -56,7 +56,7 @@ use meilisearch_types::features::{ }; use meilisearch_types::heed::byteorder::BE; use meilisearch_types::heed::types::{DecodeIgnore, SerdeJson, Str, I128}; -use meilisearch_types::heed::{self, Database, Env, RoTxn, RwTxn, WithoutTls}; +use meilisearch_types::heed::{self, Database, Env, RoTxn, WithoutTls}; use meilisearch_types::milli::index::IndexEmbeddingConfig; use meilisearch_types::milli::update::IndexerConfig; use meilisearch_types::milli::vector::{Embedder, EmbedderOptions, EmbeddingConfigs}; @@ -311,11 +311,7 @@ impl IndexScheduler { Ok(this) } - pub fn write_txn(&self) -> Result { - self.env.write_txn().map_err(|e| e.into()) - } - - pub fn read_txn(&self) -> Result> { + fn read_txn(&self) -> Result> { self.env.read_txn().map_err(|e| e.into()) } @@ -901,8 +897,9 @@ impl IndexScheduler { res.map(EmbeddingConfigs::new) } - pub fn chat_settings(&self, rtxn: &RoTxn, uid: &str) -> Result> { - self.chat_settings.get(rtxn, uid).map_err(Into::into) + pub fn chat_settings(&self, uid: &str) -> Result> { + let rtxn = self.env.read_txn()?; + self.chat_settings.get(&rtxn, uid).map_err(Into::into) } /// Return true if chat workspace exists. @@ -911,17 +908,18 @@ impl IndexScheduler { Ok(self.chat_settings.remap_data_type::().get(&rtxn, name)?.is_some()) } - pub fn put_chat_settings( - &self, - wtxn: &mut RwTxn, - uid: &str, - settings: &ChatCompletionSettings, - ) -> Result<()> { - self.chat_settings.put(wtxn, uid, settings).map_err(Into::into) + pub fn put_chat_settings(&self, uid: &str, settings: &ChatCompletionSettings) -> Result<()> { + let mut wtxn = self.env.write_txn()?; + self.chat_settings.put(&mut wtxn, uid, settings)?; + wtxn.commit()?; + Ok(()) } - pub fn delete_chat_settings(&self, wtxn: &mut RwTxn, uid: &str) -> Result { - self.chat_settings.delete(wtxn, uid).map_err(Into::into) + pub fn delete_chat_settings(&self, uid: &str) -> Result { + let mut wtxn = self.env.write_txn()?; + let deleted = self.chat_settings.delete(&mut wtxn, uid)?; + wtxn.commit()?; + Ok(deleted) } } diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index f65c958ee..786398cf7 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -315,8 +315,7 @@ async fn non_streamed_chat( )); let filters = index_scheduler.filters(); - let rtxn = index_scheduler.read_txn()?; - let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid).unwrap() { + let chat_settings = match index_scheduler.chat_settings(workspace_uid).unwrap() { Some(settings) => settings, None => { return Err(ResponseError::from_msg( @@ -413,8 +412,7 @@ async fn streamed_chat( index_scheduler.features().check_chat_completions("using the /chats chat completions route")?; let filters = index_scheduler.filters(); - let rtxn = index_scheduler.read_txn()?; - let chat_settings = match index_scheduler.chat_settings(&rtxn, workspace_uid)? { + let chat_settings = match index_scheduler.chat_settings(workspace_uid)? { Some(settings) => settings, None => { return Err(ResponseError::from_msg( @@ -423,7 +421,6 @@ async fn streamed_chat( )) } }; - drop(rtxn); let config = Config::new(&chat_settings); let auth_token = extract_token_from_request(&req)?.unwrap().to_string(); diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 7a868fd45..c381a20c1 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -72,10 +72,8 @@ pub async fn delete_chat( ) -> Result { index_scheduler.features().check_chat_completions("deleting a chat")?; - let mut wtxn = index_scheduler.write_txn()?; let workspace_uid = workspace_uid.into_inner(); - if index_scheduler.delete_chat_settings(&mut wtxn, &workspace_uid)? { - wtxn.commit()?; + if index_scheduler.delete_chat_settings(&workspace_uid)? { Ok(HttpResponse::NoContent().finish()) } else { Err(ResponseError::from_msg(format!("chat {workspace_uid} not found"), Code::ChatNotFound)) diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index ab696f68a..cd1ce5767 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -42,8 +42,7 @@ async fn get_settings( let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here ??? - let rtxn = index_scheduler.read_txn()?; - let mut settings = match index_scheduler.chat_settings(&rtxn, &workspace_uid)? { + let mut settings = match index_scheduler.chat_settings(&workspace_uid)? { Some(settings) => settings, None => { return Err(ResponseError::from_msg( @@ -68,8 +67,7 @@ async fn patch_settings( let ChatsParam { workspace_uid } = chats_param.into_inner(); // TODO do a spawn_blocking here - let mut wtxn = index_scheduler.write_txn()?; - let old_settings = index_scheduler.chat_settings(&wtxn, &workspace_uid)?.unwrap_or_default(); + let old_settings = index_scheduler.chat_settings(&workspace_uid)?.unwrap_or_default(); let prompts = match new.prompts { Setting::Set(new_prompts) => DbChatCompletionPrompts { @@ -147,8 +145,7 @@ async fn patch_settings( // ); settings.validate()?; - index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &settings)?; - wtxn.commit()?; + index_scheduler.put_chat_settings(&workspace_uid, &settings)?; settings.hide_secrets(); @@ -165,11 +162,9 @@ async fn reset_settings( index_scheduler.features().check_chat_completions("using the /chats/settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); - let mut wtxn = index_scheduler.write_txn()?; - if index_scheduler.chat_settings(&wtxn, &workspace_uid)?.is_some() { + if index_scheduler.chat_settings(&workspace_uid)?.is_some() { let settings = Default::default(); - index_scheduler.put_chat_settings(&mut wtxn, &workspace_uid, &settings)?; - wtxn.commit()?; + index_scheduler.put_chat_settings(&workspace_uid, &settings)?; Ok(HttpResponse::Ok().json(settings)) } else { Err(ResponseError::from_msg( From 4352a924d7a9cc35a4581caf1436dcb39729a2f0 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 14:05:02 +0200 Subject: [PATCH 242/292] Remove useless filters parameter --- crates/index-scheduler/src/lib.rs | 1 - crates/meilisearch/src/routes/chats/mod.rs | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/crates/index-scheduler/src/lib.rs b/crates/index-scheduler/src/lib.rs index 639facd44..505ce23f8 100644 --- a/crates/index-scheduler/src/lib.rs +++ b/crates/index-scheduler/src/lib.rs @@ -553,7 +553,6 @@ impl IndexScheduler { /// And a `Vec` of the workspace_uids pub fn paginated_chat_workspace_uids( &self, - _filters: &meilisearch_auth::AuthFilter, from: usize, limit: usize, ) -> Result<(usize, Vec)> { diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index c381a20c1..4985deb39 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -114,12 +114,8 @@ pub async fn list_workspaces( index_scheduler.features().check_chat_completions("listing the chats")?; debug!(parameters = ?paginate, "List chat workspaces"); - let filters = index_scheduler.filters(); - let (total, workspaces) = index_scheduler.paginated_chat_workspace_uids( - filters, - *paginate.offset, - *paginate.limit, - )?; + let (total, workspaces) = + index_scheduler.paginated_chat_workspace_uids(*paginate.offset, *paginate.limit)?; let workspaces = workspaces.into_iter().map(|uid| ChatWorkspaceView { uid }).collect::>(); let ret = paginate.as_pagination().format_with(total, workspaces); From 7c1b15fd06914c72411dea799dcfcb9705fb3e0a Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 14:05:35 +0200 Subject: [PATCH 243/292] Remove useless liquid dependency for Meilisearch --- Cargo.lock | 1 - crates/meilisearch/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a3942d5b..93921bb99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3762,7 +3762,6 @@ dependencies = [ "itertools 0.14.0", "jsonwebtoken", "lazy_static", - "liquid", "manifest-dir-macros", "maplit", "meili-snap", diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index a40b63a24..c75b55bc2 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -49,7 +49,6 @@ is-terminal = "0.4.13" itertools = "0.14.0" jsonwebtoken = "9.3.0" lazy_static = "1.5.0" -liquid = "0.26.9" meilisearch-auth = { path = "../meilisearch-auth" } meilisearch-types = { path = "../meilisearch-types" } mimalloc = { version = "0.1.43", default-features = false } From 32207f9f1987b8af71b7b519a27a216764eca96f Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 14:07:53 +0200 Subject: [PATCH 244/292] Rename the error code about ranking score threshold --- crates/milli/src/index.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index 6ff972ae0..9936e9b0c 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -1971,7 +1971,7 @@ pub struct SearchParameters { } #[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Deserr, ToSchema)] -#[deserr(try_from(f64) = TryFrom::try_from -> InvalidSearchRankingScoreThreshold)] +#[deserr(try_from(f64) = TryFrom::try_from -> InvalidSettingsRankingScoreThreshold)] pub struct RankingScoreThreshold(f64); impl RankingScoreThreshold { @@ -1981,11 +1981,11 @@ impl RankingScoreThreshold { } impl TryFrom for RankingScoreThreshold { - type Error = InvalidSearchRankingScoreThreshold; + type Error = InvalidSettingsRankingScoreThreshold; fn try_from(value: f64) -> StdResult { if !(0.0..=1.0).contains(&value) { - Err(InvalidSearchRankingScoreThreshold) + Err(InvalidSettingsRankingScoreThreshold) } else { Ok(RankingScoreThreshold(value)) } @@ -1993,11 +1993,11 @@ impl TryFrom for RankingScoreThreshold { } #[derive(Debug)] -pub struct InvalidSearchRankingScoreThreshold; +pub struct InvalidSettingsRankingScoreThreshold; -impl Error for InvalidSearchRankingScoreThreshold {} +impl Error for InvalidSettingsRankingScoreThreshold {} -impl fmt::Display for InvalidSearchRankingScoreThreshold { +impl fmt::Display for InvalidSettingsRankingScoreThreshold { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, From c60d11fb424516efe84d9b5654cedb4437f5dfba Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 14:56:13 +0200 Subject: [PATCH 245/292] Clean up the prompts --- crates/meilisearch-types/src/features.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 1cb0fa244..651077484 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -8,7 +8,7 @@ pub const DEFAULT_CHAT_SYSTEM_PROMPT: &str = "You are a highly capable research pub const DEFAULT_CHAT_SEARCH_DESCRIPTION_PROMPT: &str = "Search the database for relevant JSON documents using an optional query."; pub const DEFAULT_CHAT_SEARCH_Q_PARAM_PROMPT: &str = "The search query string used to find relevant documents in the index. This should contain keywords or phrases that best represent what the user is looking for. More specific queries will yield more precise results."; -pub const DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT: &str = "The name of the index to search within. An index is a collection of documents organized for search. Selecting the right index ensures the most relevant results for the user query. You have access to two indexes: movies, steam. The movies index contains movies with overviews. The steam index contains steam games from the Steam platform with their prices"; +pub const DEFAULT_CHAT_SEARCH_INDEX_UID_PARAM_PROMPT: &str = "The name of the index to search within. An index is a collection of documents organized for search. Selecting the right index ensures the most relevant results for the user query."; #[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)] #[serde(rename_all = "camelCase", default)] From 6a683975bfb91cb3973c950fb20e086d58f2344e Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Tue, 10 Jun 2025 16:58:48 +0300 Subject: [PATCH 246/292] More fixes of the tests Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 20 + crates/meilisearch/tests/common/server.rs | 2 +- crates/meilisearch/tests/search/multi/mod.rs | 625 +++++++++---------- 3 files changed, 333 insertions(+), 314 deletions(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 7ef72ed06..fcd17879e 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -43,10 +43,30 @@ pub fn default_snapshot_settings_for_test<'a>( } } + fn uuid_in_json_key_redaction(content: Content, _content_path: ContentPath) -> Content { + match content { + Content::Map(map) => { + let new_map = map.iter() + .map(|(key, value)| { + match key { + Content::String(s) => { + let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "[uuid]"); + (Content::String(uuid_replaced.to_string()), value.clone()) + } + _ => (key.clone(), value.clone()), + } + }).collect(); + Content::Map(new_map) + } + _ => content, + } + } + settings.add_dynamic_redaction(".message", uuid_in_message_redaction); settings.add_dynamic_redaction(".**.message", uuid_in_message_redaction); settings.add_dynamic_redaction(".indexUid", uuid_in_message_redaction); settings.add_dynamic_redaction(".**.indexUid", uuid_in_message_redaction); + settings.add_dynamic_redaction(".facetsByIndex", uuid_in_json_key_redaction); let test_name = test_name.strip_suffix("::{{closure}}").unwrap_or(test_name); let test_name = test_name.rsplit("::").next().unwrap().to_owned(); diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index fecdc5f16..1f5688a02 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -350,7 +350,7 @@ impl Server { pub fn unique_index_with_prefix(&self, prefix: &str) -> Index<'_> { let uuid = Uuid::new_v4(); Index { - uid: format!("{prefix}-{}", uuid.to_string()), + uid: format!("{prefix}-{}", uuid), service: &self.service, encoder: Encoder::Plain, marker: PhantomData, diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 3914e7c9d..d75a09364 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -29,10 +29,10 @@ async fn federation_empty_list() { let (response, code) = server.multi_search(json!({"federation": {}, "queries": []})).await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, {".processingTimeMs" => "[time]"}), @r###" + snapshot!(response, @r###" { "hits": [], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 0 @@ -100,7 +100,7 @@ async fn simple_search_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response["results"], { "[].processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response["results"], { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" [ { "indexUid": "SHARED_DOCUMENTS", @@ -115,7 +115,7 @@ async fn simple_search_single_index() { } ], "query": "glass", - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 1 @@ -133,7 +133,7 @@ async fn simple_search_single_index() { } ], "query": "captain", - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 1 @@ -153,7 +153,7 @@ async fn federation_single_search_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -170,7 +170,7 @@ async fn federation_single_search_single_index() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 1 @@ -192,7 +192,7 @@ async fn federation_multiple_search_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -241,7 +241,7 @@ async fn federation_multiple_search_single_index() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 5 @@ -261,7 +261,7 @@ async fn federation_two_search_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -291,7 +291,7 @@ async fn federation_two_search_single_index() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 2 @@ -309,7 +309,7 @@ async fn simple_search_missing_index_uid() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, @r###" + snapshot!(response, @r###" { "message": "Missing field `indexUid` inside `.queries[0]`", "code": "missing_index_uid", @@ -329,7 +329,7 @@ async fn federation_simple_search_missing_index_uid() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, @r###" + snapshot!(response, @r###" { "message": "Missing field `indexUid` inside `.queries[0]`", "code": "missing_index_uid", @@ -349,7 +349,7 @@ async fn simple_search_illegal_index_uid() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, @r###" + snapshot!(response, @r###" { "message": "Invalid value at `.queries[0].indexUid`: `hé` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_), and can not be more than 512 bytes.", "code": "invalid_index_uid", @@ -369,7 +369,7 @@ async fn federation_search_illegal_index_uid() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, @r###" + snapshot!(response, @r###" { "message": "Invalid value at `.queries[0].indexUid`: `hé` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_), and can not be more than 512 bytes.", "code": "invalid_index_uid", @@ -393,7 +393,7 @@ async fn simple_search_two_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response["results"], { "[].processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response["results"], { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" [ { "indexUid": "SHARED_DOCUMENTS", @@ -408,7 +408,7 @@ async fn simple_search_two_indexes() { } ], "query": "glass", - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 1 @@ -449,7 +449,7 @@ async fn simple_search_two_indexes() { } ], "query": "pésti", - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 2 @@ -471,7 +471,7 @@ async fn federation_two_search_two_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -482,7 +482,7 @@ async fn federation_two_search_two_indexes() { "red" ], "_federation": { - "indexUid": "SHARED_NESTED_DOCUMENTS", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -529,7 +529,7 @@ async fn federation_two_search_two_indexes() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 3 @@ -562,7 +562,7 @@ async fn federation_multiple_search_multiple_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -728,7 +728,7 @@ async fn federation_multiple_search_multiple_indexes() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 12 @@ -832,15 +832,14 @@ async fn search_one_query_error() { let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : index.uid, "q": "glass", "facets": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "facets": ["color"]}, {"indexUid": nested_index.uid, "q": "pésti"}, ]})) .await; - dbg!(&response); snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: Invalid facet distribution: Attribute `title` is not filterable. This index does not have configured filterable attributes.", + "message": "Inside `.queries[0]`: Invalid facet distribution: Attribute `color` is not filterable. Available filterable attributes patterns are: `id, title`.", "code": "invalid_search_facets", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_facets" @@ -864,7 +863,7 @@ async fn federation_one_query_error() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `title` is not filterable. This index does not have configured filterable attributes.\n1:6 title = toto", + "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `title` is not filterable. Available filterable attribute patterns are: `cattos`, `doggos`, `father`.\n1:6 title = toto", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -884,6 +883,7 @@ async fn federation_one_query_sort_error() { {"indexUid": nested_index.uid, "q": "pésti", "sort": ["doggos:desc"]}, ]})) .await; + dbg!(&response); snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { @@ -903,15 +903,14 @@ async fn search_multiple_query_errors() { let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : index.uid, "q": "glass", "facets": ["title"]}, + {"indexUid" : index.uid, "q": "glass", "facets": ["color"]}, {"indexUid": nested_index.uid, "q": "pésti", "facets": ["doggos"]}, ]})) .await; - dbg!(&response); snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: Invalid facet distribution: Attribute `title` is not filterable. This index does not have configured filterable attributes.", + "message": "Inside `.queries[0]`: Invalid facet distribution: Attribute `color` is not filterable. Available filterable attributes patterns are: `id, title`.", "code": "invalid_search_facets", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_facets" @@ -927,14 +926,14 @@ async fn federation_multiple_query_errors() { let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : index.uid, "q": "glass", "filter": ["title = toto"]}, - {"indexUid": nested_index.uid, "q": "pésti", "filter": ["doggos IN [intel, kefir]"]}, + {"indexUid" : index.uid, "q": "glass", "filter": ["color = toto"]}, + {"indexUid": nested_index.uid, "q": "pésti", "filter": ["mother IN [intel, kefir]"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: Index `test`: Attribute `title` is not filterable. This index does not have configured filterable attributes.\n1:6 title = toto", + "message": "Inside `.queries[0]`: Index `SHARED_DOCUMENTS`: Attribute `color` is not filterable. Available filterable attribute patterns are: `id`, `title`.\n1:6 color = toto", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -950,14 +949,14 @@ async fn federation_multiple_query_sort_errors() { let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : index.uid, "q": "glass", "sort": ["title:desc"]}, + {"indexUid" : index.uid, "q": "glass", "sort": ["color:desc"]}, {"indexUid": nested_index.uid, "q": "pésti", "sort": ["doggos:desc"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: Index `SHARED_DOCUMENTS`: Attribute `title` is not sortable. This index does not have configured sortable attributes.", + "message": "Inside `.queries[0]`: Index `SHARED_DOCUMENTS`: Attribute `color` is not sortable. Available sortable attributes are: `id, title`.", "code": "invalid_search_sort", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_sort" @@ -974,14 +973,14 @@ async fn federation_multiple_query_errors_interleaved() { let (response, code) = server .multi_search(json!({"queries": [ {"indexUid" : index.uid, "q": "glass"}, - {"indexUid": nested_index.uid, "q": "pésti", "filter": ["doggos IN [intel, kefir]"]}, + {"indexUid": nested_index.uid, "q": "pésti", "filter": ["mother IN [intel, kefir]"]}, {"indexUid" : index.uid, "q": "glass", "filter": ["title = toto"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `doggos` is not filterable. This index does not have configured filterable attributes.\n1:7 doggos IN [intel, kefir]", + "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `mother` is not filterable. Available filterable attribute patterns are: `cattos`, `doggos`, `father`.\n1:7 mother IN [intel, kefir]", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -998,14 +997,14 @@ async fn federation_multiple_query_sort_errors_interleaved() { let (response, code) = server .multi_search(json!({"queries": [ {"indexUid" : index.uid, "q": "glass"}, - {"indexUid": nested_index.uid, "q": "pésti", "sort": ["doggos:desc"]}, + {"indexUid": nested_index.uid, "q": "pésti", "sort": ["mother:desc"]}, {"indexUid" : index.uid, "q": "glass", "sort": ["title:desc"]}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `doggos` is not sortable. This index does not have configured sortable attributes.", + "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `mother` is not sortable. Available sortable attributes are: `doggos`.", "code": "invalid_search_sort", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_sort" @@ -1036,7 +1035,7 @@ async fn federation_filter() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(response, @r###" { "hits": [ { @@ -1072,7 +1071,7 @@ async fn federation_filter() { "_rankingScore": 0.953042328042328 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 3 @@ -1112,7 +1111,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -1198,7 +1197,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { "_rankingScore": 1.0 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 4 @@ -1213,7 +1212,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -1285,7 +1284,7 @@ async fn federation_sort_same_indexes_same_criterion_same_direction() { "_rankingScore": 0.9848484848484848 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 3 @@ -1325,7 +1324,7 @@ async fn federation_sort_same_indexes_same_criterion_opposite_direction() { ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `mother`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", @@ -1342,7 +1341,7 @@ async fn federation_sort_same_indexes_same_criterion_opposite_direction() { ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `mother`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", @@ -1384,7 +1383,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -1470,7 +1469,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { "_rankingScore": 1.0 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 4 @@ -1486,7 +1485,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -1558,7 +1557,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { "_rankingScore": 0.9991181657848324 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 3 @@ -1569,7 +1568,7 @@ async fn federation_sort_same_indexes_different_criterion_same_direction() { #[actix_rt::test] async fn federation_sort_same_indexes_different_criterion_opposite_direction() { let server = Server::new_shared(); - let index = server.unique_index(); + let index = server.unique_index_with_prefix("nested"); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -1598,9 +1597,9 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested-[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested-[uuid].rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -1615,9 +1614,9 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested.rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested.rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n", + "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested-[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested.rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -1678,7 +1677,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -1802,7 +1801,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "_rankingScore": 1.0 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 10 @@ -1818,7 +1817,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -1829,7 +1828,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 }, @@ -1839,7 +1838,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, @@ -1849,7 +1848,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, @@ -1859,7 +1858,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8317901234567902 }, @@ -1869,7 +1868,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.23106060606060605 }, @@ -1879,14 +1878,14 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { "title": "Badman", "id": "E", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.5 }, "_rankingScore": 0.5 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 6 @@ -1898,7 +1897,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { async fn federation_sort_different_ranking_rules() { let server = Server::new_shared(); - let movies_index = server.unique_index(); + let movies_index = server.unique_index_with_prefix("movies"); let documents = DOCUMENTS.clone(); let (value, _) = movies_index.add_documents(documents, None).await; @@ -1919,7 +1918,7 @@ async fn federation_sort_different_ranking_rules() { .await; movies_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index(); + let batman_index = server.unique_index_with_prefix("batman"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_index.add_documents(documents, None).await; @@ -1948,14 +1947,14 @@ async fn federation_sort_different_ranking_rules() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "title": "Badman", "id": "E", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1965,7 +1964,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1975,7 +1974,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1985,7 +1984,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1995,7 +1994,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2009,7 +2008,7 @@ async fn federation_sort_different_ranking_rules() { "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2023,7 +2022,7 @@ async fn federation_sort_different_ranking_rules() { "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2037,7 +2036,7 @@ async fn federation_sort_different_ranking_rules() { "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2051,7 +2050,7 @@ async fn federation_sort_different_ranking_rules() { "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2065,14 +2064,14 @@ async fn federation_sort_different_ranking_rules() { "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, "_rankingScore": 1.0 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 10 @@ -2088,9 +2087,9 @@ async fn federation_sort_different_ranking_rules() { ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `[uuid].rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `batman-[uuid].rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2102,7 +2101,7 @@ async fn federation_sort_different_ranking_rules() { async fn federation_sort_different_indexes_same_criterion_opposite_direction() { let server = Server::new_shared(); - let movies_index = server.unique_index(); + let movies_index = server.unique_index_with_prefix("movies"); let documents = DOCUMENTS.clone(); let (value, _) = movies_index.add_documents(documents, None).await; @@ -2123,7 +2122,7 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { .await; movies_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index(); + let batman_index = server.unique_index_with_prefix("batman"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_index.add_documents(documents, None).await; @@ -2152,9 +2151,9 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n 2. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman-[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n 2. `queries[0].sort[0]`, `batman-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2170,7 +2169,7 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", @@ -2184,7 +2183,7 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { async fn federation_sort_different_indexes_different_criterion_same_direction() { let server = Server::new_shared(); - let movies_index = server.unique_index(); + let movies_index = server.unique_index_with_prefix("movies"); let documents = DOCUMENTS.clone(); let (value, _) = movies_index.add_documents(documents, None).await; @@ -2205,7 +2204,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() .await; movies_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index(); + let batman_index = server.unique_index_with_prefix("batman"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_index.add_documents(documents, None).await; @@ -2234,14 +2233,14 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2251,7 +2250,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2261,7 +2260,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2275,7 +2274,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2285,7 +2284,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman", "id": "D", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2295,7 +2294,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Badman", "id": "E", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2309,7 +2308,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2323,7 +2322,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2337,7 +2336,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "red" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, @@ -2351,14 +2350,14 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 }, "_rankingScore": 1.0 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 10 @@ -2374,14 +2373,14 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "title": "Badman", "id": "E", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.5 }, @@ -2391,7 +2390,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman", "id": "D", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.23106060606060605 }, @@ -2405,7 +2404,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "blue" ], "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9848484848484848 }, @@ -2415,7 +2414,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8317901234567902 }, @@ -2425,7 +2424,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, @@ -2435,14 +2434,14 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9528218694885362 }, "_rankingScore": 0.9528218694885362 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 6 @@ -2454,7 +2453,7 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() async fn federation_sort_different_indexes_different_criterion_opposite_direction() { let server = Server::new_shared(); - let movies_index = server.unique_index(); + let movies_index = server.unique_index_with_prefix("movies"); let documents = DOCUMENTS.clone(); let (value, _) = movies_index.add_documents(documents, None).await; @@ -2475,7 +2474,7 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio .await; movies_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index(); + let batman_index = server.unique_index_with_prefix("batman"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_index.add_documents(documents, None).await; @@ -2504,9 +2503,9 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[0].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman-[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[0].sort[0]`, `batman-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2522,7 +2521,7 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", @@ -2535,7 +2534,7 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio #[actix_rt::test] async fn federation_limit_offset() { let server = Server::new_shared(); - let index = server.unique_index(); + let index = shared_index_with_documents().await; let nested_index = shared_index_with_nested_documents().await; let score_index = shared_index_with_score_documents().await; @@ -2555,8 +2554,9 @@ async fn federation_limit_offset() { {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; + dbg!(&response); snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -2656,7 +2656,7 @@ async fn federation_limit_offset() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 12 @@ -2681,7 +2681,7 @@ async fn federation_limit_offset() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -2693,7 +2693,7 @@ async fn federation_limit_offset() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 1, "offset": 0, "estimatedTotalHits": 12 @@ -2718,7 +2718,7 @@ async fn federation_limit_offset() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -2802,7 +2802,7 @@ async fn federation_limit_offset() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 2, "estimatedTotalHits": 12 @@ -2827,10 +2827,10 @@ async fn federation_limit_offset() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" { "hits": [], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 12, "estimatedTotalHits": 12 @@ -2842,10 +2842,9 @@ async fn federation_limit_offset() { #[actix_rt::test] async fn federation_formatting() { let server = Server::new_shared(); - let index = server.unique_index(); - - let nested_index = server.unique_index(); - let score_index = server.unique_index(); + let index = shared_index_with_documents().await; + let nested_index = shared_index_with_nested_documents().await; + let score_index = shared_index_with_score_documents().await; { let (response, code) = server @@ -2864,7 +2863,7 @@ async fn federation_formatting() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -2991,7 +2990,7 @@ async fn federation_formatting() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 12 @@ -3016,7 +3015,7 @@ async fn federation_formatting() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -3028,7 +3027,7 @@ async fn federation_formatting() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 1, "offset": 0, "estimatedTotalHits": 12 @@ -3053,7 +3052,7 @@ async fn federation_formatting() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -3137,7 +3136,7 @@ async fn federation_formatting() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 2, "estimatedTotalHits": 12 @@ -3162,10 +3161,10 @@ async fn federation_formatting() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }, @r###" + snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" { "hits": [], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 12, "estimatedTotalHits": 12 @@ -3197,7 +3196,7 @@ async fn federation_invalid_weight() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(response, @r###" { "message": "Invalid value at `.queries[1].federationOptions.weight`: the value of `weight` is invalid, expected a positive float (>= 0.0).", "code": "invalid_multi_search_weight", @@ -3211,7 +3210,7 @@ async fn federation_invalid_weight() { async fn federation_null_weight() { let server = Server::new_shared(); - let index = server.unique_index(); + let index = server.unique_index_with_prefix("fruits"); let documents = FRUITS_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -3231,7 +3230,7 @@ async fn federation_null_weight() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -3239,7 +3238,7 @@ async fn federation_null_weight() { "id": "red-delicious-boosted", "BOOST": true, "_federation": { - "indexUid": "[uuid]", + "indexUid": "fruits-[uuid]", "queriesPosition": 0, "weightedRankingScore": 2.7281746031746033 }, @@ -3250,7 +3249,7 @@ async fn federation_null_weight() { "id": "green-apple-boosted", "BOOST": true, "_federation": { - "indexUid": "[uuid]", + "indexUid": "fruits-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.318181818181818 }, @@ -3260,14 +3259,14 @@ async fn federation_null_weight() { "name": "Red apple gala", "id": "red-apple-gala", "_federation": { - "indexUid": "[uuid]", + "indexUid": "fruits-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.0 }, "_rankingScore": 0.953042328042328 } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 3 @@ -3279,7 +3278,7 @@ async fn federation_null_weight() { async fn federation_federated_contains_pagination() { let server = Server::new_shared(); - let index = server.unique_index(); + let index = server.unique_index_with_prefix("fruits"); let documents = FRUITS_DOCUMENTS.clone(); let (value, _) = index.add_documents(documents, None).await; @@ -3293,7 +3292,7 @@ async fn federation_federated_contains_pagination() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(response, @r###" { "message": "Inside `.queries[1]`: Using pagination options is not allowed in federated queries.\n - Hint: remove `limit` from query #1 or remove `federation` from the request\n - Hint: pass `federation.limit` and `federation.offset` for pagination in federated search", "code": "invalid_multi_search_query_pagination", @@ -3309,7 +3308,7 @@ async fn federation_federated_contains_pagination() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(response, @r###" { "message": "Inside `.queries[1]`: Using pagination options is not allowed in federated queries.\n - Hint: remove `offset` from query #1 or remove `federation` from the request\n - Hint: pass `federation.limit` and `federation.offset` for pagination in federated search", "code": "invalid_multi_search_query_pagination", @@ -3325,7 +3324,7 @@ async fn federation_federated_contains_pagination() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(response, @r###" { "message": "Inside `.queries[1]`: Using pagination options is not allowed in federated queries.\n - Hint: remove `page` from query #1 or remove `federation` from the request\n - Hint: pass `federation.limit` and `federation.offset` for pagination in federated search", "code": "invalid_multi_search_query_pagination", @@ -3341,7 +3340,7 @@ async fn federation_federated_contains_pagination() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(response, @r###" { "message": "Inside `.queries[1]`: Using pagination options is not allowed in federated queries.\n - Hint: remove `hitsPerPage` from query #1 or remove `federation` from the request\n - Hint: pass `federation.limit` and `federation.offset` for pagination in federated search", "code": "invalid_multi_search_query_pagination", @@ -3355,7 +3354,7 @@ async fn federation_federated_contains_pagination() { async fn federation_federated_contains_facets() { let server = Server::new_shared(); - let index = server.unique_index(); + let index = server.unique_index_with_prefix("fruits"); let (value, _) = index .update_settings( @@ -3377,14 +3376,14 @@ async fn federation_federated_contains_facets() { ]})) .await; snapshot!(code, @"200 OK"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]", ".**.indexUid" => "[uuid]" }, @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "name": "Red apple gala", "id": "red-apple-gala", "_federation": { - "indexUid": "[uuid]", + "indexUid": "fruits-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.953042328042328 } @@ -3394,7 +3393,7 @@ async fn federation_federated_contains_facets() { "id": "red-delicious-boosted", "BOOST": true, "_federation": { - "indexUid": "[uuid]", + "indexUid": "fruits-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9093915343915344 } @@ -3404,13 +3403,13 @@ async fn federation_federated_contains_facets() { "id": "green-apple-boosted", "BOOST": true, "_federation": { - "indexUid": "[uuid]", + "indexUid": "fruits-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.4393939393939394 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 3 @@ -3425,7 +3424,7 @@ async fn federation_federated_contains_facets() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response), @r###" { "message": "Inside `.queries[1]`: Using facet options is not allowed in federated queries.\n - Hint: remove `facets` from query #1 or remove `federation` from the request\n - Hint: pass `federation.facetsByIndex.fruits: [\"BOOSTED\"]` for facets in federated search", "code": "invalid_multi_search_query_facets", @@ -3439,7 +3438,7 @@ async fn federation_federated_contains_facets() { async fn federation_non_faceted_for_an_index() { let server = Server::new_shared(); - let fruits_index = server.unique_index(); + let fruits_index = server.unique_index_with_prefix("fruits"); let (value, _) = fruits_index .update_settings( @@ -3449,7 +3448,7 @@ async fn federation_non_faceted_for_an_index() { fruits_index.wait_task(value.uid()).await.succeeded(); - let fruits_no_name_index = server.unique_index(); + let fruits_no_name_index = server.unique_index_with_prefix("fruits-no-name"); let (value, _) = fruits_no_name_index .update_settings( @@ -3459,7 +3458,7 @@ async fn federation_non_faceted_for_an_index() { fruits_no_name_index.wait_task(value.uid()).await.succeeded(); - let fruits_no_facets_index = server.unique_index(); + let fruits_no_facets_index = server.unique_index_with_prefix("fruits-no-facets"); let (value, _) = fruits_no_facets_index.update_settings(json!({"searchableAttributes": ["name"]})).await; @@ -3483,9 +3482,9 @@ async fn federation_non_faceted_for_an_index() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.federation.facetsByIndex.fruits-no-name`: Invalid facet distribution: Attribute `name` is not filterable. Available filterable attributes patterns are: `BOOST, id`.\n - Note: index `fruits-no-name` used in `.queries[1]`", + "message": "Inside `.federation.facetsByIndex.fruits-no-name-[uuid]`: Invalid facet distribution: Attribute `name` is not filterable. Available filterable attributes patterns are: `BOOST, id`.\n - Note: index `fruits-no-name-[uuid]` used in `.queries[1]`", "code": "invalid_multi_search_facets", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_facets" @@ -3505,9 +3504,9 @@ async fn federation_non_faceted_for_an_index() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.federation.facetsByIndex.fruits-no-name`: Invalid facet distribution: Attribute `name` is not filterable. Available filterable attributes patterns are: `BOOST, id`.\n - Note: index `fruits-no-name` is not used in queries", + "message": "Inside `.federation.facetsByIndex.fruits-no-name-[uuid]`: Invalid facet distribution: Attribute `name` is not filterable. Available filterable attributes patterns are: `BOOST, id`.\n - Note: index `fruits-no-name-[uuid]` is not used in queries", "code": "invalid_multi_search_facets", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_facets" @@ -3528,9 +3527,9 @@ async fn federation_non_faceted_for_an_index() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r#" + snapshot!(json_string!(response), @r#" { - "message": "Inside `.federation.facetsByIndex.fruits-no-facets`: Invalid facet distribution: Attributes `BOOST, id` are not filterable. This index does not have configured filterable attributes.\n - Note: index `fruits-no-facets` is not used in queries", + "message": "Inside `.federation.facetsByIndex.fruits-no-facets-[uuid]`: Invalid facet distribution: Attributes `BOOST, id` are not filterable. This index does not have configured filterable attributes.\n - Note: index `fruits-no-facets-[uuid]` is not used in queries", "code": "invalid_multi_search_facets", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_facets" @@ -3550,7 +3549,7 @@ async fn federation_non_faceted_for_an_index() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(response, @r###" { "message": "Inside `.federation.facetsByIndex.zorglub`: Index `zorglub` not found.\n - Note: index `zorglub` is not used in queries", "code": "index_not_found", @@ -3578,7 +3577,7 @@ async fn federation_non_federated_contains_federation_option() { ]})) .await; snapshot!(code, @"400 Bad Request"); - insta::assert_json_snapshot!(response, { ".processingTimeMs" => "[time]" }, @r###" + snapshot!(response, @r###" { "message": "Inside `.queries[1]`: Using `federationOptions` is not allowed in a non-federated search.\n - Hint: remove `federationOptions` from query #1 or add `federation` to the request.", "code": "invalid_multi_search_federation_options", @@ -3621,7 +3620,7 @@ async fn federation_vector_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -3661,7 +3660,7 @@ async fn federation_vector_single_index() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 4, @@ -3678,7 +3677,7 @@ async fn federation_vector_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -3718,7 +3717,7 @@ async fn federation_vector_single_index() { } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 4, @@ -3736,7 +3735,7 @@ async fn federation_vector_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -3780,7 +3779,7 @@ async fn federation_vector_single_index() { "_rankingScore": "[score]" } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 4, @@ -3793,7 +3792,7 @@ async fn federation_vector_single_index() { async fn federation_vector_two_indexes() { let server = Server::new_shared(); - let vectors_animal_index = server.unique_index(); + let vectors_animal_index = server.unique_index_with_prefix("vectors-animal"); let (value, _) = vectors_animal_index .update_settings(json!({"embedders": { @@ -3810,7 +3809,7 @@ async fn federation_vector_two_indexes() { snapshot!(code, @"202 Accepted"); vectors_animal_index.wait_task(value.uid()).await.succeeded(); - let vectors_sentiment_index = server.unique_index(); + let vectors_sentiment_index = server.unique_index_with_prefix("vectors-sentiment"); let (value, _) = vectors_sentiment_index .update_settings(json!({"embedders": { @@ -3836,7 +3835,7 @@ async fn federation_vector_two_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -3859,7 +3858,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.979868710041046 } @@ -3884,7 +3883,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9728479385375975 } @@ -3909,7 +3908,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 } @@ -3934,7 +3933,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9242424242424242 } @@ -3959,7 +3958,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9242424242424242 } @@ -3984,7 +3983,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8601469993591309 } @@ -4009,7 +4008,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8432406187057495 } @@ -4034,13 +4033,13 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.6690993905067444 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 8, @@ -4056,7 +4055,7 @@ async fn federation_vector_two_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]", ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -4079,7 +4078,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9728479385375975 }, @@ -4105,7 +4104,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 }, @@ -4131,7 +4130,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9522157907485962 }, @@ -4157,7 +4156,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.8719604015350342 }, @@ -4183,7 +4182,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8601469993591309 }, @@ -4209,7 +4208,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8432406187057495 }, @@ -4235,7 +4234,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.8297949433326721 }, @@ -4261,14 +4260,14 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "[uuid]", + "indexUid": "vectors-sentiment-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.18887794017791748 }, "_rankingScore": "[score]" } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 8, @@ -4281,7 +4280,7 @@ async fn federation_vector_two_indexes() { async fn federation_facets_different_indexes_same_facet() { let server = Server::new_shared(); - let movies_index = server.unique_index(); + let movies_index = server.unique_index_with_prefix("movies"); let documents = DOCUMENTS.clone(); let (value, _) = movies_index.add_documents(documents, None).await; @@ -4303,7 +4302,7 @@ async fn federation_facets_different_indexes_same_facet() { .await; movies_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index(); + let batman_index = server.unique_index_with_prefix("batman"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_index.add_documents(documents, None).await; @@ -4325,7 +4324,7 @@ async fn federation_facets_different_indexes_same_facet() { .await; batman_index.wait_task(value.uid()).await.succeeded(); - let batman_2_index = server.unique_index(); + let batman_2_index = server.unique_index_with_prefix("batman-2"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_2_index.add_documents(documents, None).await; @@ -4362,13 +4361,13 @@ async fn federation_facets_different_indexes_same_facet() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4376,7 +4375,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4384,7 +4383,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4392,7 +4391,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4400,7 +4399,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4408,7 +4407,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4416,7 +4415,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4424,7 +4423,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4432,7 +4431,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4440,7 +4439,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4448,7 +4447,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Captain Marvel", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4456,7 +4455,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Escape Room", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4464,7 +4463,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Gläss", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4472,7 +4471,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4480,18 +4479,18 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Shazam!", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 15, "facetsByIndex": { - "batman": { + "batman-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4503,7 +4502,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "batman-2": { + "batman-2-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4515,7 +4514,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "movies": { + "movies-[uuid]": { "distribution": { "color": { "blue": 3, @@ -4552,13 +4551,13 @@ async fn federation_facets_different_indexes_same_facet() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4566,7 +4565,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4574,7 +4573,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4582,7 +4581,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4590,7 +4589,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4598,7 +4597,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4606,7 +4605,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4614,7 +4613,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4622,7 +4621,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -4630,7 +4629,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4638,7 +4637,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Captain Marvel", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4646,7 +4645,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Escape Room", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4654,7 +4653,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Gläss", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4662,7 +4661,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -4670,13 +4669,13 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Shazam!", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 15, @@ -4714,13 +4713,13 @@ async fn federation_facets_different_indexes_same_facet() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "title": "Captain Marvel", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 2, "weightedRankingScore": 0.9848484848484848 } @@ -4728,7 +4727,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 3, "weightedRankingScore": 0.9528218694885362 } @@ -4736,7 +4735,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.7028218694885362 } @@ -4744,7 +4743,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 3, "weightedRankingScore": 0.9528218694885362 } @@ -4752,7 +4751,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.7028218694885362 } @@ -4760,7 +4759,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8317901234567902 } @@ -4768,7 +4767,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.8317901234567902 } @@ -4776,7 +4775,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.23106060606060605 } @@ -4784,7 +4783,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.23106060606060605 } @@ -4792,7 +4791,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.5 } @@ -4800,18 +4799,18 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.5 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 11, "facetsByIndex": { - "batman": { + "batman-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4823,7 +4822,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "batman-2": { + "batman-2-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4835,7 +4834,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "movies": { + "movies-[uuid]": { "distribution": {}, "stats": {} } @@ -4848,7 +4847,7 @@ async fn federation_facets_different_indexes_same_facet() { async fn federation_facets_same_indexes() { let server = Server::new_shared(); - let doggos_index = server.unique_index(); + let doggos_index = server.unique_index_with_prefix("doggos"); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = doggos_index.add_documents(documents, None).await; @@ -4869,7 +4868,7 @@ async fn federation_facets_same_indexes() { .await; doggos_index.wait_task(value.uid()).await.succeeded(); - let doggos2_index = server.unique_index(); + let doggos2_index = server.unique_index_with_prefix("doggos-2"); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = doggos2_index.add_documents(documents, None).await; @@ -4901,13 +4900,13 @@ async fn federation_facets_same_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "id": 852, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -4915,7 +4914,7 @@ async fn federation_facets_same_indexes() { { "id": 951, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -4923,18 +4922,18 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 3, "facetsByIndex": { - "doggos": { + "doggos-[uuid]": { "distribution": { "doggos.age": { "2": 1, @@ -4975,13 +4974,13 @@ async fn federation_facets_same_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { "hits": [ { "id": 852, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -4989,7 +4988,7 @@ async fn federation_facets_same_indexes() { { "id": 951, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -4997,7 +4996,7 @@ async fn federation_facets_same_indexes() { { "id": 852, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5005,18 +5004,18 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 4, "facetsByIndex": { - "doggos": { + "doggos-[uuid]": { "distribution": { "doggos.age": { "2": 1, @@ -5040,7 +5039,7 @@ async fn federation_facets_same_indexes() { } } }, - "doggos-2": { + "doggos-2-[uuid]": { "distribution": { "doggos.age": { "2": 1, @@ -5078,13 +5077,13 @@ async fn federation_facets_same_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { "hits": [ { "id": 852, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5092,7 +5091,7 @@ async fn federation_facets_same_indexes() { { "id": 951, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9621212121212122 } @@ -5100,7 +5099,7 @@ async fn federation_facets_same_indexes() { { "id": 852, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5108,13 +5107,13 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "[uuid]", + "indexUid": "doggos-2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 4, @@ -5149,7 +5148,7 @@ async fn federation_facets_same_indexes() { async fn federation_inconsistent_merge_order() { let server = Server::new_shared(); - let movies_index = server.unique_index(); + let movies_index = server.unique_index_with_prefix("movies"); let documents = DOCUMENTS.clone(); let (value, _) = movies_index.add_documents(documents, None).await; @@ -5171,7 +5170,7 @@ async fn federation_inconsistent_merge_order() { .await; movies_index.wait_task(value.uid()).await.succeeded(); - let movies2_index = server.unique_index(); + let movies2_index = server.unique_index_with_prefix("movies-2"); let documents = DOCUMENTS.clone(); let (value, _) = movies2_index.add_documents(documents, None).await; @@ -5196,7 +5195,7 @@ async fn federation_inconsistent_merge_order() { .await; movies2_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index(); + let batman_index = server.unique_index_with_prefix("batman"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_index.add_documents(documents, None).await; @@ -5233,13 +5232,13 @@ async fn federation_inconsistent_merge_order() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5247,7 +5246,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5255,7 +5254,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5263,7 +5262,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5271,7 +5270,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5279,7 +5278,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5287,7 +5286,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5295,7 +5294,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5303,7 +5302,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5311,7 +5310,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5319,7 +5318,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5327,7 +5326,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5335,7 +5334,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5343,7 +5342,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5351,18 +5350,18 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 15, "facetsByIndex": { - "batman": { + "batman-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -5374,7 +5373,7 @@ async fn federation_inconsistent_merge_order() { }, "stats": {} }, - "movies": { + "movies-[uuid]": { "distribution": { "color": { "blue": 3, @@ -5392,7 +5391,7 @@ async fn federation_inconsistent_merge_order() { }, "stats": {} }, - "movies-2": { + "movies-2-[uuid]": { "distribution": { "color": { "red": 3, @@ -5430,9 +5429,9 @@ async fn federation_inconsistent_merge_order() { ]})) .await; snapshot!(code, @"400 Bad Request"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { - "message": "Inside `.federation.facetsByIndex.movies-2`: Inconsistent order for values in facet `color`: index `[uuid]` orders alphabetically, but index `[uuid]` orders by count.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `[uuid]` used in `.queries[2]`", + "message": "Inside `.federation.facetsByIndex.movies-2-[uuid]`: Inconsistent order for values in facet `color`: index `movies-[uuid]` orders alphabetically, but index `movies-2-[uuid]` orders by count.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `movies-2-[uuid]` used in `.queries[2]`", "code": "invalid_multi_search_facet_order", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_facet_order" @@ -5457,13 +5456,13 @@ async fn federation_inconsistent_merge_order() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".processingTimeMs" => "[time]" }), @r###" + snapshot!(json_string!(response), @r###" { "hits": [ { "title": "Badman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5471,7 +5470,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5479,7 +5478,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman Returns", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5487,7 +5486,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5495,7 +5494,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "[uuid]", + "indexUid": "batman-[uuid]", "queriesPosition": 1, "weightedRankingScore": 1.0 } @@ -5503,7 +5502,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5511,7 +5510,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5519,7 +5518,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5527,7 +5526,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5535,7 +5534,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5543,7 +5542,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5551,7 +5550,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5559,7 +5558,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5567,7 +5566,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-[uuid]", "queriesPosition": 0, "weightedRankingScore": 1.0 } @@ -5575,13 +5574,13 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "[uuid]", + "indexUid": "movies-2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } } ], - "processingTimeMs": "[time]", + "processingTimeMs": "[duration]", "limit": 20, "offset": 0, "estimatedTotalHits": 15, From 28e6adc435ccda4dc5a0b2608736b95f290aca5b Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:16:11 +0200 Subject: [PATCH 247/292] Remove the SearchQuery Default impl and change the From impl --- crates/meilisearch/src/search/mod.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/crates/meilisearch/src/search/mod.rs b/crates/meilisearch/src/search/mod.rs index 27369591b..5e543c53f 100644 --- a/crates/meilisearch/src/search/mod.rs +++ b/crates/meilisearch/src/search/mod.rs @@ -57,7 +57,7 @@ pub const DEFAULT_HIGHLIGHT_PRE_TAG: fn() -> String = || "".to_string(); pub const DEFAULT_HIGHLIGHT_POST_TAG: fn() -> String = || "".to_string(); pub const DEFAULT_SEMANTIC_RATIO: fn() -> SemanticRatio = || SemanticRatio(0.5); -#[derive(Clone, PartialEq, Deserr, ToSchema)] +#[derive(Clone, Default, PartialEq, Deserr, ToSchema)] #[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct SearchQuery { #[deserr(default, error = DeserrJsonError)] @@ -145,19 +145,9 @@ impl From for SearchQuery { matching_strategy: matching_strategy.map(MatchingStrategy::from).unwrap_or_default(), attributes_to_search_on, ranking_score_threshold: ranking_score_threshold.map(RankingScoreThreshold::from), - ..Default::default() - } - } -} - -impl Default for SearchQuery { - fn default() -> Self { - SearchQuery { q: None, vector: None, - hybrid: None, offset: DEFAULT_SEARCH_OFFSET(), - limit: DEFAULT_SEARCH_LIMIT(), page: None, hits_per_page: None, attributes_to_retrieve: None, @@ -169,15 +159,10 @@ impl Default for SearchQuery { show_ranking_score: false, show_ranking_score_details: false, filter: None, - sort: None, - distinct: None, facets: None, highlight_pre_tag: DEFAULT_HIGHLIGHT_PRE_TAG(), highlight_post_tag: DEFAULT_HIGHLIGHT_POST_TAG(), crop_marker: DEFAULT_CROP_MARKER(), - matching_strategy: Default::default(), - attributes_to_search_on: None, - ranking_score_threshold: None, locales: None, } } From 34d572e3e580ee472c5a7ce8bdadd8e78980128e Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:17:41 +0200 Subject: [PATCH 248/292] Reove useless commented code --- crates/milli/src/update/chat.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/milli/src/update/chat.rs b/crates/milli/src/update/chat.rs index c52ede029..2f364894d 100644 --- a/crates/milli/src/update/chat.rs +++ b/crates/milli/src/update/chat.rs @@ -97,14 +97,6 @@ pub struct ChatSearchParams { #[schema(value_type = Option)] pub limit: Setting, - // #[serde(default, skip_serializing_if = "Setting::is_not_set")] - // #[deserr(default)] - // pub attributes_to_retrieve: Option>, - - // #[serde(default, skip_serializing_if = "Setting::is_not_set")] - // #[deserr(default)] - // pub filter: Option, - // #[serde(default, skip_serializing_if = "Setting::is_not_set")] #[deserr(default)] #[schema(value_type = Option>)] From 5ceb3c6a10dbd3e296f823a872cf01ebf0b5398d Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:27:18 +0200 Subject: [PATCH 249/292] Report an error when the document template max bytes is zero --- crates/meilisearch-types/src/error.rs | 1 + crates/milli/src/error.rs | 2 ++ crates/milli/src/update/settings.rs | 11 +++++++---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index bdf9bb162..077600a8e 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -447,6 +447,7 @@ impl ErrorCode for milli::Error { | UserError::InvalidSettingsDimensions { .. } | UserError::InvalidUrl { .. } | UserError::InvalidSettingsDocumentTemplateMaxBytes { .. } + | UserError::InvalidChatSettingsDocumentTemplateMaxBytes | UserError::InvalidPrompt(_) | UserError::InvalidDisableBinaryQuantization { .. } | UserError::InvalidSourceForNested { .. } diff --git a/crates/milli/src/error.rs b/crates/milli/src/error.rs index e129a31a0..2136ec97e 100644 --- a/crates/milli/src/error.rs +++ b/crates/milli/src/error.rs @@ -386,6 +386,8 @@ and can not be more than 511 bytes.", .document_id.to_string() DocumentEditionRuntimeError(Box), #[error("Document edition runtime error encountered while compiling the function: {0}")] DocumentEditionCompilationError(rhai::ParseError), + #[error("`.chat.documentTemplateMaxBytes`: `documentTemplateMaxBytes` cannot be zero")] + InvalidChatSettingsDocumentTemplateMaxBytes, #[error("{0}")] DocumentEmbeddingError(String), } diff --git a/crates/milli/src/update/settings.rs b/crates/milli/src/update/settings.rs index ae46cb5d9..05607d7a5 100644 --- a/crates/milli/src/update/settings.rs +++ b/crates/milli/src/update/settings.rs @@ -19,7 +19,7 @@ use crate::attribute_patterns::PatternMatch; use crate::constants::RESERVED_GEO_FIELD_NAME; use crate::criterion::Criterion; use crate::disabled_typos_terms::DisabledTyposTerms; -use crate::error::UserError; +use crate::error::UserError::{self, InvalidChatSettingsDocumentTemplateMaxBytes}; use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder}; use crate::filterable_attributes_rules::match_faceted_field; use crate::index::{ @@ -1249,7 +1249,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { Ok(()) } - fn update_chat_config(&mut self) -> heed::Result { + fn update_chat_config(&mut self) -> Result { match &mut self.chat { Setting::Set(ChatSettings { description: new_description, @@ -1273,7 +1273,10 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { Setting::NotSet => prompt.template.clone(), }, max_bytes: match new_document_template_max_bytes { - Setting::Set(m) => NonZeroUsize::new(*m), + Setting::Set(m) => Some( + NonZeroUsize::new(*m) + .ok_or(InvalidChatSettingsDocumentTemplateMaxBytes)?, + ), Setting::Reset => Some(default_max_bytes()), Setting::NotSet => prompt.max_bytes, }, @@ -1347,7 +1350,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { Ok(true) } - Setting::Reset => self.index.delete_chat_config(self.wtxn), + Setting::Reset => self.index.delete_chat_config(self.wtxn).map_err(Into::into), Setting::NotSet => Ok(false), } } From ab0eba2f72018e48fae3de31d29cf653ac2be851 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:31:58 +0200 Subject: [PATCH 250/292] Remove useless double check --- crates/meilisearch/src/routes/indexes/settings.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/meilisearch/src/routes/indexes/settings.rs b/crates/meilisearch/src/routes/indexes/settings.rs index d91c3cd35..a4b7a5219 100644 --- a/crates/meilisearch/src/routes/indexes/settings.rs +++ b/crates/meilisearch/src/routes/indexes/settings.rs @@ -569,10 +569,6 @@ pub async fn update_all( debug!(parameters = ?new_settings, "Update all settings"); let new_settings = validate_settings(new_settings, &index_scheduler)?; - if !new_settings.chat.is_not_set() { - index_scheduler.features().check_chat_completions("setting `chat` in the index route")?; - } - analytics.publish( SettingsAnalytics { ranking_rules: RankingRulesAnalytics::new(new_settings.ranking_rules.as_ref().set()), From e9d547556d3f50c68b835ebc560f034403ae47c8 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:40:50 +0200 Subject: [PATCH 251/292] Better error reporting when multi choices is used --- crates/meilisearch-types/src/error.rs | 1 + .../src/routes/chats/chat_completions.rs | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 077600a8e..3f7f00cd0 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -391,6 +391,7 @@ EditDocumentsByFunctionError , InvalidRequest , BAD_REQU InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ; // Experimental features - Chat Completions UnimplementedNonStreamingChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; +UnimplementedMultiChoiceChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; ChatNotFound , InvalidRequest , NOT_FOUND ; InvalidChatCompletionOrgId , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionProjectId , InvalidRequest , BAD_REQUEST ; diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 786398cf7..e06f9a082 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -64,12 +64,6 @@ async fn chat( ) -> impl Responder { let ChatsParam { workspace_uid } = chats_param.into_inner(); - assert_eq!( - chat_completion.n.unwrap_or(1), - 1, - "Meilisearch /chat only support one completion at a time (n = 1, n = null)" - ); - if chat_completion.stream.unwrap_or(false) { Either::Right( streamed_chat( @@ -309,6 +303,13 @@ async fn non_streamed_chat( ) -> Result { index_scheduler.features().check_chat_completions("using the /chats chat completions route")?; + if let Some(n) = chat_completion.n.filter(|&n| n != 1) { + return Err(ResponseError::from_msg( + format!("You tried to specify n = {n} but only single choices are supported (n = 1)."), + Code::UnimplementedMultiChoiceChatCompletions, + )); + } + return Err(ResponseError::from_msg( "Non-streamed chat completions is not implemented".to_string(), Code::UnimplementedNonStreamingChatCompletions, @@ -412,6 +413,13 @@ async fn streamed_chat( index_scheduler.features().check_chat_completions("using the /chats chat completions route")?; let filters = index_scheduler.filters(); + if let Some(n) = chat_completion.n.filter(|&n| n != 1) { + return Err(ResponseError::from_msg( + format!("You tried to specify n = {n} but only single choices are supported (n = 1)."), + Code::UnimplementedMultiChoiceChatCompletions, + )); + } + let chat_settings = match index_scheduler.chat_settings(workspace_uid)? { Some(settings) => settings, None => { From b037e416d3a246b8a356a922101c1dc7c2094006 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:43:20 +0200 Subject: [PATCH 252/292] Make an unreachable case, unreachable --- crates/meilisearch/src/routes/chats/utils.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/utils.rs b/crates/meilisearch/src/routes/chats/utils.rs index 34bfebcc7..ee3a1bf27 100644 --- a/crates/meilisearch/src/routes/chats/utils.rs +++ b/crates/meilisearch/src/routes/chats/utils.rs @@ -232,9 +232,8 @@ pub fn format_documents<'doc>( for (docid, external_docid) in internal_docids.into_iter().zip(external_ids) { let document = match DocumentFromDb::new(docid, rtxn, index, &fid_map)? { Some(doc) => doc, - None => continue, + None => unreachable!("Document with internal ID {docid} not found"), }; - let text = prompt.render_document(&external_docid, document, &gfid_map, doc_alloc).unwrap(); renders.push(text); } From a0a4ac66ec6172defd594c41a9aa758c14e2cfcc Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:48:28 +0200 Subject: [PATCH 253/292] Better document the done streamed event --- crates/meilisearch/src/routes/chats/utils.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chats/utils.rs b/crates/meilisearch/src/routes/chats/utils.rs index ee3a1bf27..752eb10e6 100644 --- a/crates/meilisearch/src/routes/chats/utils.rs +++ b/crates/meilisearch/src/routes/chats/utils.rs @@ -197,7 +197,10 @@ impl SseEventSender { } pub async fn stop(self) -> Result<(), SendError> { - self.0.send(Event::Data(sse::Data::new("[DONE]"))).await + // It is the way OpenAI sends a correct end of stream + // + const DONE_DATA: &str = "[DONE]"; + self.0.send(Event::Data(sse::Data::new(DONE_DATA))).await } async fn send_json(&self, data: &S) -> Result<(), SendError> { From 7ea2e4ec7b142d14eaf2f4b9727c8678b60b340f Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 16:51:39 +0200 Subject: [PATCH 254/292] Better document why we duplicate structs --- crates/milli/src/index.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/milli/src/index.rs b/crates/milli/src/index.rs index 9936e9b0c..e9e63a853 100644 --- a/crates/milli/src/index.rs +++ b/crates/milli/src/index.rs @@ -2021,6 +2021,8 @@ pub struct PrefixSettings { pub compute_prefixes: PrefixSearch, } +/// This is unfortunately a duplication of the struct in . +/// The reason why it is duplicated is because milli cannot depend on meilisearch. It would be cyclic imports. #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Deserr, ToSchema, Serialize, Deserialize)] #[deserr(rename_all = camelCase)] #[serde(rename_all = "camelCase")] From 952fabf8a0452dc2be01540a6b8286cc048e1334 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 17:01:00 +0200 Subject: [PATCH 255/292] Better document function names --- crates/meilisearch/src/routes/chats/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/meilisearch/src/routes/chats/mod.rs b/crates/meilisearch/src/routes/chats/mod.rs index 4985deb39..a8a93e6a4 100644 --- a/crates/meilisearch/src/routes/chats/mod.rs +++ b/crates/meilisearch/src/routes/chats/mod.rs @@ -26,12 +26,21 @@ pub mod settings; mod utils; /// The function name to report search progress. +/// This function is used to report on what meilisearch is +/// doing which must be used on the frontend to report progress. const MEILI_SEARCH_PROGRESS_NAME: &str = "_meiliSearchProgress"; /// The function name to append a conversation message in the user conversation. +/// This function is used to append a conversation message in the user conversation. +/// This must be used on the frontend to keep context of what happened on the +/// Meilisearch-side and keep good context for follow up questions. const MEILI_APPEND_CONVERSATION_MESSAGE_NAME: &str = "_meiliAppendConversationMessage"; /// The function name to report sources to the frontend. +/// This function is used to report sources to the frontend. +/// The call id is associated to the one used by the search progress function. const MEILI_SEARCH_SOURCES_NAME: &str = "_meiliSearchSources"; /// The *internal* function name to provide to the LLM to search in indexes. +/// This function must not leak to the user as the LLM will call it and the +/// main goal of Meilisearch is to provide an answer to these calls. const MEILI_SEARCH_IN_INDEX_FUNCTION_NAME: &str = "_meiliSearchInIndex"; #[derive(Deserialize)] From 506ee40dc552baa337a95f2f7cd28463331a46f4 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 10 Jun 2025 17:52:35 +0200 Subject: [PATCH 256/292] Improve errors and other stuff --- crates/meilisearch-types/src/error.rs | 1 + .../src/routes/chats/chat_completions.rs | 48 +++++++++---------- .../meilisearch/src/routes/chats/settings.rs | 2 - 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 3f7f00cd0..10fd645ae 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -390,6 +390,7 @@ InvalidDocumentEditionFunctionFilter , InvalidRequest , BAD_REQU EditDocumentsByFunctionError , InvalidRequest , BAD_REQUEST ; InvalidSettingsIndexChat , InvalidRequest , BAD_REQUEST ; // Experimental features - Chat Completions +UnimplementedExternalFunctionCalling , InvalidRequest , NOT_IMPLEMENTED ; UnimplementedNonStreamingChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; UnimplementedMultiChoiceChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; ChatNotFound , InvalidRequest , NOT_FOUND ; diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index e06f9a082..143d2cddf 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -113,8 +113,24 @@ fn setup_search_tool( system_role: SystemRole, ) -> Result { let tools = chat_completion.tools.get_or_insert_default(); - if tools.iter().any(|t| t.function.name == MEILI_SEARCH_IN_INDEX_FUNCTION_NAME) { - panic!("{MEILI_SEARCH_IN_INDEX_FUNCTION_NAME} function already set"); + for tool in &tools[..] { + match tool.function.name.as_str() { + MEILI_SEARCH_IN_INDEX_FUNCTION_NAME => { + return Err(ResponseError::from_msg( + format!("{MEILI_SEARCH_IN_INDEX_FUNCTION_NAME} function is already defined."), + Code::BadRequest, + )); + } + MEILI_SEARCH_PROGRESS_NAME + | MEILI_SEARCH_SOURCES_NAME + | MEILI_APPEND_CONVERSATION_MESSAGE_NAME => (), + external_function_name => { + return Err(ResponseError::from_msg( + format!("{external_function_name}: External functions are not supported yet."), + Code::UnimplementedExternalFunctionCalling, + )); + } + } } // Remove internal tools used for front-end notifications as they should be hidden from the LLM. @@ -220,9 +236,6 @@ async fn process_search_request( index_uid: String, q: Option, ) -> Result<(Index, Vec, String), ResponseError> { - // TBD - // let mut aggregate = SearchAggregator::::from_query(&query); - let index = index_scheduler.index(&index_uid)?; let rtxn = index.static_read_txn()?; let ChatConfig { description: _, prompt: _, search_parameters } = index.chat_config(&rtxn)?; @@ -281,7 +294,6 @@ async fn process_search_request( documents.push(document); } } - // analytics.publish(aggregate, &req); let (rtxn, search_result) = output?; let render_alloc = Bump::new(); @@ -495,7 +507,7 @@ async fn run_conversation( function_support: FunctionSupport, ) -> Result, ()>, SendError> { let mut finish_reason = None; - // safety: The unwrap can only happen if the stream is not correctly configured. + // safety: unwrap: can only happens if `stream` was set to `false` let mut response = client.chat().create_stream(chat_completion.clone()).await.unwrap(); while let Some(result) = response.next().await { match result { @@ -535,15 +547,11 @@ async fn run_conversation( Call::External } }); - - if global_tool_calls.get(index).is_some_and(Call::is_external) { - todo!("Support forwarding external tool calls"); - } } } None => { if !global_tool_calls.is_empty() { - let (meili_calls, other_calls): (Vec<_>, Vec<_>) = + let (meili_calls, _other_calls): (Vec<_>, Vec<_>) = mem::take(global_tool_calls) .into_values() .flat_map(|call| match call { @@ -568,11 +576,6 @@ async fn run_conversation( .into(), ); - assert!( - other_calls.is_empty(), - "We do not support external tool forwarding for now" - ); - handle_meili_tools( index_scheduler, auth_ctrl, @@ -698,16 +701,13 @@ impl Call { matches!(self, Call::Internal { .. }) } - fn is_external(&self) -> bool { - matches!(self, Call::External { .. }) - } - + /// # Panics + /// + /// - if called on external calls fn append(&mut self, more: &str) { match self { Call::Internal { arguments, .. } => arguments.push_str(more), - Call::External { .. } => { - panic!("Cannot append argument chunks to an external function") - } + Call::External => panic!("Cannot append argument chunks to an external function"), } } } diff --git a/crates/meilisearch/src/routes/chats/settings.rs b/crates/meilisearch/src/routes/chats/settings.rs index cd1ce5767..28611ee98 100644 --- a/crates/meilisearch/src/routes/chats/settings.rs +++ b/crates/meilisearch/src/routes/chats/settings.rs @@ -41,7 +41,6 @@ async fn get_settings( let ChatsParam { workspace_uid } = chats_param.into_inner(); - // TODO do a spawn_blocking here ??? let mut settings = match index_scheduler.chat_settings(&workspace_uid)? { Some(settings) => settings, None => { @@ -66,7 +65,6 @@ async fn patch_settings( index_scheduler.features().check_chat_completions("using the /chats/settings route")?; let ChatsParam { workspace_uid } = chats_param.into_inner(); - // TODO do a spawn_blocking here let old_settings = index_scheduler.chat_settings(&workspace_uid)?.unwrap_or_default(); let prompts = match new.prompts { From 8a916a4e42a328c21fdcff8ac9d3629884813c05 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 11 Jun 2025 07:54:04 +0300 Subject: [PATCH 257/292] More assertion fixes Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 122 +++++++++---------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index d75a09364..9ddf938fc 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -100,7 +100,7 @@ async fn simple_search_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response["results"], { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response["results"], { ".**.processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" [ { "indexUid": "SHARED_DOCUMENTS", @@ -199,7 +199,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -208,7 +208,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 3, "weightedRankingScore": 1.0 } @@ -217,7 +217,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.9848484848484848 } @@ -226,7 +226,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.9848484848484848 } @@ -235,7 +235,7 @@ async fn federation_multiple_search_single_index() { "title": "Badman", "id": "E", "_federation": { - "indexUid": "test", + "indexUid": "SHARED_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.5 } @@ -393,7 +393,7 @@ async fn simple_search_two_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response["results"], { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response["results"], { ".**.processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" [ { "indexUid": "SHARED_DOCUMENTS", @@ -1616,7 +1616,7 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested-[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested.rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n", + "message": "Inside `.queries[1]`: The results of queries #0 and #1 are incompatible: \n 1. `queries[0].sort[0]`, `nested-[uuid].rankingRules[0]`: ascending sort rule(s) on field `mother`\n 2. `queries[1].sort[0]`, `nested-[uuid].rankingRules[0]`: descending sort rule(s) on field `father`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2089,7 +2089,7 @@ async fn federation_sort_different_ranking_rules() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `batman-[uuid].rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `batman-[uuid].rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `movies-[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2153,7 +2153,7 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman-[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n 2. `queries[0].sort[0]`, `batman-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman-[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n 2. `queries[0].sort[0]`, `movies-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2171,7 +2171,7 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `batman-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n 2. `queries[1].sort[0]`, `movies-[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2505,7 +2505,7 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman-[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[0].sort[0]`, `batman-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", + "message": "Inside `.queries[0]`: The results of queries #1 and #0 are incompatible: \n 1. `queries[1].sort[0]`, `batman-[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[0].sort[0]`, `movies-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n - note: The ranking rules of query #1 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n - note: The ranking rules of query #0 were modified during canonicalization:\n 1. Removed relevancy rule `words` at position #1 in ranking rules because the query is a placeholder search (`q`: \"\")\n 2. Removed relevancy rule `typo` at position #2 in ranking rules because the query is a placeholder search (`q`: \"\")\n 3. Removed relevancy rule `proximity` at position #3 in ranking rules because the query is a placeholder search (`q`: \"\")\n 4. Removed relevancy rule `attribute` at position #4 in ranking rules because the query is a placeholder search (`q`: \"\")\n 5. Removed relevancy rule `exactness` at position #5 in ranking rules because the query is a placeholder search (`q`: \"\")\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2523,7 +2523,7 @@ async fn federation_sort_different_indexes_different_criterion_opposite_directio snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[1].sort[0]`, `[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2].sort[0]`, `batman-[uuid].rankingRules[0]`: descending sort rule(s) on field `id`\n 2. `queries[1].sort[0]`, `movies-[uuid].rankingRules[0]`: ascending sort rule(s) on field `title`\n - cannot compare two sort rules in opposite directions\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" @@ -2681,7 +2681,7 @@ async fn federation_limit_offset() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -2718,7 +2718,7 @@ async fn federation_limit_offset() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -2827,7 +2827,7 @@ async fn federation_limit_offset() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [], "processingTimeMs": "[duration]", @@ -3052,7 +3052,7 @@ async fn federation_formatting() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -3161,7 +3161,7 @@ async fn federation_formatting() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [], "processingTimeMs": "[duration]", @@ -3426,7 +3426,7 @@ async fn federation_federated_contains_facets() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Using facet options is not allowed in federated queries.\n - Hint: remove `facets` from query #1 or remove `federation` from the request\n - Hint: pass `federation.facetsByIndex.fruits: [\"BOOSTED\"]` for facets in federated search", + "message": "Inside `.queries[1]`: Using facet options is not allowed in federated queries.\n - Hint: remove `facets` from query #1 or remove `federation` from the request\n - Hint: pass `federation.facetsByIndex.fruits-[uuid]: [\"BOOSTED\"]` for facets in federated search", "code": "invalid_multi_search_query_facets", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_facets" @@ -3735,7 +3735,7 @@ async fn federation_vector_single_index() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -4055,7 +4055,7 @@ async fn federation_vector_two_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response, { ".**._rankingScore" => "[score]" }), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { "hits": [ { @@ -4078,7 +4078,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment-[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9728479385375975 }, @@ -4104,7 +4104,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment-[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.9701486229896544 }, @@ -4182,7 +4182,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment-[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8601469993591309 }, @@ -4208,7 +4208,7 @@ async fn federation_vector_two_indexes() { } }, "_federation": { - "indexUid": "vectors-sentiment-[uuid]", + "indexUid": "vectors-animal-[uuid]", "queriesPosition": 0, "weightedRankingScore": 0.8432406187057495 }, @@ -4490,7 +4490,7 @@ async fn federation_facets_different_indexes_same_facet() { "offset": 0, "estimatedTotalHits": 15, "facetsByIndex": { - "batman-[uuid]": { + "batman-2-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4502,7 +4502,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "batman-2-[uuid]": { + "batman-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4810,7 +4810,7 @@ async fn federation_facets_different_indexes_same_facet() { "offset": 0, "estimatedTotalHits": 11, "facetsByIndex": { - "batman-[uuid]": { + "batman-2-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4822,7 +4822,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "batman-2-[uuid]": { + "batman-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4974,7 +4974,7 @@ async fn federation_facets_same_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -5015,6 +5015,27 @@ async fn federation_facets_same_indexes() { "offset": 0, "estimatedTotalHits": 4, "facetsByIndex": { + "doggos-2-[uuid]": { + "distribution": { + "doggos.age": { + "2": 1, + "4": 1 + }, + "father": { + "jean": 1, + "romain": 1 + }, + "mother": { + "michelle": 2 + } + }, + "stats": { + "doggos.age": { + "min": 2.0, + "max": 4.0 + } + } + }, "doggos-[uuid]": { "distribution": { "doggos.age": { @@ -5038,27 +5059,6 @@ async fn federation_facets_same_indexes() { "max": 6.0 } } - }, - "doggos-2-[uuid]": { - "distribution": { - "doggos.age": { - "2": 1, - "4": 1 - }, - "father": { - "jean": 1, - "romain": 1 - }, - "mother": { - "michelle": 2 - } - }, - "stats": { - "doggos.age": { - "min": 2.0, - "max": 4.0 - } - } } } } @@ -5077,7 +5077,7 @@ async fn federation_facets_same_indexes() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -5373,13 +5373,13 @@ async fn federation_inconsistent_merge_order() { }, "stats": {} }, - "movies-[uuid]": { + "movies-2-[uuid]": { "distribution": { "color": { - "blue": 3, - "green": 2, "red": 3, - "yellow": 2 + "blue": 3, + "yellow": 2, + "green": 2 }, "title": { "Captain Marvel": 1, @@ -5391,13 +5391,13 @@ async fn federation_inconsistent_merge_order() { }, "stats": {} }, - "movies-2-[uuid]": { + "movies-[uuid]": { "distribution": { "color": { - "red": 3, "blue": 3, - "yellow": 2, - "green": 2 + "green": 2, + "red": 3, + "yellow": 2 }, "title": { "Captain Marvel": 1, @@ -5431,7 +5431,7 @@ async fn federation_inconsistent_merge_order() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.federation.facetsByIndex.movies-2-[uuid]`: Inconsistent order for values in facet `color`: index `movies-[uuid]` orders alphabetically, but index `movies-2-[uuid]` orders by count.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `movies-2-[uuid]` used in `.queries[2]`", + "message": "Inside `.federation.facetsByIndex.movies-[uuid]`: Inconsistent order for values in facet `color`: index `movies-2-[uuid]` orders by count, but index `movies-[uuid]` orders alphabetically.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `movies-[uuid]` used in `.queries[0]`", "code": "invalid_multi_search_facet_order", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_facet_order" From 0263eb0aec85f34e42d9e781f0bb2aba60d027e7 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 11 Jun 2025 08:42:35 +0300 Subject: [PATCH 258/292] More assertion fixes Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 152 +++++++++---------- 1 file changed, 75 insertions(+), 77 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 9ddf938fc..86b40e601 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -181,7 +181,7 @@ async fn federation_single_search_single_index() { #[actix_rt::test] async fn federation_multiple_search_single_index() { let server = Server::new_shared(); - let index = shared_index_with_documents().await; + let index = shared_index_with_score_documents().await; let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ @@ -199,7 +199,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "SHARED_DOCUMENTS", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -208,7 +208,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "SHARED_DOCUMENTS", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 3, "weightedRankingScore": 1.0 } @@ -217,7 +217,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "SHARED_DOCUMENTS", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.9848484848484848 } @@ -226,7 +226,7 @@ async fn federation_multiple_search_single_index() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "SHARED_DOCUMENTS", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 2, "weightedRankingScore": 0.9848484848484848 } @@ -235,7 +235,7 @@ async fn federation_multiple_search_single_index() { "title": "Badman", "id": "E", "_federation": { - "indexUid": "SHARED_DOCUMENTS", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 0.5 } @@ -880,14 +880,13 @@ async fn federation_one_query_sort_error() { let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ {"indexUid" : index.uid, "q": "glass"}, - {"indexUid": nested_index.uid, "q": "pésti", "sort": ["doggos:desc"]}, + {"indexUid": nested_index.uid, "q": "pésti", "sort": ["mother:desc"]}, ]})) .await; - dbg!(&response); snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `nested`: Attribute `doggos` is not sortable. This index does not have configured sortable attributes.", + "message": "Inside `.queries[1]`: Index `SHARED_NESTED_DOCUMENTS`: Attribute `mother` is not sortable. Available sortable attributes are: `doggos`.", "code": "invalid_search_sort", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_sort" @@ -2554,7 +2553,6 @@ async fn federation_limit_offset() { {"indexUid" : score_index.uid, "q": "batman returns", "attributesToRetrieve": ["title"]}, ]})) .await; - dbg!(&response); snapshot!(code, @"200 OK"); snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]", ".**._rankingScore" => "[score]" }), @r###" { @@ -4324,7 +4322,7 @@ async fn federation_facets_different_indexes_same_facet() { .await; batman_index.wait_task(value.uid()).await.succeeded(); - let batman_2_index = server.unique_index_with_prefix("batman-2"); + let batman_2_index = server.unique_index_with_prefix("batman_2"); let documents = SCORE_DOCUMENTS.clone(); let (value, _) = batman_2_index.add_documents(documents, None).await; @@ -4375,7 +4373,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4391,7 +4389,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4407,7 +4405,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4423,7 +4421,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4439,7 +4437,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4490,7 +4488,7 @@ async fn federation_facets_different_indexes_same_facet() { "offset": 0, "estimatedTotalHits": 15, "facetsByIndex": { - "batman-2-[uuid]": { + "batman-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4502,7 +4500,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "batman-[uuid]": { + "batman_2-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4565,7 +4563,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4581,7 +4579,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4597,7 +4595,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4613,7 +4611,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4629,7 +4627,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -4735,7 +4733,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 2", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.7028218694885362 } @@ -4751,7 +4749,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman the dark knight returns: Part 1", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.7028218694885362 } @@ -4767,7 +4765,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman Returns", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.8317901234567902 } @@ -4783,7 +4781,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Batman", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.23106060606060605 } @@ -4799,7 +4797,7 @@ async fn federation_facets_different_indexes_same_facet() { { "title": "Badman", "_federation": { - "indexUid": "batman-2-[uuid]", + "indexUid": "batman_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.5 } @@ -4810,7 +4808,7 @@ async fn federation_facets_different_indexes_same_facet() { "offset": 0, "estimatedTotalHits": 11, "facetsByIndex": { - "batman-2-[uuid]": { + "batman-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4822,7 +4820,7 @@ async fn federation_facets_different_indexes_same_facet() { }, "stats": {} }, - "batman-[uuid]": { + "batman_2-[uuid]": { "distribution": { "title": { "Badman": 1, @@ -4868,7 +4866,7 @@ async fn federation_facets_same_indexes() { .await; doggos_index.wait_task(value.uid()).await.succeeded(); - let doggos2_index = server.unique_index_with_prefix("doggos-2"); + let doggos2_index = server.unique_index_with_prefix("doggos_2"); let documents = NESTED_DOCUMENTS.clone(); let (value, _) = doggos2_index.add_documents(documents, None).await; @@ -4996,7 +4994,7 @@ async fn federation_facets_same_indexes() { { "id": 852, "_federation": { - "indexUid": "doggos-2-[uuid]", + "indexUid": "doggos_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5004,7 +5002,7 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "doggos-2-[uuid]", + "indexUid": "doggos_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5015,27 +5013,6 @@ async fn federation_facets_same_indexes() { "offset": 0, "estimatedTotalHits": 4, "facetsByIndex": { - "doggos-2-[uuid]": { - "distribution": { - "doggos.age": { - "2": 1, - "4": 1 - }, - "father": { - "jean": 1, - "romain": 1 - }, - "mother": { - "michelle": 2 - } - }, - "stats": { - "doggos.age": { - "min": 2.0, - "max": 4.0 - } - } - }, "doggos-[uuid]": { "distribution": { "doggos.age": { @@ -5059,6 +5036,27 @@ async fn federation_facets_same_indexes() { "max": 6.0 } } + }, + "doggos_2-[uuid]": { + "distribution": { + "doggos.age": { + "2": 1, + "4": 1 + }, + "father": { + "jean": 1, + "romain": 1 + }, + "mother": { + "michelle": 2 + } + }, + "stats": { + "doggos.age": { + "min": 2.0, + "max": 4.0 + } + } } } } @@ -5099,7 +5097,7 @@ async fn federation_facets_same_indexes() { { "id": 852, "_federation": { - "indexUid": "doggos-2-[uuid]", + "indexUid": "doggos_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5107,7 +5105,7 @@ async fn federation_facets_same_indexes() { { "id": 750, "_federation": { - "indexUid": "doggos-2-[uuid]", + "indexUid": "doggos_2-[uuid]", "queriesPosition": 1, "weightedRankingScore": 0.9621212121212122 } @@ -5170,7 +5168,7 @@ async fn federation_inconsistent_merge_order() { .await; movies_index.wait_task(value.uid()).await.succeeded(); - let movies2_index = server.unique_index_with_prefix("movies-2"); + let movies2_index = server.unique_index_with_prefix("movies_2"); let documents = DOCUMENTS.clone(); let (value, _) = movies2_index.add_documents(documents, None).await; @@ -5286,7 +5284,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5302,7 +5300,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5318,7 +5316,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5334,7 +5332,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5350,7 +5348,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5373,13 +5371,13 @@ async fn federation_inconsistent_merge_order() { }, "stats": {} }, - "movies-2-[uuid]": { + "movies-[uuid]": { "distribution": { "color": { - "red": 3, "blue": 3, - "yellow": 2, - "green": 2 + "green": 2, + "red": 3, + "yellow": 2 }, "title": { "Captain Marvel": 1, @@ -5391,13 +5389,13 @@ async fn federation_inconsistent_merge_order() { }, "stats": {} }, - "movies-[uuid]": { + "movies_2-[uuid]": { "distribution": { "color": { - "blue": 3, - "green": 2, "red": 3, - "yellow": 2 + "blue": 3, + "yellow": 2, + "green": 2 }, "title": { "Captain Marvel": 1, @@ -5431,7 +5429,7 @@ async fn federation_inconsistent_merge_order() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.federation.facetsByIndex.movies-[uuid]`: Inconsistent order for values in facet `color`: index `movies-2-[uuid]` orders by count, but index `movies-[uuid]` orders alphabetically.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `movies-[uuid]` used in `.queries[0]`", + "message": "Inside `.federation.facetsByIndex.movies_2-[uuid]`: Inconsistent order for values in facet `color`: index `movies-[uuid]` orders alphabetically, but index `movies_2-[uuid]` orders by count.\n - Hint: Remove `federation.mergeFacets` or change `faceting.sortFacetValuesBy` to be consistent in settings.\n - Note: index `movies_2-[uuid]` used in `.queries[2]`", "code": "invalid_multi_search_facet_order", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_facet_order" @@ -5456,7 +5454,7 @@ async fn federation_inconsistent_merge_order() { ]})) .await; snapshot!(code, @"200 OK"); - snapshot!(json_string!(response), @r###" + snapshot!(json_string!(response, { ".processingTimeMs" => "[duration]" }), @r###" { "hits": [ { @@ -5510,7 +5508,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Captain Marvel", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5526,7 +5524,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Escape Room", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5542,7 +5540,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Gläss", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5558,7 +5556,7 @@ async fn federation_inconsistent_merge_order() { { "title": "How to Train Your Dragon: The Hidden World", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } @@ -5574,7 +5572,7 @@ async fn federation_inconsistent_merge_order() { { "title": "Shazam!", "_federation": { - "indexUid": "movies-2-[uuid]", + "indexUid": "movies_2-[uuid]", "queriesPosition": 2, "weightedRankingScore": 1.0 } From bb4baf7fae78311e65db47b1949c5a0884d8b86e Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 11 Jun 2025 08:52:28 +0300 Subject: [PATCH 259/292] Remove useless dynamic redactions. They are covered by their `.**.xyz` counterparts Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index fcd17879e..3c838f6d6 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -62,9 +62,7 @@ pub fn default_snapshot_settings_for_test<'a>( } } - settings.add_dynamic_redaction(".message", uuid_in_message_redaction); settings.add_dynamic_redaction(".**.message", uuid_in_message_redaction); - settings.add_dynamic_redaction(".indexUid", uuid_in_message_redaction); settings.add_dynamic_redaction(".**.indexUid", uuid_in_message_redaction); settings.add_dynamic_redaction(".facetsByIndex", uuid_in_json_key_redaction); From 824f5b12cec4119ef04250fbd8002b00a2aeca9d Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 11 Jun 2025 08:54:58 +0300 Subject: [PATCH 260/292] Formatting Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index 3c838f6d6..e026f303a 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -46,16 +46,16 @@ pub fn default_snapshot_settings_for_test<'a>( fn uuid_in_json_key_redaction(content: Content, _content_path: ContentPath) -> Content { match content { Content::Map(map) => { - let new_map = map.iter() - .map(|(key, value)| { - match key { - Content::String(s) => { - let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "[uuid]"); - (Content::String(uuid_replaced.to_string()), value.clone()) - } - _ => (key.clone(), value.clone()), + let new_map = map + .iter() + .map(|(key, value)| match key { + Content::String(s) => { + let uuid_replaced = UUID_IN_MESSAGE_RE.replace_all(s, "[uuid]"); + (Content::String(uuid_replaced.to_string()), value.clone()) } - }).collect(); + _ => (key.clone(), value.clone()), + }) + .collect(); Content::Map(new_map) } _ => content, From a73d3c03e99c08809c6f1ad73334c7c1197afb69 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 11 Jun 2025 09:10:10 +0300 Subject: [PATCH 261/292] Make the dynamic assertion for `facetsByIndex` JSON key more broader Signed-off-by: Martin Tzvetanov Grigorov --- crates/meili-snap/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meili-snap/src/lib.rs b/crates/meili-snap/src/lib.rs index e026f303a..efe57f8df 100644 --- a/crates/meili-snap/src/lib.rs +++ b/crates/meili-snap/src/lib.rs @@ -64,7 +64,7 @@ pub fn default_snapshot_settings_for_test<'a>( settings.add_dynamic_redaction(".**.message", uuid_in_message_redaction); settings.add_dynamic_redaction(".**.indexUid", uuid_in_message_redaction); - settings.add_dynamic_redaction(".facetsByIndex", uuid_in_json_key_redaction); + settings.add_dynamic_redaction(".**.facetsByIndex", uuid_in_json_key_redaction); let test_name = test_name.strip_suffix("::{{closure}}").unwrap_or(test_name); let test_name = test_name.rsplit("::").next().unwrap().to_owned(); From 77cc3678b52cfeed6d9f387ac2a31e564c50af02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 11 Jun 2025 09:27:14 +0200 Subject: [PATCH 262/292] Make sure template errors are reported to the LLM and front-end without panicking --- crates/meilisearch-types/src/error.rs | 1 + .../src/routes/chats/chat_completions.rs | 12 ++++-- crates/meilisearch/src/routes/chats/errors.rs | 41 +++++++++++++------ crates/meilisearch/src/routes/chats/utils.rs | 12 +++++- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index 10fd645ae..d2500b7e1 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -394,6 +394,7 @@ UnimplementedExternalFunctionCalling , InvalidRequest , NOT_IMPL UnimplementedNonStreamingChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; UnimplementedMultiChoiceChatCompletions , InvalidRequest , NOT_IMPLEMENTED ; ChatNotFound , InvalidRequest , NOT_FOUND ; +InvalidChatSettingDocumentTemplate , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionOrgId , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionProjectId , InvalidRequest , BAD_REQUEST ; InvalidChatCompletionApiVersion , InvalidRequest , BAD_REQUEST ; diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 143d2cddf..60f28d638 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -646,7 +646,7 @@ async fn handle_meili_tools( } let result = match serde_json::from_str(&call.function.arguments) { - Ok(SearchInIndexParameters { index_uid, q }) => process_search_request( + Ok(SearchInIndexParameters { index_uid, q }) => match process_search_request( index_scheduler, auth_ctrl.clone(), search_queue, @@ -655,7 +655,14 @@ async fn handle_meili_tools( q, ) .await - .map_err(|e| e.to_string()), + { + Ok(output) => Ok(output), + Err(err) => { + let error_text = err.to_string(); + tx.send_error(&StreamErrorEvent::from_response_error(err)).await?; + Err(error_text) + } + }, Err(err) => Err(err.to_string()), }; @@ -664,7 +671,6 @@ async fn handle_meili_tools( if report_sources { tx.report_sources(resp.clone(), &call.id, &documents).await?; } - text } Err(err) => err, diff --git a/crates/meilisearch/src/routes/chats/errors.rs b/crates/meilisearch/src/routes/chats/errors.rs index f1aa9722b..efa60ba50 100644 --- a/crates/meilisearch/src/routes/chats/errors.rs +++ b/crates/meilisearch/src/routes/chats/errors.rs @@ -1,5 +1,6 @@ use async_openai::error::{ApiError, OpenAIError}; use async_openai::reqwest_eventsource::Error as EventSourceError; +use meilisearch_types::error::ResponseError; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -53,12 +54,13 @@ pub struct StreamError { } impl StreamErrorEvent { + const ERROR_TYPE: &str = "error"; + pub async fn from_openai_error(error: OpenAIError) -> Result { - let error_type = "error".to_string(); match error { OpenAIError::Reqwest(e) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "internal_reqwest_error".to_string(), code: Some("internal".to_string()), @@ -69,7 +71,7 @@ impl StreamErrorEvent { }), OpenAIError::ApiError(ApiError { message, r#type, param, code }) => { Ok(StreamErrorEvent { - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), event_id: Uuid::new_v4().to_string(), error: StreamError { r#type: r#type.unwrap_or_else(|| "unknown".to_string()), @@ -82,7 +84,7 @@ impl StreamErrorEvent { } OpenAIError::JSONDeserialize(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "json_deserialize_error".to_string(), code: Some("internal".to_string()), @@ -100,7 +102,7 @@ impl StreamErrorEvent { Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type, code, message, param, event_id: None }, }) } @@ -111,13 +113,13 @@ impl StreamErrorEvent { Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type, code, message, param, event_id: None }, }) } EventSourceError::Utf8(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "invalid_utf8_error".to_string(), code: None, @@ -128,7 +130,7 @@ impl StreamErrorEvent { }), EventSourceError::Parser(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "parser_error".to_string(), code: None, @@ -139,7 +141,7 @@ impl StreamErrorEvent { }), EventSourceError::Transport(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "transport_error".to_string(), code: None, @@ -150,7 +152,7 @@ impl StreamErrorEvent { }), EventSourceError::InvalidLastEventId(message) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "invalid_last_event_id".to_string(), code: None, @@ -161,7 +163,7 @@ impl StreamErrorEvent { }), EventSourceError::StreamEnded => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "stream_ended".to_string(), code: None, @@ -173,7 +175,7 @@ impl StreamErrorEvent { }, OpenAIError::InvalidArgument(message) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: error_type, + r#type: Self::ERROR_TYPE.to_string(), error: StreamError { r#type: "invalid_argument".to_string(), code: None, @@ -184,4 +186,19 @@ impl StreamErrorEvent { }), } } + + pub fn from_response_error(error: ResponseError) -> Self { + let ResponseError { code, message, .. } = error; + StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: Self::ERROR_TYPE.to_string(), + error: StreamError { + r#type: "response_error".to_string(), + code: Some(code.as_str().to_string()), + message, + param: None, + event_id: None, + }, + } + } } diff --git a/crates/meilisearch/src/routes/chats/utils.rs b/crates/meilisearch/src/routes/chats/utils.rs index 752eb10e6..61961bd4b 100644 --- a/crates/meilisearch/src/routes/chats/utils.rs +++ b/crates/meilisearch/src/routes/chats/utils.rs @@ -9,7 +9,7 @@ use async_openai::types::{ FunctionCall, FunctionCallStream, Role, }; use bumpalo::Bump; -use meilisearch_types::error::ResponseError; +use meilisearch_types::error::{Code, ResponseError}; use meilisearch_types::heed::RoTxn; use meilisearch_types::milli::index::ChatConfig; use meilisearch_types::milli::prompt::{Prompt, PromptData}; @@ -237,7 +237,15 @@ pub fn format_documents<'doc>( Some(doc) => doc, None => unreachable!("Document with internal ID {docid} not found"), }; - let text = prompt.render_document(&external_docid, document, &gfid_map, doc_alloc).unwrap(); + let text = match prompt.render_document(&external_docid, document, &gfid_map, doc_alloc) { + Ok(text) => text, + Err(err) => { + return Err(ResponseError::from_msg( + err.to_string(), + Code::InvalidChatSettingDocumentTemplate, + )) + } + }; renders.push(text); } From 620867d611c5805e9ff9e31fd6c91953675ca9fa Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 11 Jun 2025 11:01:05 +0300 Subject: [PATCH 263/292] Use unique indices for the searches in non-existing indices By using hardcoded there is a chance that the index could exist Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 86b40e601..a7489260d 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -1,3 +1,4 @@ +use uuid::Uuid; use meili_snap::{json_string, snapshot}; use super::{DOCUMENTS, FRUITS_DOCUMENTS, NESTED_DOCUMENTS}; @@ -784,16 +785,19 @@ async fn federation_one_index_doesnt_exist() { async fn search_multiple_indexes_dont_exist() { let server = Server::new_shared(); + let index_1 = format!("index_1-{}", Uuid::new_v4()); + let index_2 = format!("index_2-{}", Uuid::new_v4()); + let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti"}, + {"indexUid" : index_1, "q": "glass"}, + {"indexUid": index_2, "q": "pésti"}, ]})) .await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: Index `test` not found.", + "message": "Inside `.queries[0]`: Index `index_1-[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" @@ -805,10 +809,13 @@ async fn search_multiple_indexes_dont_exist() { async fn federation_multiple_indexes_dont_exist() { let server = Server::new_shared(); + let index_1 = format!("index_1-{}", Uuid::new_v4()); + let index_2 = format!("index_2-{}", Uuid::new_v4()); + let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : "test", "q": "glass"}, - {"indexUid": "nested", "q": "pésti"}, + {"indexUid" : index_1, "q": "glass"}, + {"indexUid": index_2, "q": "pésti"}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -816,7 +823,7 @@ async fn federation_multiple_indexes_dont_exist() { // the query index is the lowest index with that index snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: Index `nested` not found.", + "message": "Inside `.queries[0]`: Index `index_1-[uuid]` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" From b8845d10157bb69979f1c762ad8f2b5c22423170 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 11 Jun 2025 11:29:33 +0300 Subject: [PATCH 264/292] Sort the imports Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index a7489260d..e862649f4 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -1,5 +1,5 @@ -use uuid::Uuid; use meili_snap::{json_string, snapshot}; +use uuid::Uuid; use super::{DOCUMENTS, FRUITS_DOCUMENTS, NESTED_DOCUMENTS}; use crate::common::{ From 19d077a4b11faea976a894d85f817106aea008e5 Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Wed, 11 Jun 2025 08:35:24 +0000 Subject: [PATCH 265/292] Update version for the next release (v1.15.1) in Cargo.toml --- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e9a072d3..9af5a9b5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -492,7 +492,7 @@ source = "git+https://github.com/meilisearch/bbqueue#cbb87cc707b5af415ef203bdaf2 [[package]] name = "benchmarks" -version = "1.15.0" +version = "1.15.1" dependencies = [ "anyhow", "bumpalo", @@ -683,7 +683,7 @@ dependencies = [ [[package]] name = "build-info" -version = "1.15.0" +version = "1.15.1" dependencies = [ "anyhow", "time", @@ -1673,7 +1673,7 @@ dependencies = [ [[package]] name = "dump" -version = "1.15.0" +version = "1.15.1" dependencies = [ "anyhow", "big_s", @@ -1875,7 +1875,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "file-store" -version = "1.15.0" +version = "1.15.1" dependencies = [ "tempfile", "thiserror 2.0.12", @@ -1897,7 +1897,7 @@ dependencies = [ [[package]] name = "filter-parser" -version = "1.15.0" +version = "1.15.1" dependencies = [ "insta", "nom", @@ -1917,7 +1917,7 @@ dependencies = [ [[package]] name = "flatten-serde-json" -version = "1.15.0" +version = "1.15.1" dependencies = [ "criterion", "serde_json", @@ -2056,7 +2056,7 @@ dependencies = [ [[package]] name = "fuzzers" -version = "1.15.0" +version = "1.15.1" dependencies = [ "arbitrary", "bumpalo", @@ -2787,7 +2787,7 @@ dependencies = [ [[package]] name = "index-scheduler" -version = "1.15.0" +version = "1.15.1" dependencies = [ "anyhow", "big_s", @@ -3015,7 +3015,7 @@ dependencies = [ [[package]] name = "json-depth-checker" -version = "1.15.0" +version = "1.15.1" dependencies = [ "criterion", "serde_json", @@ -3488,7 +3488,7 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "meili-snap" -version = "1.15.0" +version = "1.15.1" dependencies = [ "insta", "md5", @@ -3497,7 +3497,7 @@ dependencies = [ [[package]] name = "meilisearch" -version = "1.15.0" +version = "1.15.1" dependencies = [ "actix-cors", "actix-http", @@ -3589,7 +3589,7 @@ dependencies = [ [[package]] name = "meilisearch-auth" -version = "1.15.0" +version = "1.15.1" dependencies = [ "base64 0.22.1", "enum-iterator", @@ -3608,7 +3608,7 @@ dependencies = [ [[package]] name = "meilisearch-types" -version = "1.15.0" +version = "1.15.1" dependencies = [ "actix-web", "anyhow", @@ -3642,7 +3642,7 @@ dependencies = [ [[package]] name = "meilitool" -version = "1.15.0" +version = "1.15.1" dependencies = [ "anyhow", "clap", @@ -3676,7 +3676,7 @@ dependencies = [ [[package]] name = "milli" -version = "1.15.0" +version = "1.15.1" dependencies = [ "allocator-api2", "arroy", @@ -4189,7 +4189,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "permissive-json-pointer" -version = "1.15.0" +version = "1.15.1" dependencies = [ "big_s", "serde_json", @@ -6845,7 +6845,7 @@ dependencies = [ [[package]] name = "xtask" -version = "1.15.0" +version = "1.15.1" dependencies = [ "anyhow", "build-info", diff --git a/Cargo.toml b/Cargo.toml index ce4b806f9..2ab980401 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ members = [ ] [workspace.package] -version = "1.15.0" +version = "1.15.1" authors = [ "Quentin de Quelen ", "Clément Renault ", From 7533a11143749e2f4d40117c58cd5b93b8f3df11 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 11 Jun 2025 10:49:21 +0200 Subject: [PATCH 266/292] Make sure to send the tool response before the error message --- .../meilisearch/src/routes/chats/chat_completions.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 60f28d638..7431609e6 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -645,6 +645,8 @@ async fn handle_meili_tools( .await?; } + let mut error = None; + let result = match serde_json::from_str(&call.function.arguments) { Ok(SearchInIndexParameters { index_uid, q }) => match process_search_request( index_scheduler, @@ -658,8 +660,8 @@ async fn handle_meili_tools( { Ok(output) => Ok(output), Err(err) => { - let error_text = err.to_string(); - tx.send_error(&StreamErrorEvent::from_response_error(err)).await?; + let error_text = format!("the search tool call failed with {err}"); + error = Some(err); Err(error_text) } }, @@ -686,6 +688,10 @@ async fn handle_meili_tools( } chat_completion.messages.push(tool); + + if let Some(error) = error { + tx.send_error(&StreamErrorEvent::from_response_error(error)).await?; + } } Ok(()) From 484fdd9ce29bfba2957ba7338d9f87e24a635554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 11 Jun 2025 10:59:14 +0200 Subject: [PATCH 267/292] Fix the insta snapshots --- .../upgrade_failure/after_processing_everything.snap | 4 ++-- .../upgrade_failure/register_automatic_upgrade_task.snap | 2 +- .../registered_a_task_while_the_upgrade_task_is_enqueued.snap | 2 +- .../test_failure.rs/upgrade_failure/upgrade_task_failed.snap | 4 ++-- .../upgrade_failure/upgrade_task_failed_again.snap | 4 ++-- .../upgrade_failure/upgrade_task_succeeded.snap | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap index 30abdb36b..83814339e 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 0) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} 2 {uid: 2, batch_uid: 2, status: succeeded, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} 3 {uid: 3, batch_uid: 3, status: failed, error: ResponseError { code: 200, message: "Index `doggo` already exists.", error_code: "index_already_exists", error_type: "invalid_request", error_link: "https://docs.meilisearch.com/errors#index_already_exists" }, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} @@ -57,7 +57,7 @@ girafo: { number_of_documents: 0, field_distribution: {} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } 1 {uid: 1, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } 2 {uid: 2, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } 3 {uid: 3, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap index 37bb9d78e..389afebda 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 0) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} ---------------------------------------------------------------------- ### Status: enqueued [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap index fd8656c42..a6cb4edb3 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 0) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} ---------------------------------------------------------------------- ### Status: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap index beb1176c2..21c399d66 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 0) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} ---------------------------------------------------------------------- ### Status: @@ -37,7 +37,7 @@ catto [1,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap index faa3ea23d..c71c4082b 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 0) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} 2 {uid: 2, status: enqueued, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} ---------------------------------------------------------------------- @@ -40,7 +40,7 @@ doggo [2,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap index ee569fdc4..ad75252d4 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 0) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} 2 {uid: 2, status: enqueued, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} 3 {uid: 3, status: enqueued, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} @@ -43,7 +43,7 @@ doggo [2,3,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.0"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] From 48d2d3a5cd74cbd9ec9c2173c3e46de8ac226363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Wed, 11 Jun 2025 11:58:22 +0200 Subject: [PATCH 268/292] Fix more tests --- crates/meilisearch/tests/upgrade/mod.rs | 4 ++-- ...ches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...ches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...tches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...asks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...asks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap | 2 +- ..._whole_batch_queue_once_everything_has_been_processed.snap | 2 +- ...e_whole_task_queue_once_everything_has_been_processed.snap | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/meilisearch/tests/upgrade/mod.rs b/crates/meilisearch/tests/upgrade/mod.rs index f1e45164e..8a91d9057 100644 --- a/crates/meilisearch/tests/upgrade/mod.rs +++ b/crates/meilisearch/tests/upgrade/mod.rs @@ -43,7 +43,7 @@ async fn version_too_old() { std::fs::write(db_path.join("VERSION"), "1.11.9999").unwrap(); let options = Opt { experimental_dumpless_upgrade: true, ..default_settings }; let err = Server::new_with_options(options).await.map(|_| ()).unwrap_err(); - snapshot!(err, @"Database version 1.11.9999 is too old for the experimental dumpless upgrade feature. Please generate a dump using the v1.11.9999 and import it in the v1.15.0"); + snapshot!(err, @"Database version 1.11.9999 is too old for the experimental dumpless upgrade feature. Please generate a dump using the v1.11.9999 and import it in the v1.15.1"); } #[actix_rt::test] @@ -58,7 +58,7 @@ async fn version_requires_downgrade() { std::fs::write(db_path.join("VERSION"), format!("{major}.{minor}.{patch}")).unwrap(); let options = Opt { experimental_dumpless_upgrade: true, ..default_settings }; let err = Server::new_with_options(options).await.map(|_| ()).unwrap_err(); - snapshot!(err, @"Database version 1.15.1 is higher than the Meilisearch version 1.15.0. Downgrade is not supported"); + snapshot!(err, @"Database version 1.15.2 is higher than the Meilisearch version 1.15.1. Downgrade is not supported"); } #[actix_rt::test] diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap index f7f678e36..3484efdfe 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap index f7f678e36..3484efdfe 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap index f7f678e36..3484efdfe 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap index 480f85bdb..a37202b3e 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "error": null, "duration": "[duration]", diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap index 480f85bdb..a37202b3e 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "error": null, "duration": "[duration]", diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap index 480f85bdb..a37202b3e 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "error": null, "duration": "[duration]", diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap index 78cb4e656..4923b3d15 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap index 5c409891c..29e11e738 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.0" + "upgradeTo": "v1.15.1" }, "error": null, "duration": "[duration]", From 646e44ddf90a18c593d94db60a448c622e86578f Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 12 Jun 2025 08:59:19 +0300 Subject: [PATCH 269/292] Re-use the shared_index_with_score_documents since the settings are as the default Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 33 +++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index e862649f4..79b8952b1 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -1924,26 +1924,7 @@ async fn federation_sort_different_ranking_rules() { .await; movies_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index_with_prefix("batman"); - - let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = batman_index.add_documents(documents, None).await; - batman_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = batman_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "words", - "typo", - "proximity", - "attribute", - "sort", - "exactness" - ] - })) - .await; - batman_index.wait_task(value.uid()).await.succeeded(); + let batman_index = shared_index_with_score_documents().await; // return titles ordered across indexes let (response, code) = server @@ -1960,7 +1941,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Badman", "id": "E", "_federation": { - "indexUid": "batman-[uuid]", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1970,7 +1951,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman", "id": "D", "_federation": { - "indexUid": "batman-[uuid]", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1980,7 +1961,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman Returns", "id": "C", "_federation": { - "indexUid": "batman-[uuid]", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -1990,7 +1971,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman the dark knight returns: Part 1", "id": "A", "_federation": { - "indexUid": "batman-[uuid]", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2000,7 +1981,7 @@ async fn federation_sort_different_ranking_rules() { "title": "Batman the dark knight returns: Part 2", "id": "B", "_federation": { - "indexUid": "batman-[uuid]", + "indexUid": "SHARED_SCORE_DOCUMENTS", "queriesPosition": 1, "weightedRankingScore": 1.0 }, @@ -2095,7 +2076,7 @@ async fn federation_sort_different_ranking_rules() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `batman-[uuid].rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `movies-[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", + "message": "Inside `.queries[1]`: The results of queries #2 and #1 are incompatible: \n 1. `queries[2]`, `SHARED_SCORE_DOCUMENTS.rankingRules[0..=3]`: relevancy rule(s) words, typo, proximity, attribute\n 2. `queries[1].sort[0]`, `movies-[uuid].rankingRules[0]`: descending sort rule(s) on field `title`\n - cannot compare a relevancy rule with a sort rule\n", "code": "invalid_multi_search_query_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_multi_search_query_ranking_rules" From 40776ed4cd8e1a53e36354a39daf0805499e47bd Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 12 Jun 2025 11:05:08 +0200 Subject: [PATCH 270/292] add test reproducing #5650 --- crates/meilisearch/tests/search/mod.rs | 73 ++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/crates/meilisearch/tests/search/mod.rs b/crates/meilisearch/tests/search/mod.rs index ff6d3e2b8..b2d781e7f 100644 --- a/crates/meilisearch/tests/search/mod.rs +++ b/crates/meilisearch/tests/search/mod.rs @@ -2086,3 +2086,76 @@ async fn test_exact_typos_terms() { ) .await; } + +#[actix_rt::test] +async fn simple_search_changing_unrelated_settings() { + let server = Server::new_shared(); + let index = server.unique_index(); + + let documents = DOCUMENTS.clone(); + let (task, _status_code) = index.add_documents(documents, None).await; + index.wait_task(task.uid()).await.succeeded(); + + index + .search(json!({"q": "Dragon"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "title": "How to Train Your Dragon: The Hidden World", + "id": "166428", + "color": [ + "green", + "red" + ] + } + ] + "###); + }) + .await; + + let (task, _status_code) = + index.update_settings(json!({ "filterableAttributes": ["title"] })).await; + let r = index.wait_task(task.uid()).await.succeeded(); + snapshot!(r["status"], @r###""succeeded""###); + + index + .search(json!({"q": "Dragon"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "title": "How to Train Your Dragon: The Hidden World", + "id": "166428", + "color": [ + "green", + "red" + ] + } + ] + "###); + }) + .await; + + let (task, _status_code) = index.update_settings(json!({ "filterableAttributes": [] })).await; + let r = index.wait_task(task.uid()).await.succeeded(); + snapshot!(r["status"], @r###""succeeded""###); + + index + .search(json!({"q": "Dragon"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "title": "How to Train Your Dragon: The Hidden World", + "id": "166428", + "color": [ + "green", + "red" + ] + } + ] + "###); + }) + .await; +} From 5d191c479e0f328ca670be5803fc4cbaeb967c0e Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 12 Jun 2025 12:37:27 +0200 Subject: [PATCH 271/292] Skip indexing on settings update when possible, when removing a field from the filterable settings, this will trigger a reindexing of the negative version of the document, which removes the document from the searchable as well because the field was considered removed. --- .../extract/extract_docid_word_positions.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/milli/src/update/index_documents/extract/extract_docid_word_positions.rs b/crates/milli/src/update/index_documents/extract/extract_docid_word_positions.rs index d502e69cc..b906c7778 100644 --- a/crates/milli/src/update/index_documents/extract/extract_docid_word_positions.rs +++ b/crates/milli/src/update/index_documents/extract/extract_docid_word_positions.rs @@ -29,7 +29,6 @@ pub fn extract_docid_word_positions( let max_positions_per_attributes = max_positions_per_attributes .map_or(MAX_POSITION_PER_ATTRIBUTE, |max| max.min(MAX_POSITION_PER_ATTRIBUTE)); let max_memory = indexer.max_memory_by_thread(); - let force_reindexing = settings_diff.reindex_searchable(); // initialize destination values. let mut documents_ids = RoaringBitmap::new(); @@ -43,6 +42,12 @@ pub fn extract_docid_word_positions( true, ); + let force_reindexing = settings_diff.reindex_searchable(); + let skip_indexing = !force_reindexing && settings_diff.settings_update_only(); + if skip_indexing { + return sorter_into_reader(docid_word_positions_sorter, indexer); + } + // initialize buffers. let mut del_buffers = Buffers::default(); let mut add_buffers = Buffers::default(); From e8774ad0798cedbea4b94bcf7346fe135f29ebbc Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 12 Jun 2025 13:46:17 +0300 Subject: [PATCH 272/292] Extract shared indices for movies and batman documents Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 352 ++++--------------- 1 file changed, 78 insertions(+), 274 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 79b8952b1..8c6e45c74 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -1,16 +1,80 @@ use meili_snap::{json_string, snapshot}; +use tokio::sync::OnceCell; use uuid::Uuid; use super::{DOCUMENTS, FRUITS_DOCUMENTS, NESTED_DOCUMENTS}; +use crate::common::index::Index; use crate::common::{ shared_index_with_documents, shared_index_with_nested_documents, - shared_index_with_score_documents, Server, + shared_index_with_score_documents, Server, Shared, }; use crate::json; use crate::search::{SCORE_DOCUMENTS, VECTOR_DOCUMENTS}; mod proxy; +pub async fn shared_movies_index() -> &'static Index<'static, Shared> { + static INDEX: OnceCell> = OnceCell::const_new(); + INDEX + .get_or_init(|| async { + let server = Server::new_shared(); + let movies_index = server.unique_index_with_prefix("movies"); + + let documents = DOCUMENTS.clone(); + let (response, _code) = movies_index.add_documents(documents, None).await; + movies_index.wait_task(response.uid()).await.succeeded(); + + let (value, _) = movies_index + .update_settings(json!({ + "sortableAttributes": ["title"], + "filterableAttributes": ["title", "color"], + "rankingRules": [ + "sort", + "words", + "typo", + "proximity", + "attribute", + "exactness" + ] + })) + .await; + movies_index.wait_task(value.uid()).await.succeeded(); + movies_index.to_shared() + }) + .await +} + +pub async fn shared_batman_index() -> &'static Index<'static, Shared> { + static INDEX: OnceCell> = OnceCell::const_new(); + INDEX + .get_or_init(|| async { + let server = Server::new_shared(); + let batman_index = server.unique_index_with_prefix("batman"); + + let documents = SCORE_DOCUMENTS.clone(); + let (response, _code) = batman_index.add_documents(documents, None).await; + batman_index.wait_task(response.uid()).await.succeeded(); + + let (value, _) = batman_index + .update_settings(json!({ + "sortableAttributes": ["id", "title"], + "filterableAttributes": ["title"], + "rankingRules": [ + "sort", + "words", + "typo", + "proximity", + "attribute", + "exactness" + ] + })) + .await; + batman_index.wait_task(value.uid()).await.succeeded(); + batman_index.to_shared() + }) + .await +} + #[actix_rt::test] async fn search_empty_list() { let server = Server::new_shared(); @@ -1633,47 +1697,8 @@ async fn federation_sort_same_indexes_different_criterion_opposite_direction() { #[actix_rt::test] async fn federation_sort_different_indexes_same_criterion_same_direction() { let server = Server::new_shared(); - let movies_index = server.unique_index_with_prefix("movies"); - - let documents = DOCUMENTS.clone(); - let (value, _) = movies_index.add_documents(documents, None).await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = movies_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let batman_index = server.unique_index_with_prefix("batman"); - - let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = batman_index.add_documents(documents, None).await; - batman_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = batman_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - batman_index.wait_task(value.uid()).await.succeeded(); + let movies_index = shared_movies_index().await; + let batman_index = shared_batman_index().await; // return titles ordered across indexes let (response, code) = server @@ -1903,26 +1928,7 @@ async fn federation_sort_different_indexes_same_criterion_same_direction() { async fn federation_sort_different_ranking_rules() { let server = Server::new_shared(); - let movies_index = server.unique_index_with_prefix("movies"); - - let documents = DOCUMENTS.clone(); - let (value, _) = movies_index.add_documents(documents, None).await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = movies_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - movies_index.wait_task(value.uid()).await.succeeded(); + let movies_index = shared_movies_index().await; let batman_index = shared_index_with_score_documents().await; @@ -2087,48 +2093,8 @@ async fn federation_sort_different_ranking_rules() { #[actix_rt::test] async fn federation_sort_different_indexes_same_criterion_opposite_direction() { let server = Server::new_shared(); - - let movies_index = server.unique_index_with_prefix("movies"); - - let documents = DOCUMENTS.clone(); - let (value, _) = movies_index.add_documents(documents, None).await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = movies_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let batman_index = server.unique_index_with_prefix("batman"); - - let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = batman_index.add_documents(documents, None).await; - batman_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = batman_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - batman_index.wait_task(value.uid()).await.succeeded(); + let movies_index = shared_movies_index().await; + let batman_index = shared_batman_index().await; // all results from query 0 let (response, code) = server @@ -2169,48 +2135,8 @@ async fn federation_sort_different_indexes_same_criterion_opposite_direction() { #[actix_rt::test] async fn federation_sort_different_indexes_different_criterion_same_direction() { let server = Server::new_shared(); - - let movies_index = server.unique_index_with_prefix("movies"); - - let documents = DOCUMENTS.clone(); - let (value, _) = movies_index.add_documents(documents, None).await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = movies_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let batman_index = server.unique_index_with_prefix("batman"); - - let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = batman_index.add_documents(documents, None).await; - batman_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = batman_index - .update_settings(json!({ - "sortableAttributes": ["id"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - batman_index.wait_task(value.uid()).await.succeeded(); + let movies_index = shared_movies_index().await; + let batman_index = shared_batman_index().await; // return titles ordered across indexes let (response, code) = server @@ -2439,48 +2365,8 @@ async fn federation_sort_different_indexes_different_criterion_same_direction() #[actix_rt::test] async fn federation_sort_different_indexes_different_criterion_opposite_direction() { let server = Server::new_shared(); - - let movies_index = server.unique_index_with_prefix("movies"); - - let documents = DOCUMENTS.clone(); - let (value, _) = movies_index.add_documents(documents, None).await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = movies_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let batman_index = server.unique_index_with_prefix("batman"); - - let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = batman_index.add_documents(documents, None).await; - batman_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = batman_index - .update_settings(json!({ - "sortableAttributes": ["id"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - batman_index.wait_task(value.uid()).await.succeeded(); + let movies_index = shared_movies_index().await; + let batman_index = shared_batman_index().await; // all results from query 0 first let (response, code) = server @@ -4265,50 +4151,8 @@ async fn federation_vector_two_indexes() { #[actix_rt::test] async fn federation_facets_different_indexes_same_facet() { let server = Server::new_shared(); - - let movies_index = server.unique_index_with_prefix("movies"); - - let documents = DOCUMENTS.clone(); - let (value, _) = movies_index.add_documents(documents, None).await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = movies_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "filterableAttributes": ["title", "color"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let batman_index = server.unique_index_with_prefix("batman"); - - let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = batman_index.add_documents(documents, None).await; - batman_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = batman_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "filterableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - batman_index.wait_task(value.uid()).await.succeeded(); + let movies_index = shared_movies_index().await; + let batman_index = shared_batman_index().await; let batman_2_index = server.unique_index_with_prefix("batman_2"); @@ -5134,27 +4978,7 @@ async fn federation_facets_same_indexes() { async fn federation_inconsistent_merge_order() { let server = Server::new_shared(); - let movies_index = server.unique_index_with_prefix("movies"); - - let documents = DOCUMENTS.clone(); - let (value, _) = movies_index.add_documents(documents, None).await; - movies_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = movies_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "filterableAttributes": ["title", "color"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - movies_index.wait_task(value.uid()).await.succeeded(); + let movies_index = shared_movies_index().await; let movies2_index = server.unique_index_with_prefix("movies_2"); @@ -5181,27 +5005,7 @@ async fn federation_inconsistent_merge_order() { .await; movies2_index.wait_task(value.uid()).await.succeeded(); - let batman_index = server.unique_index_with_prefix("batman"); - - let documents = SCORE_DOCUMENTS.clone(); - let (value, _) = batman_index.add_documents(documents, None).await; - batman_index.wait_task(value.uid()).await.succeeded(); - - let (value, _) = batman_index - .update_settings(json!({ - "sortableAttributes": ["title"], - "filterableAttributes": ["title"], - "rankingRules": [ - "sort", - "words", - "typo", - "proximity", - "attribute", - "exactness" - ] - })) - .await; - batman_index.wait_task(value.uid()).await.succeeded(); + let batman_index = shared_batman_index().await; // without merging, it works let (response, code) = server From f3dd6834c616798dd214e0cbe5628db60db25dbc Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Thu, 12 Jun 2025 10:51:09 +0000 Subject: [PATCH 273/292] Update version for the next release (v1.15.2) in Cargo.toml --- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9975e5ed0..086335e61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -580,7 +580,7 @@ source = "git+https://github.com/meilisearch/bbqueue#cbb87cc707b5af415ef203bdaf2 [[package]] name = "benchmarks" -version = "1.15.1" +version = "1.15.2" dependencies = [ "anyhow", "bumpalo", @@ -791,7 +791,7 @@ dependencies = [ [[package]] name = "build-info" -version = "1.15.1" +version = "1.15.2" dependencies = [ "anyhow", "time", @@ -1787,7 +1787,7 @@ dependencies = [ [[package]] name = "dump" -version = "1.15.1" +version = "1.15.2" dependencies = [ "anyhow", "big_s", @@ -2009,7 +2009,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "file-store" -version = "1.15.1" +version = "1.15.2" dependencies = [ "tempfile", "thiserror 2.0.12", @@ -2031,7 +2031,7 @@ dependencies = [ [[package]] name = "filter-parser" -version = "1.15.1" +version = "1.15.2" dependencies = [ "insta", "nom", @@ -2051,7 +2051,7 @@ dependencies = [ [[package]] name = "flatten-serde-json" -version = "1.15.1" +version = "1.15.2" dependencies = [ "criterion", "serde_json", @@ -2196,7 +2196,7 @@ dependencies = [ [[package]] name = "fuzzers" -version = "1.15.1" +version = "1.15.2" dependencies = [ "arbitrary", "bumpalo", @@ -2996,7 +2996,7 @@ dependencies = [ [[package]] name = "index-scheduler" -version = "1.15.1" +version = "1.15.2" dependencies = [ "anyhow", "big_s", @@ -3231,7 +3231,7 @@ dependencies = [ [[package]] name = "json-depth-checker" -version = "1.15.1" +version = "1.15.2" dependencies = [ "criterion", "serde_json", @@ -3717,7 +3717,7 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "meili-snap" -version = "1.15.1" +version = "1.15.2" dependencies = [ "insta", "md5", @@ -3726,7 +3726,7 @@ dependencies = [ [[package]] name = "meilisearch" -version = "1.15.1" +version = "1.15.2" dependencies = [ "actix-cors", "actix-http", @@ -3822,7 +3822,7 @@ dependencies = [ [[package]] name = "meilisearch-auth" -version = "1.15.1" +version = "1.15.2" dependencies = [ "base64 0.22.1", "enum-iterator", @@ -3841,7 +3841,7 @@ dependencies = [ [[package]] name = "meilisearch-types" -version = "1.15.1" +version = "1.15.2" dependencies = [ "actix-web", "anyhow", @@ -3875,7 +3875,7 @@ dependencies = [ [[package]] name = "meilitool" -version = "1.15.1" +version = "1.15.2" dependencies = [ "anyhow", "clap", @@ -3909,7 +3909,7 @@ dependencies = [ [[package]] name = "milli" -version = "1.15.1" +version = "1.15.2" dependencies = [ "allocator-api2", "arroy", @@ -4414,7 +4414,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "permissive-json-pointer" -version = "1.15.1" +version = "1.15.2" dependencies = [ "big_s", "serde_json", @@ -7195,7 +7195,7 @@ dependencies = [ [[package]] name = "xtask" -version = "1.15.1" +version = "1.15.2" dependencies = [ "anyhow", "build-info", diff --git a/Cargo.toml b/Cargo.toml index 2ab980401..835ef497c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ members = [ ] [workspace.package] -version = "1.15.1" +version = "1.15.2" authors = [ "Quentin de Quelen ", "Clément Renault ", From 596617dd31576ba50d0e2d3939339c0e773f2a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 12 Jun 2025 13:45:05 +0200 Subject: [PATCH 274/292] Make sure Mistral base url is well defined --- crates/meilisearch/src/routes/chats/config.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/chats/config.rs b/crates/meilisearch/src/routes/chats/config.rs index 182eff735..24ba6bd07 100644 --- a/crates/meilisearch/src/routes/chats/config.rs +++ b/crates/meilisearch/src/routes/chats/config.rs @@ -24,7 +24,8 @@ impl Config { if let Some(api_key) = chat_settings.api_key.as_ref() { config = config.with_api_key(api_key); } - if let Some(base_url) = chat_settings.base_url.as_ref() { + let base_url = chat_settings.base_url.as_deref(); + if let Some(base_url) = chat_settings.source.base_url().or(base_url) { config = config.with_api_base(base_url); } Self::OpenAiCompatible(config) From 9ae73e3c05a8fe479d2a232eca79c45b4751d820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 12 Jun 2025 14:46:44 +0200 Subject: [PATCH 275/292] Better support for Mistral errors --- crates/meilisearch-types/src/features.rs | 2 +- .../src/routes/chats/chat_completions.rs | 17 ++- crates/meilisearch/src/routes/chats/errors.rs | 108 +++++++++++++----- 3 files changed, 92 insertions(+), 35 deletions(-) diff --git a/crates/meilisearch-types/src/features.rs b/crates/meilisearch-types/src/features.rs index 651077484..83054e784 100644 --- a/crates/meilisearch-types/src/features.rs +++ b/crates/meilisearch-types/src/features.rs @@ -107,7 +107,7 @@ impl ChatCompletionSettings { } } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default)] #[serde(rename_all = "camelCase")] pub enum ChatCompletionSource { #[default] diff --git a/crates/meilisearch/src/routes/chats/chat_completions.rs b/crates/meilisearch/src/routes/chats/chat_completions.rs index 7431609e6..8108e24dc 100644 --- a/crates/meilisearch/src/routes/chats/chat_completions.rs +++ b/crates/meilisearch/src/routes/chats/chat_completions.rs @@ -23,7 +23,10 @@ use futures::StreamExt; use index_scheduler::IndexScheduler; use meilisearch_auth::AuthController; use meilisearch_types::error::{Code, ResponseError}; -use meilisearch_types::features::{ChatCompletionPrompts as DbChatCompletionPrompts, SystemRole}; +use meilisearch_types::features::{ + ChatCompletionPrompts as DbChatCompletionPrompts, + ChatCompletionSource as DbChatCompletionSource, SystemRole, +}; use meilisearch_types::keys::actions; use meilisearch_types::milli::index::ChatConfig; use meilisearch_types::milli::{all_obkv_to_json, obkv_to_json, TimeBudget}; @@ -34,7 +37,7 @@ use tokio::runtime::Handle; use tokio::sync::mpsc::error::SendError; use super::config::Config; -use super::errors::StreamErrorEvent; +use super::errors::{MistralError, OpenAiOutsideError, StreamErrorEvent}; use super::utils::format_documents; use super::{ ChatsParam, MEILI_APPEND_CONVERSATION_MESSAGE_NAME, MEILI_SEARCH_IN_INDEX_FUNCTION_NAME, @@ -469,6 +472,7 @@ async fn streamed_chat( &search_queue, &auth_token, &client, + chat_settings.source, &mut chat_completion, &tx, &mut global_tool_calls, @@ -501,6 +505,7 @@ async fn run_conversation( search_queue: &web::Data, auth_token: &str, client: &Client, + source: DbChatCompletionSource, chat_completion: &mut CreateChatCompletionRequest, tx: &SseEventSender, global_tool_calls: &mut HashMap, @@ -595,7 +600,13 @@ async fn run_conversation( } } Err(error) => { - let error = StreamErrorEvent::from_openai_error(error).await.unwrap(); + let result = match source { + DbChatCompletionSource::Mistral => { + StreamErrorEvent::from_openai_error::(error).await + } + _ => StreamErrorEvent::from_openai_error::(error).await, + }; + let error = result.unwrap_or_else(StreamErrorEvent::from_reqwest_error); tx.send_error(&error).await?; return Ok(ControlFlow::Break(None)); } diff --git a/crates/meilisearch/src/routes/chats/errors.rs b/crates/meilisearch/src/routes/chats/errors.rs index efa60ba50..e7fb661ed 100644 --- a/crates/meilisearch/src/routes/chats/errors.rs +++ b/crates/meilisearch/src/routes/chats/errors.rs @@ -4,6 +4,39 @@ use meilisearch_types::error::ResponseError; use serde::{Deserialize, Serialize}; use uuid::Uuid; +/// The error type which is always `error`. +const ERROR_TYPE: &str = "error"; + +/// The error struct returned by the Mistral API. +/// +/// ```json +/// { +/// "object": "error", +/// "message": "Service tier capacity exceeded for this model.", +/// "type": "invalid_request_error", +/// "param": null, +/// "code": null +/// } +/// ``` +#[derive(Debug, Clone, Deserialize)] +pub struct MistralError { + message: String, + r#type: String, + param: Option, + code: Option, +} + +impl From for StreamErrorEvent { + fn from(error: MistralError) -> Self { + let MistralError { message, r#type, param, code } = error; + StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: ERROR_TYPE.to_owned(), + error: StreamError { r#type, code, message, param, event_id: None }, + } + } +} + #[derive(Debug, Clone, Deserialize)] pub struct OpenAiOutsideError { /// Emitted when an error occurs. @@ -23,6 +56,17 @@ pub struct OpenAiInnerError { r#type: String, } +impl From for StreamErrorEvent { + fn from(error: OpenAiOutsideError) -> Self { + let OpenAiOutsideError { error: OpenAiInnerError { code, message, param, r#type } } = error; + StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: ERROR_TYPE.to_string(), + error: StreamError { r#type, code, message, param, event_id: None }, + } + } +} + /// An error that occurs during the streaming process. /// /// It directly comes from the OpenAI API and you can @@ -54,13 +98,15 @@ pub struct StreamError { } impl StreamErrorEvent { - const ERROR_TYPE: &str = "error"; - - pub async fn from_openai_error(error: OpenAIError) -> Result { + pub async fn from_openai_error(error: OpenAIError) -> Result + where + E: serde::de::DeserializeOwned, + Self: From, + { match error { OpenAIError::Reqwest(e) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "internal_reqwest_error".to_string(), code: Some("internal".to_string()), @@ -71,7 +117,7 @@ impl StreamErrorEvent { }), OpenAIError::ApiError(ApiError { message, r#type, param, code }) => { Ok(StreamErrorEvent { - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), event_id: Uuid::new_v4().to_string(), error: StreamError { r#type: r#type.unwrap_or_else(|| "unknown".to_string()), @@ -84,7 +130,7 @@ impl StreamErrorEvent { } OpenAIError::JSONDeserialize(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "json_deserialize_error".to_string(), code: Some("internal".to_string()), @@ -96,30 +142,16 @@ impl StreamErrorEvent { OpenAIError::FileSaveError(_) | OpenAIError::FileReadError(_) => unreachable!(), OpenAIError::StreamError(error) => match error { EventSourceError::InvalidStatusCode(_status_code, response) => { - let OpenAiOutsideError { - error: OpenAiInnerError { code, message, param, r#type }, - } = response.json().await?; - - Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), - error: StreamError { r#type, code, message, param, event_id: None }, - }) + let error = response.json::().await?; + Ok(StreamErrorEvent::from(error)) } EventSourceError::InvalidContentType(_header_value, response) => { - let OpenAiOutsideError { - error: OpenAiInnerError { code, message, param, r#type }, - } = response.json().await?; - - Ok(StreamErrorEvent { - event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), - error: StreamError { r#type, code, message, param, event_id: None }, - }) + let error = response.json::().await?; + Ok(StreamErrorEvent::from(error)) } EventSourceError::Utf8(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "invalid_utf8_error".to_string(), code: None, @@ -130,7 +162,7 @@ impl StreamErrorEvent { }), EventSourceError::Parser(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "parser_error".to_string(), code: None, @@ -141,7 +173,7 @@ impl StreamErrorEvent { }), EventSourceError::Transport(error) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "transport_error".to_string(), code: None, @@ -152,7 +184,7 @@ impl StreamErrorEvent { }), EventSourceError::InvalidLastEventId(message) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "invalid_last_event_id".to_string(), code: None, @@ -163,7 +195,7 @@ impl StreamErrorEvent { }), EventSourceError::StreamEnded => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "stream_ended".to_string(), code: None, @@ -175,7 +207,7 @@ impl StreamErrorEvent { }, OpenAIError::InvalidArgument(message) => Ok(StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "invalid_argument".to_string(), code: None, @@ -191,7 +223,7 @@ impl StreamErrorEvent { let ResponseError { code, message, .. } = error; StreamErrorEvent { event_id: Uuid::new_v4().to_string(), - r#type: Self::ERROR_TYPE.to_string(), + r#type: ERROR_TYPE.to_string(), error: StreamError { r#type: "response_error".to_string(), code: Some(code.as_str().to_string()), @@ -201,4 +233,18 @@ impl StreamErrorEvent { }, } } + + pub fn from_reqwest_error(error: reqwest::Error) -> Self { + StreamErrorEvent { + event_id: Uuid::new_v4().to_string(), + r#type: ERROR_TYPE.to_string(), + error: StreamError { + r#type: "reqwest_error".to_string(), + code: None, + message: error.to_string(), + param: None, + event_id: None, + }, + } + } } From 396d76046de8adff191410c01cf4dbfb6bd86efd Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 12 Jun 2025 15:41:53 +0200 Subject: [PATCH 276/292] Regenerate embeddings more often: - When `regenerate` was previously `false` and became `true` - When rendering the old version of the docs failed --- .../src/update/new/extract/vectors/mod.rs | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/crates/milli/src/update/new/extract/vectors/mod.rs b/crates/milli/src/update/new/extract/vectors/mod.rs index 47bd622ae..0c727fa11 100644 --- a/crates/milli/src/update/new/extract/vectors/mod.rs +++ b/crates/milli/src/update/new/extract/vectors/mod.rs @@ -141,17 +141,31 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { context.new_fields_ids_map, &context.doc_alloc, )?; - let old_rendered = prompt.render_document( - update.external_document_id(), - update.merged( - &context.rtxn, - context.index, - context.db_fields_ids_map, - )?, - context.new_fields_ids_map, - &context.doc_alloc, - )?; - if new_rendered != old_rendered { + let must_regenerate = if !old_vectors.regenerate { + // we just enabled `regenerate` + true + } else { + let old_rendered = prompt.render_document( + update.external_document_id(), + update.merged( + &context.rtxn, + context.index, + context.db_fields_ids_map, + )?, + context.new_fields_ids_map, + &context.doc_alloc, + ); + + if let Ok(old_rendered) = old_rendered { + // must regenerate if the rendered changed + new_rendered != old_rendered + } else { + // cannot check previous rendered, better regenerate + true + } + }; + + if must_regenerate { chunks.set_autogenerated( update.docid(), update.external_document_id(), From 209c4bfc18112e5921008ad91073138f04dc7bb1 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 12 Jun 2025 15:47:47 +0200 Subject: [PATCH 277/292] Switch the versions of the documents for rendering :/ --- crates/milli/src/update/new/extract/vectors/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/milli/src/update/new/extract/vectors/mod.rs b/crates/milli/src/update/new/extract/vectors/mod.rs index 0c727fa11..77bfc1206 100644 --- a/crates/milli/src/update/new/extract/vectors/mod.rs +++ b/crates/milli/src/update/new/extract/vectors/mod.rs @@ -133,7 +133,7 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { } else if new_vectors.regenerate { let new_rendered = prompt.render_document( update.external_document_id(), - update.current( + update.merged( &context.rtxn, context.index, context.db_fields_ids_map, @@ -147,7 +147,7 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { } else { let old_rendered = prompt.render_document( update.external_document_id(), - update.merged( + update.current( &context.rtxn, context.index, context.db_fields_ids_map, From 68e7bfb37fd6334803664136ab31c98a299a8e77 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 12 Jun 2025 15:55:33 +0200 Subject: [PATCH 278/292] Don't fail if you cannot render previous version --- .../src/update/new/extract/vectors/mod.rs | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/crates/milli/src/update/new/extract/vectors/mod.rs b/crates/milli/src/update/new/extract/vectors/mod.rs index 77bfc1206..2864475c9 100644 --- a/crates/milli/src/update/new/extract/vectors/mod.rs +++ b/crates/milli/src/update/new/extract/vectors/mod.rs @@ -175,16 +175,6 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { } } } else if old_vectors.regenerate { - let old_rendered = prompt.render_document( - update.external_document_id(), - update.current( - &context.rtxn, - context.index, - context.db_fields_ids_map, - )?, - context.new_fields_ids_map, - &context.doc_alloc, - )?; let new_rendered = prompt.render_document( update.external_document_id(), update.merged( @@ -195,7 +185,28 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { context.new_fields_ids_map, &context.doc_alloc, )?; - if new_rendered != old_rendered { + + let must_regenerate = { + let old_rendered = prompt.render_document( + update.external_document_id(), + update.current( + &context.rtxn, + context.index, + context.db_fields_ids_map, + )?, + context.new_fields_ids_map, + &context.doc_alloc, + ); + if let Ok(old_rendered) = old_rendered { + // regenerate if the rendered version changed + new_rendered != old_rendered + } else { + // if we cannot render the previous version of the documents, let's regenerate + true + } + }; + + if must_regenerate { chunks.set_autogenerated( update.docid(), update.external_document_id(), From 72004372465895e09cb2e5599d412fb19687a016 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 12 Jun 2025 15:55:52 +0200 Subject: [PATCH 279/292] Comment the cases --- crates/milli/src/update/new/extract/vectors/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/milli/src/update/new/extract/vectors/mod.rs b/crates/milli/src/update/new/extract/vectors/mod.rs index 2864475c9..43647e786 100644 --- a/crates/milli/src/update/new/extract/vectors/mod.rs +++ b/crates/milli/src/update/new/extract/vectors/mod.rs @@ -111,6 +111,8 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { let prompt = chunks.prompt(); let old_vectors = old_vectors.vectors_for_key(embedder_name)?.unwrap(); + + // case where we have a `_vectors` field in the updated document if let Some(new_vectors) = new_vectors.as_ref().and_then(|new_vectors| { new_vectors.vectors_for_key(embedder_name).transpose() }) { @@ -130,6 +132,7 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { error: error.to_string(), })?, )?; + // regenerate if the new `_vectors` fields is set to. } else if new_vectors.regenerate { let new_rendered = prompt.render_document( update.external_document_id(), @@ -174,6 +177,7 @@ impl<'extractor> Extractor<'extractor> for EmbeddingExtractor<'_, '_> { )?; } } + // no `_vectors` field, so only regenerate if the document is already set to in the DB. } else if old_vectors.regenerate { let new_rendered = prompt.render_document( update.external_document_id(), From df4e3c2e438f3e89c2db621b3b88926a463f7769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Thu, 12 Jun 2025 15:48:26 +0200 Subject: [PATCH 280/292] Fix the version everywhere --- .../upgrade_failure/after_processing_everything.snap | 4 ++-- .../upgrade_failure/register_automatic_upgrade_task.snap | 2 +- .../registered_a_task_while_the_upgrade_task_is_enqueued.snap | 2 +- .../test_failure.rs/upgrade_failure/upgrade_task_failed.snap | 4 ++-- .../upgrade_failure/upgrade_task_failed_again.snap | 4 ++-- .../upgrade_failure/upgrade_task_succeeded.snap | 4 ++-- crates/meilisearch/tests/upgrade/mod.rs | 4 ++-- ...ches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...ches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...tches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...asks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...asks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap | 2 +- ...tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap | 2 +- ..._whole_batch_queue_once_everything_has_been_processed.snap | 2 +- ...e_whole_task_queue_once_everything_has_been_processed.snap | 2 +- 15 files changed, 20 insertions(+), 20 deletions(-) diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap index 83814339e..ee18cd1db 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/after_processing_everything.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 2) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, batch_uid: 1, status: succeeded, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} 2 {uid: 2, batch_uid: 2, status: succeeded, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} 3 {uid: 3, batch_uid: 3, status: failed, error: ResponseError { code: 200, message: "Index `doggo` already exists.", error_code: "index_already_exists", error_type: "invalid_request", error_link: "https://docs.meilisearch.com/errors#index_already_exists" }, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} @@ -57,7 +57,7 @@ girafo: { number_of_documents: 0, field_distribution: {} } [timestamp] [4,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.2"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } 1 {uid: 1, details: {"primaryKey":"mouse"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"catto":1}}, stop reason: "created batch containing only task with id 1 of type `indexCreation` that cannot be batched with any other task.", } 2 {uid: 2, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 2 of type `indexCreation` that cannot be batched with any other task.", } 3 {uid: 3, details: {"primaryKey":"bone"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"indexCreation":1},"indexUids":{"doggo":1}}, stop reason: "created batch containing only task with id 3 of type `indexCreation` that cannot be batched with any other task.", } diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap index 389afebda..9fa30ee2a 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/register_automatic_upgrade_task.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 2) }, kind: UpgradeDatabase { from: (1, 12, 0) }} ---------------------------------------------------------------------- ### Status: enqueued [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap index a6cb4edb3..162798cad 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/registered_a_task_while_the_upgrade_task_is_enqueued.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, status: enqueued, details: { from: (1, 12, 0), to: (1, 15, 2) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} ---------------------------------------------------------------------- ### Status: diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap index 21c399d66..8f615cb1c 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 2) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} ---------------------------------------------------------------------- ### Status: @@ -37,7 +37,7 @@ catto [1,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.2"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap index c71c4082b..a5f9be6e1 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_failed_again.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: failed, error: ResponseError { code: 200, message: "Planned failure for tests.", error_code: "internal", error_type: "internal", error_link: "https://docs.meilisearch.com/errors#internal" }, details: { from: (1, 12, 0), to: (1, 15, 2) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} 2 {uid: 2, status: enqueued, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} ---------------------------------------------------------------------- @@ -40,7 +40,7 @@ doggo [2,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.2"}, stats: {"totalNbTasks":1,"status":{"failed":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap index ad75252d4..eb738d626 100644 --- a/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap +++ b/crates/index-scheduler/src/scheduler/snapshots/test_failure.rs/upgrade_failure/upgrade_task_succeeded.snap @@ -6,7 +6,7 @@ source: crates/index-scheduler/src/scheduler/test_failure.rs [] ---------------------------------------------------------------------- ### All Tasks: -0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 1) }, kind: UpgradeDatabase { from: (1, 12, 0) }} +0 {uid: 0, batch_uid: 0, status: succeeded, details: { from: (1, 12, 0), to: (1, 15, 2) }, kind: UpgradeDatabase { from: (1, 12, 0) }} 1 {uid: 1, status: enqueued, details: { primary_key: Some("mouse") }, kind: IndexCreation { index_uid: "catto", primary_key: Some("mouse") }} 2 {uid: 2, status: enqueued, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} 3 {uid: 3, status: enqueued, details: { primary_key: Some("bone") }, kind: IndexCreation { index_uid: "doggo", primary_key: Some("bone") }} @@ -43,7 +43,7 @@ doggo [2,3,] [timestamp] [0,] ---------------------------------------------------------------------- ### All Batches: -0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.1"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } +0 {uid: 0, details: {"upgradeFrom":"v1.12.0","upgradeTo":"v1.15.2"}, stats: {"totalNbTasks":1,"status":{"succeeded":1},"types":{"upgradeDatabase":1},"indexUids":{}}, stop reason: "stopped after the last task of type `upgradeDatabase` because they cannot be batched with tasks of any other type.", } ---------------------------------------------------------------------- ### Batch to tasks mapping: 0 [0,] diff --git a/crates/meilisearch/tests/upgrade/mod.rs b/crates/meilisearch/tests/upgrade/mod.rs index 8a91d9057..4faa7e0c0 100644 --- a/crates/meilisearch/tests/upgrade/mod.rs +++ b/crates/meilisearch/tests/upgrade/mod.rs @@ -43,7 +43,7 @@ async fn version_too_old() { std::fs::write(db_path.join("VERSION"), "1.11.9999").unwrap(); let options = Opt { experimental_dumpless_upgrade: true, ..default_settings }; let err = Server::new_with_options(options).await.map(|_| ()).unwrap_err(); - snapshot!(err, @"Database version 1.11.9999 is too old for the experimental dumpless upgrade feature. Please generate a dump using the v1.11.9999 and import it in the v1.15.1"); + snapshot!(err, @"Database version 1.11.9999 is too old for the experimental dumpless upgrade feature. Please generate a dump using the v1.11.9999 and import it in the v1.15.2"); } #[actix_rt::test] @@ -58,7 +58,7 @@ async fn version_requires_downgrade() { std::fs::write(db_path.join("VERSION"), format!("{major}.{minor}.{patch}")).unwrap(); let options = Opt { experimental_dumpless_upgrade: true, ..default_settings }; let err = Server::new_with_options(options).await.map(|_| ()).unwrap_err(); - snapshot!(err, @"Database version 1.15.2 is higher than the Meilisearch version 1.15.1. Downgrade is not supported"); + snapshot!(err, @"Database version 1.15.3 is higher than the Meilisearch version 1.15.2. Downgrade is not supported"); } #[actix_rt::test] diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap index 3484efdfe..4355b9213 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap index 3484efdfe..4355b9213 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap index 3484efdfe..4355b9213 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/batches_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap index a37202b3e..ebe246ee5 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterEnqueuedAt_equal_2025-01-16T16_47_41.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "error": null, "duration": "[duration]", diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap index a37202b3e..ebe246ee5 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterFinishedAt_equal_2025-01-16T16_47_41.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "error": null, "duration": "[duration]", diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap index a37202b3e..ebe246ee5 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/tasks_filter_afterStartedAt_equal_2025-01-16T16_47_41.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "error": null, "duration": "[duration]", diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap index 4923b3d15..c2d7967f0 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_batch_queue_once_everything_has_been_processed.snap @@ -8,7 +8,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "progress": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "stats": { "totalNbTasks": 1, diff --git a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap index 29e11e738..52da67fef 100644 --- a/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap +++ b/crates/meilisearch/tests/upgrade/v1_12/snapshots/v1_12_0.rs/check_the_index_scheduler/the_whole_task_queue_once_everything_has_been_processed.snap @@ -12,7 +12,7 @@ source: crates/meilisearch/tests/upgrade/v1_12/v1_12_0.rs "canceledBy": null, "details": { "upgradeFrom": "v1.12.0", - "upgradeTo": "v1.15.1" + "upgradeTo": "v1.15.2" }, "error": null, "duration": "[duration]", From 2269104337b6d38e7b1d25ab5b84cfa6f5c5c289 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Sat, 14 Jun 2025 13:35:03 +0300 Subject: [PATCH 281/292] Use unique_index_with_prefix() instead of composing the index names manually with Uuid Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 8c6e45c74..8ddcb2cdc 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -1,6 +1,5 @@ use meili_snap::{json_string, snapshot}; use tokio::sync::OnceCell; -use uuid::Uuid; use super::{DOCUMENTS, FRUITS_DOCUMENTS, NESTED_DOCUMENTS}; use crate::common::index::Index; @@ -849,13 +848,13 @@ async fn federation_one_index_doesnt_exist() { async fn search_multiple_indexes_dont_exist() { let server = Server::new_shared(); - let index_1 = format!("index_1-{}", Uuid::new_v4()); - let index_2 = format!("index_2-{}", Uuid::new_v4()); + let index_1 = server.unique_index_with_prefix("index_1"); + let index_2 = server.unique_index_with_prefix("index_2"); let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : index_1, "q": "glass"}, - {"indexUid": index_2, "q": "pésti"}, + {"indexUid" : index_1.uid, "q": "glass"}, + {"indexUid": index_2.uid, "q": "pésti"}, ]})) .await; snapshot!(code, @"400 Bad Request"); @@ -873,13 +872,13 @@ async fn search_multiple_indexes_dont_exist() { async fn federation_multiple_indexes_dont_exist() { let server = Server::new_shared(); - let index_1 = format!("index_1-{}", Uuid::new_v4()); - let index_2 = format!("index_2-{}", Uuid::new_v4()); + let index_1 = server.unique_index_with_prefix("index_1"); + let index_2 = server.unique_index_with_prefix("index_2"); let (response, code) = server .multi_search(json!({"federation": {}, "queries": [ - {"indexUid" : index_1, "q": "glass"}, - {"indexUid": index_2, "q": "pésti"}, + {"indexUid" : index_1.uid, "q": "glass"}, + {"indexUid": index_2.uid, "q": "pésti"}, ]})) .await; snapshot!(code, @"400 Bad Request"); From 059832025231ae2ce399ee85e36e13cf1d65b67a Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Sat, 14 Jun 2025 14:07:57 +0300 Subject: [PATCH 282/292] Try to debug the problem with the existing "test" index in a shared server Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index 8ddcb2cdc..f136fd4eb 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -848,19 +848,20 @@ async fn federation_one_index_doesnt_exist() { async fn search_multiple_indexes_dont_exist() { let server = Server::new_shared(); - let index_1 = server.unique_index_with_prefix("index_1"); - let index_2 = server.unique_index_with_prefix("index_2"); - let (response, code) = server .multi_search(json!({"queries": [ - {"indexUid" : index_1.uid, "q": "glass"}, - {"indexUid": index_2.uid, "q": "pésti"}, + {"indexUid" : "test", "q": "glass"}, + {"indexUid": "nested", "q": "pésti"}, ]})) .await; snapshot!(code, @"400 Bad Request"); + + let (list_response, _code) = server.list_indexes(Some(0), Some(1_000_000)).await; + dbg!(list_response); + snapshot!(json_string!(response), @r###" { - "message": "Inside `.queries[0]`: Index `index_1-[uuid]` not found.", + "message": "Inside `.queries[0]`: Index `test` not found.", "code": "index_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#index_not_found" From 95e8a9bef1f5718e8332b4fc10e3b83c4c7ea97c Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Sat, 14 Jun 2025 15:10:48 +0300 Subject: [PATCH 283/292] Use a unique name for an index in a shared server Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/index/create_index.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/index/create_index.rs b/crates/meilisearch/tests/index/create_index.rs index e8efd14e2..3422e8b3f 100644 --- a/crates/meilisearch/tests/index/create_index.rs +++ b/crates/meilisearch/tests/index/create_index.rs @@ -46,8 +46,10 @@ async fn create_index_with_gzip_encoded_request_and_receiving_brotli_encoded_res let server = Server::new_shared(); let app = server.init_web_app().await; + let index = server.unique_index_with_prefix("test"); + let body = serde_json::to_string(&json!({ - "uid": "test", + "uid": index.uid.clone(), "primaryKey": None::<&str>, })) .unwrap(); @@ -68,7 +70,7 @@ async fn create_index_with_gzip_encoded_request_and_receiving_brotli_encoded_res let parsed_response = serde_json::from_slice::(decoded.into().as_ref()).expect("Expecting valid json"); - assert_eq!(parsed_response["indexUid"], "test"); + assert_eq!(parsed_response["indexUid"], index.uid); } #[actix_rt::test] From 6ee608c2d1b5ffef23118af8972dd0bf38aa8f83 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Sat, 14 Jun 2025 15:45:04 +0300 Subject: [PATCH 284/292] Remove debug leftovers Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/multi/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/meilisearch/tests/search/multi/mod.rs b/crates/meilisearch/tests/search/multi/mod.rs index f136fd4eb..cf98baa10 100644 --- a/crates/meilisearch/tests/search/multi/mod.rs +++ b/crates/meilisearch/tests/search/multi/mod.rs @@ -855,10 +855,6 @@ async fn search_multiple_indexes_dont_exist() { ]})) .await; snapshot!(code, @"400 Bad Request"); - - let (list_response, _code) = server.list_indexes(Some(0), Some(1_000_000)).await; - dbg!(list_response); - snapshot!(json_string!(response), @r###" { "message": "Inside `.queries[0]`: Index `test` not found.", From 0e10ff1aa3b524c621341284f887c2c92a763d82 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 16 Jun 2025 09:21:47 +0300 Subject: [PATCH 285/292] docs: Recommend using a custom path for the benches' data This reduces the build time of the `benchmarks` crate from ~220secs to 45secs (according to `cargo build --timings`) on my dev machine Additionally I've introduced a parent folder for the Meili related cache paths - ~/.cache/meili Signed-off-by: Martin Tzvetanov Grigorov --- CONTRIBUTING.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e129e5600..57d52116e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,9 +57,17 @@ This command will be triggered to each PR as a requirement for merging it. You can set the `LINDERA_CACHE` environment variable to speed up your successive builds by up to 2 minutes. It'll store some built artifacts in the directory of your choice. -We recommend using the standard `$HOME/.cache/lindera` directory: +We recommend using the `$HOME/.cache/meili/lindera` directory: ```sh -export LINDERA_CACHE=$HOME/.cache/lindera +export LINDERA_CACHE=$HOME/.cache/meili/lindera +``` + +You can set the `MILLI_BENCH_DATASETS_PATH` environment variable to further speed up your builds. +It'll store some big files used for the benchmarks in the directory of your choice. + +We recommend using the `$HOME/.cache/meili/benches` directory: +```sh +export MILLI_BENCH_DATASETS_PATH=$HOME/.cache/meili/benches ``` Furthermore, you can improve incremental compilation by setting the `MEILI_NO_VERGEN` environment variable. From 60f105a4a32360ab1475b2abaf397bc40360a6c9 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 16 Jun 2025 16:25:15 +0300 Subject: [PATCH 286/292] tests: Faster document::errors IT tests * Add a call to .failed() for an awaited task * Use Server::wait_task() instead of Index::wait_task() - it has better error checking Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/documents/errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/documents/errors.rs b/crates/meilisearch/tests/documents/errors.rs index afca9498b..506be97d5 100644 --- a/crates/meilisearch/tests/documents/errors.rs +++ b/crates/meilisearch/tests/documents/errors.rs @@ -621,7 +621,7 @@ async fn delete_document_by_filter() { let (response, code) = index.delete_document_by_filter_fail(json!({ "filter": "catto = jorts"})).await; snapshot!(code, @"202 Accepted"); - let response = server.wait_task(response.uid()).await; + let response = server.wait_task(response.uid()).await.failed(); snapshot!(response, @r###" { "uid": "[uid]", @@ -665,7 +665,7 @@ async fn fetch_document_by_filter() { Some("id"), ) .await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (response, code) = index.fetch_documents(json!(null)).await; snapshot!(code, @"400 Bad Request"); From fe9866aca84553796dba7c73bc7d5a17909c229f Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 16 Jun 2025 22:51:07 +0300 Subject: [PATCH 287/292] tests: Faster similar::mod IT tests Use shared server + unique indexes Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/similar/mod.rs | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/meilisearch/tests/similar/mod.rs b/crates/meilisearch/tests/similar/mod.rs index defb777e0..fdfcc1665 100644 --- a/crates/meilisearch/tests/similar/mod.rs +++ b/crates/meilisearch/tests/similar/mod.rs @@ -47,8 +47,8 @@ static DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn basic() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ @@ -61,12 +61,12 @@ async fn basic() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - index.wait_task(value.uid()).await.succeeded(); + server.wait_task(value.uid()).await.succeeded(); index .similar( @@ -233,8 +233,8 @@ async fn basic() { #[actix_rt::test] async fn ranking_score_threshold() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ @@ -247,12 +247,12 @@ async fn ranking_score_threshold() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - index.wait_task(value.uid()).await.succeeded(); + server.wait_task(value.uid()).await.succeeded(); index .similar( @@ -503,8 +503,8 @@ async fn ranking_score_threshold() { #[actix_rt::test] async fn filter() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ @@ -517,12 +517,12 @@ async fn filter() { "filterableAttributes": ["title", "release_year"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - index.wait_task(value.uid()).await.succeeded(); + server.wait_task(value.uid()).await.succeeded(); index .similar( @@ -621,8 +621,8 @@ async fn filter() { #[actix_rt::test] async fn limit_and_offset() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ @@ -635,12 +635,12 @@ async fn limit_and_offset() { "filterableAttributes": ["title"]})) .await; snapshot!(code, @"202 Accepted"); - server.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let documents = DOCUMENTS.clone(); let (value, code) = index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - index.wait_task(value.uid()).await.succeeded(); + server.wait_task(value.uid()).await.succeeded(); index .similar( From 056f18bd02a735aeaac05e070e795c822f4113f2 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 16 Jun 2025 23:20:11 +0300 Subject: [PATCH 288/292] tests: Faster settings::prefix_search_settings IT tests Use shared server + unique indices Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/settings/prefix_search_settings.rs | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/crates/meilisearch/tests/settings/prefix_search_settings.rs b/crates/meilisearch/tests/settings/prefix_search_settings.rs index 5da758a7d..81e1f40fc 100644 --- a/crates/meilisearch/tests/settings/prefix_search_settings.rs +++ b/crates/meilisearch/tests/settings/prefix_search_settings.rs @@ -26,11 +26,11 @@ static DOCUMENTS: Lazy = Lazy::new(|| { #[actix_rt::test] async fn add_docs_and_disable() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, _code) = index.add_documents(DOCUMENTS.clone(), None).await; - index.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index .update_settings(json!({ @@ -38,8 +38,8 @@ async fn add_docs_and_disable() { "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + server.wait_task(response.uid()).await.succeeded(); // only 1 document should match index @@ -86,8 +86,8 @@ async fn add_docs_and_disable() { #[actix_rt::test] async fn disable_and_add_docs() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ @@ -95,11 +95,11 @@ async fn disable_and_add_docs() { "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + server.wait_task(response.uid()).await.succeeded(); let (response, _code) = index.add_documents(DOCUMENTS.clone(), None).await; - index.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); // only 1 document should match index @@ -145,8 +145,8 @@ async fn disable_and_add_docs() { #[actix_rt::test] async fn disable_add_docs_and_enable() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ @@ -154,11 +154,11 @@ async fn disable_add_docs_and_enable() { "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + server.wait_task(response.uid()).await.succeeded(); let (response, _code) = index.add_documents(DOCUMENTS.clone(), None).await; - index.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index .update_settings(json!({ @@ -166,8 +166,8 @@ async fn disable_add_docs_and_enable() { "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(2).await; + assert_eq!("202", code.as_str(), "{response:?}"); + server.wait_task(response.uid()).await.succeeded(); // all documents should match index @@ -253,8 +253,8 @@ async fn disable_add_docs_and_enable() { #[actix_rt::test] async fn disable_add_docs_and_reset() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ @@ -262,11 +262,11 @@ async fn disable_add_docs_and_reset() { "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + server.wait_task(response.uid()).await.succeeded(); let (response, _code) = index.add_documents(DOCUMENTS.clone(), None).await; - index.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); let (response, code) = index .update_settings(json!({ @@ -274,8 +274,8 @@ async fn disable_add_docs_and_reset() { "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(2).await; + assert_eq!("202", code.as_str(), "{response:?}"); + server.wait_task(response.uid()).await.succeeded(); // all documents should match index @@ -361,19 +361,19 @@ async fn disable_add_docs_and_reset() { #[actix_rt::test] async fn default_behavior() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("test"); let (response, code) = index .update_settings(json!({ "rankingRules": ["words", "typo", "proximity"], })) .await; - assert_eq!("202", code.as_str(), "{:?}", response); - index.wait_task(response.uid()).await; + assert_eq!("202", code.as_str(), "{response:?}"); + server.wait_task(response.uid()).await.succeeded(); let (response, _code) = index.add_documents(DOCUMENTS.clone(), None).await; - index.wait_task(response.uid()).await; + server.wait_task(response.uid()).await.succeeded(); // all documents should match index From 8bfa6a7f54b763e933a5279b615e20f50f9ac3c4 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 16 Jun 2025 23:48:59 +0300 Subject: [PATCH 289/292] tests: Faster documents::update_documents IT tests Use a shared server + unique index Signed-off-by: Martin Tzvetanov Grigorov --- .../tests/documents/update_documents.rs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/meilisearch/tests/documents/update_documents.rs b/crates/meilisearch/tests/documents/update_documents.rs index aaf529ce5..534be1fe6 100644 --- a/crates/meilisearch/tests/documents/update_documents.rs +++ b/crates/meilisearch/tests/documents/update_documents.rs @@ -6,19 +6,18 @@ use crate::json; #[actix_rt::test] async fn error_document_update_create_index_bad_uid() { - let server = Server::new().await; - let index = server.index("883 fj!"); + let server = Server::new_shared(); + let index = server.unique_index_with_prefix("883 fj!"); let (response, code) = index.update_documents(json!([{"id": 1}]), None).await; - let expected_response = json!({ - "message": "`883 fj!` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_), and can not be more than 512 bytes.", - "code": "invalid_index_uid", - "type": "invalid_request", - "link": "https://docs.meilisearch.com/errors#invalid_index_uid" - }); - - assert_eq!(code, 400); - assert_eq!(response, expected_response); + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "`883 fj!-[uuid]` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_), and can not be more than 512 bytes.", + "code": "invalid_index_uid", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_index_uid" + }"###); } #[actix_rt::test] From 03eb50fbace85cebdbee7c5e4c388b9be448d3aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 17 Jun 2025 22:03:06 +0200 Subject: [PATCH 290/292] Upgrade dependencies --- Cargo.lock | 197 +++++++++++----------------- crates/benchmarks/Cargo.toml | 20 +-- crates/build-info/Cargo.toml | 6 +- crates/dump/Cargo.toml | 24 ++-- crates/file-store/Cargo.toml | 6 +- crates/filter-parser/Cargo.toml | 2 +- crates/fuzzers/Cargo.toml | 12 +- crates/index-scheduler/Cargo.toml | 22 ++-- crates/meili-snap/Cargo.toml | 2 +- crates/meilisearch-auth/Cargo.toml | 14 +- crates/meilisearch-types/Cargo.toml | 32 ++--- crates/meilisearch/Cargo.toml | 84 ++++++------ crates/meilitool/Cargo.toml | 16 +-- crates/milli/Cargo.toml | 50 +++---- crates/tracing-trace/Cargo.toml | 6 +- crates/xtask/Cargo.toml | 20 +-- 16 files changed, 233 insertions(+), 280 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1f50638bb..45311fb88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -800,9 +800,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" dependencies = [ "allocator-api2", "serde", @@ -817,7 +817,7 @@ dependencies = [ "allocator-api2", "bitpacking", "bumpalo", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "serde", "serde_json", ] @@ -863,9 +863,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] @@ -1160,9 +1160,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -1170,9 +1170,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.39" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -1182,9 +1182,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", @@ -2041,9 +2041,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -2063,7 +2063,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -2632,9 +2632,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", @@ -3040,7 +3040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "serde", ] @@ -3341,7 +3341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.52.6", ] [[package]] @@ -3352,9 +3352,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libmimalloc-sys" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4" +checksum = "bf88cd67e9de251c1781dbe2f641a1a3ad66eaae831b8a2c38fbdc5ddae16d4d" dependencies = [ "cc", "libc", @@ -3645,7 +3645,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" dependencies = [ - "hashbrown 0.15.3", + "hashbrown 0.15.4", ] [[package]] @@ -3895,9 +3895,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -3942,7 +3942,7 @@ dependencies = [ "fxhash", "geoutils", "grenad", - "hashbrown 0.15.3", + "hashbrown 0.15.4", "heed", "hf-hub", "indexmap", @@ -3990,9 +3990,9 @@ dependencies = [ [[package]] name = "mimalloc" -version = "0.1.46" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af" +checksum = "b1791cbe101e95af5764f06f20f6760521f7158f69dbf9d6baf941ee1bf6bc40" dependencies = [ "libmimalloc-sys", ] @@ -4073,6 +4073,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" +dependencies = [ + "spin 0.5.2", +] + [[package]] name = "nohash" version = "0.2.0" @@ -4266,6 +4275,9 @@ name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +dependencies = [ + "portable-atomic", +] [[package]] name = "once_cell_polyfill" @@ -5028,9 +5040,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.19" +version = "0.12.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119" +checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" dependencies = [ "base64 0.22.1", "bytes", @@ -5043,12 +5055,9 @@ dependencies = [ "hyper", "hyper-rustls", "hyper-util", - "ipnet", "js-sys", "log", - "mime", "mime_guess", - "once_cell", "percent-encoding", "pin-project-lite", "quinn", @@ -5091,12 +5100,14 @@ dependencies = [ [[package]] name = "rhai" -version = "1.20.0" -source = "git+https://github.com/rhaiscript/rhai?rev=ef3df63121d27aacd838f366f2b83fd65f20a1e4#ef3df63121d27aacd838f366f2b83fd65f20a1e4" +version = "1.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2780e813b755850e50b178931aaf94ed24f6817f46aaaf5d21c13c12d939a249" dependencies = [ "ahash 0.8.12", "bitflags 2.9.1", "instant", + "no-std-compat", "num-traits", "once_cell", "rhai_codegen", @@ -5109,7 +5120,8 @@ dependencies = [ [[package]] name = "rhai_codegen" version = "2.2.0" -source = "git+https://github.com/rhaiscript/rhai?rev=ef3df63121d27aacd838f366f2b83fd65f20a1e4#ef3df63121d27aacd838f366f2b83fd65f20a1e4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a11a05ee1ce44058fa3d5961d05194fdbe3ad6b40f904af764d81b86450e6b" dependencies = [ "proc-macro2", "quote", @@ -5250,9 +5262,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.27" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "log", "once_cell", @@ -5495,9 +5507,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -5647,9 +5659,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] @@ -5687,6 +5699,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -5716,9 +5734,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static-files" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e8590e848e1c53be9258210bcd4a8f4118e08988f03a4e2d63b62e4ad9f7ced" +checksum = "f9c425c07353535ef55b45420f5a8b0a397cd9bc3d7e5236497ca0d90604aa9b" dependencies = [ "change-detection", "mime_guess", @@ -5963,12 +5981,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -6159,9 +6176,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -6171,18 +6188,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -6194,9 +6211,9 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower" @@ -6552,9 +6569,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "utoipa" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435c6f69ef38c9017b4b4eea965dfb91e71e53d869e896db40d1cf2441dd75c0" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" dependencies = [ "indexmap", "serde", @@ -6564,9 +6581,9 @@ dependencies = [ [[package]] name = "utoipa-gen" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77d306bc75294fd52f3e99b13ece67c02c1a2789190a6f31d32f736624326f7" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" dependencies = [ "proc-macro2", "quote", @@ -6967,29 +6984,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -7002,12 +7003,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -7020,12 +7015,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -7038,24 +7027,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -7068,12 +7045,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -7086,12 +7057,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -7104,12 +7069,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -7122,12 +7081,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.7.10" diff --git a/crates/benchmarks/Cargo.toml b/crates/benchmarks/Cargo.toml index a5b3a39e1..f9ad77bf6 100644 --- a/crates/benchmarks/Cargo.toml +++ b/crates/benchmarks/Cargo.toml @@ -11,27 +11,27 @@ edition.workspace = true license.workspace = true [dependencies] -anyhow = "1.0.95" -bumpalo = "3.16.0" +anyhow = "1.0.98" +bumpalo = "3.18.1" csv = "1.3.1" memmap2 = "0.9.5" milli = { path = "../milli" } -mimalloc = { version = "0.1.43", default-features = false } -serde_json = { version = "1.0.135", features = ["preserve_order"] } -tempfile = "3.15.0" +mimalloc = { version = "0.1.47", default-features = false } +serde_json = { version = "1.0.140", features = ["preserve_order"] } +tempfile = "3.20.0" [dev-dependencies] criterion = { version = "0.5.1", features = ["html_reports"] } rand = "0.8.5" rand_chacha = "0.3.1" -roaring = "0.10.10" +roaring = "0.10.12" [build-dependencies] -anyhow = "1.0.95" -bytes = "1.9.0" +anyhow = "1.0.98" +bytes = "1.10.1" convert_case = "0.6.0" -flate2 = "1.0.35" -reqwest = { version = "0.12.15", features = ["blocking", "rustls-tls"], default-features = false } +flate2 = "1.1.2" +reqwest = { version = "0.12.20", features = ["blocking", "rustls-tls"], default-features = false } [features] default = ["milli/all-tokenizations"] diff --git a/crates/build-info/Cargo.toml b/crates/build-info/Cargo.toml index f8ede756e..ca8754b81 100644 --- a/crates/build-info/Cargo.toml +++ b/crates/build-info/Cargo.toml @@ -11,8 +11,8 @@ license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -time = { version = "0.3.37", features = ["parsing"] } +time = { version = "0.3.41", features = ["parsing"] } [build-dependencies] -anyhow = "1.0.95" -vergen-git2 = "1.0.2" +anyhow = "1.0.98" +vergen-git2 = "1.0.7" diff --git a/crates/dump/Cargo.toml b/crates/dump/Cargo.toml index 5c427916c..4b8a49aa0 100644 --- a/crates/dump/Cargo.toml +++ b/crates/dump/Cargo.toml @@ -11,21 +11,21 @@ readme.workspace = true license.workspace = true [dependencies] -anyhow = "1.0.95" -flate2 = "1.0.35" -http = "1.2.0" +anyhow = "1.0.98" +flate2 = "1.1.2" +http = "1.3.1" meilisearch-types = { path = "../meilisearch-types" } -once_cell = "1.20.2" +once_cell = "1.21.3" regex = "1.11.1" -roaring = { version = "0.10.10", features = ["serde"] } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = { version = "1.0.135", features = ["preserve_order"] } -tar = "0.4.43" -tempfile = "3.15.0" -thiserror = "2.0.9" -time = { version = "0.3.37", features = ["serde-well-known", "formatting", "parsing", "macros"] } +roaring = { version = "0.10.12", features = ["serde"] } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.140", features = ["preserve_order"] } +tar = "0.4.44" +tempfile = "3.20.0" +thiserror = "2.0.12" +time = { version = "0.3.41", features = ["serde-well-known", "formatting", "parsing", "macros"] } tracing = "0.1.41" -uuid = { version = "1.11.0", features = ["serde", "v4"] } +uuid = { version = "1.17.0", features = ["serde", "v4"] } [dev-dependencies] big_s = "1.0.2" diff --git a/crates/file-store/Cargo.toml b/crates/file-store/Cargo.toml index 66ea65336..864b9caff 100644 --- a/crates/file-store/Cargo.toml +++ b/crates/file-store/Cargo.toml @@ -11,7 +11,7 @@ edition.workspace = true license.workspace = true [dependencies] -tempfile = "3.15.0" -thiserror = "2.0.9" +tempfile = "3.20.0" +thiserror = "2.0.12" tracing = "0.1.41" -uuid = { version = "1.11.0", features = ["serde", "v4"] } +uuid = { version = "1.17.0", features = ["serde", "v4"] } diff --git a/crates/filter-parser/Cargo.toml b/crates/filter-parser/Cargo.toml index 2657315a4..6eeb0794b 100644 --- a/crates/filter-parser/Cargo.toml +++ b/crates/filter-parser/Cargo.toml @@ -14,7 +14,7 @@ license.workspace = true [dependencies] nom = "7.1.3" nom_locate = "4.2.0" -unescaper = "0.1.5" +unescaper = "0.1.6" [dev-dependencies] # fixed version due to format breakages in v1.40 diff --git a/crates/fuzzers/Cargo.toml b/crates/fuzzers/Cargo.toml index a838350ba..6daf95904 100644 --- a/crates/fuzzers/Cargo.toml +++ b/crates/fuzzers/Cargo.toml @@ -12,11 +12,11 @@ license.workspace = true [dependencies] arbitrary = { version = "1.4.1", features = ["derive"] } -bumpalo = "3.16.0" -clap = { version = "4.5.24", features = ["derive"] } -either = "1.13.0" +bumpalo = "3.18.1" +clap = { version = "4.5.40", features = ["derive"] } +either = "1.15.0" fastrand = "2.3.0" milli = { path = "../milli" } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = { version = "1.0.135", features = ["preserve_order"] } -tempfile = "3.15.0" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.140", features = ["preserve_order"] } +tempfile = "3.20.0" diff --git a/crates/index-scheduler/Cargo.toml b/crates/index-scheduler/Cargo.toml index b4f187729..6ca1a0aa6 100644 --- a/crates/index-scheduler/Cargo.toml +++ b/crates/index-scheduler/Cargo.toml @@ -11,10 +11,10 @@ edition.workspace = true license.workspace = true [dependencies] -anyhow = "1.0.95" +anyhow = "1.0.98" bincode = "1.3.3" byte-unit = "5.1.6" -bumpalo = "3.16.0" +bumpalo = "3.18.1" bumparaw-collections = "0.1.4" convert_case = "0.6.0" csv = "1.3.1" @@ -22,20 +22,20 @@ derive_builder = "0.20.2" dump = { path = "../dump" } enum-iterator = "2.1.0" file-store = { path = "../file-store" } -flate2 = "1.0.35" -indexmap = "2.7.0" +flate2 = "1.1.2" +indexmap = "2.9.0" meilisearch-auth = { path = "../meilisearch-auth" } meilisearch-types = { path = "../meilisearch-types" } memmap2 = "0.9.5" page_size = "0.6.0" rayon = "1.10.0" -roaring = { version = "0.10.10", features = ["serde"] } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = { version = "1.0.138", features = ["preserve_order"] } +roaring = { version = "0.10.12", features = ["serde"] } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.140", features = ["preserve_order"] } synchronoise = "1.0.1" -tempfile = "3.15.0" -thiserror = "2.0.9" -time = { version = "0.3.37", features = [ +tempfile = "3.20.0" +thiserror = "2.0.12" +time = { version = "0.3.41", features = [ "serde-well-known", "formatting", "parsing", @@ -43,7 +43,7 @@ time = { version = "0.3.37", features = [ ] } tracing = "0.1.41" ureq = "2.12.1" -uuid = { version = "1.11.0", features = ["serde", "v4"] } +uuid = { version = "1.17.0", features = ["serde", "v4"] } [dev-dependencies] big_s = "1.0.2" diff --git a/crates/meili-snap/Cargo.toml b/crates/meili-snap/Cargo.toml index be96769ab..42b900e5a 100644 --- a/crates/meili-snap/Cargo.toml +++ b/crates/meili-snap/Cargo.toml @@ -14,6 +14,6 @@ license.workspace = true # fixed version due to format breakages in v1.40 insta = { version = "=1.39.0", features = ["json", "redactions"] } md5 = "0.7.0" -once_cell = "1.20" +once_cell = "1.21" regex-lite = "0.1.6" uuid = { version = "1.17.0", features = ["v4"] } diff --git a/crates/meilisearch-auth/Cargo.toml b/crates/meilisearch-auth/Cargo.toml index d31effd6e..30eb8125b 100644 --- a/crates/meilisearch-auth/Cargo.toml +++ b/crates/meilisearch-auth/Cargo.toml @@ -17,10 +17,10 @@ hmac = "0.12.1" maplit = "1.0.2" meilisearch-types = { path = "../meilisearch-types" } rand = "0.8.5" -roaring = { version = "0.10.10", features = ["serde"] } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = { version = "1.0.135", features = ["preserve_order"] } -sha2 = "0.10.8" -thiserror = "2.0.9" -time = { version = "0.3.37", features = ["serde-well-known", "formatting", "parsing", "macros"] } -uuid = { version = "1.11.0", features = ["serde", "v4"] } +roaring = { version = "0.10.12", features = ["serde"] } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.140", features = ["preserve_order"] } +sha2 = "0.10.9" +thiserror = "2.0.12" +time = { version = "0.3.41", features = ["serde-well-known", "formatting", "parsing", "macros"] } +uuid = { version = "1.17.0", features = ["serde", "v4"] } diff --git a/crates/meilisearch-types/Cargo.toml b/crates/meilisearch-types/Cargo.toml index 55b54ecc7..fe5eb5d8f 100644 --- a/crates/meilisearch-types/Cargo.toml +++ b/crates/meilisearch-types/Cargo.toml @@ -11,37 +11,37 @@ edition.workspace = true license.workspace = true [dependencies] -actix-web = { version = "4.9.0", default-features = false } -anyhow = "1.0.95" -bumpalo = "3.16.0" +actix-web = { version = "4.11.0", default-features = false } +anyhow = "1.0.98" +bumpalo = "3.18.1" bumparaw-collections = "0.1.4" convert_case = "0.6.0" csv = "1.3.1" deserr = { version = "0.6.3", features = ["actix-web"] } -either = { version = "1.13.0", features = ["serde"] } +either = { version = "1.15.0", features = ["serde"] } enum-iterator = "2.1.0" file-store = { path = "../file-store" } -flate2 = "1.0.35" +flate2 = "1.1.2" fst = "0.4.7" memmap2 = "0.9.5" milli = { path = "../milli" } -roaring = { version = "0.10.10", features = ["serde"] } -rustc-hash = "2.1.0" -serde = { version = "1.0.217", features = ["derive"] } +roaring = { version = "0.10.12", features = ["serde"] } +rustc-hash = "2.1.1" +serde = { version = "1.0.219", features = ["derive"] } serde-cs = "0.2.4" -serde_json = { version = "1.0.135", features = ["preserve_order"] } -tar = "0.4.43" -tempfile = "3.15.0" -thiserror = "2.0.9" -time = { version = "0.3.37", features = [ +serde_json = { version = "1.0.140", features = ["preserve_order"] } +tar = "0.4.44" +tempfile = "3.20.0" +thiserror = "2.0.12" +time = { version = "0.3.41", features = [ "serde-well-known", "formatting", "parsing", "macros", ] } -tokio = "1.43" -utoipa = { version = "5.3.1", features = ["macros"] } -uuid = { version = "1.11.0", features = ["serde", "v4"] } +tokio = "1.45" +utoipa = { version = "5.4.0", features = ["macros"] } +uuid = { version = "1.17.0", features = ["serde", "v4"] } [dev-dependencies] # fixed version due to format breakages in v1.40 diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index 931d91d51..1bede5695 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -13,51 +13,51 @@ license.workspace = true default-run = "meilisearch" [dependencies] -actix-cors = "0.7.0" -actix-http = { version = "3.9.0", default-features = false, features = [ +actix-cors = "0.7.1" +actix-http = { version = "3.11.0", default-features = false, features = [ "compress-brotli", "compress-gzip", "rustls-0_23", ] } actix-utils = "3.0.1" -actix-web = { version = "4.9.0", default-features = false, features = [ +actix-web = { version = "4.11.0", default-features = false, features = [ "macros", "compress-brotli", "compress-gzip", "cookies", "rustls-0_23", ] } -anyhow = { version = "1.0.95", features = ["backtrace"] } -async-trait = "0.1.85" -bstr = "1.11.3" +anyhow = { version = "1.0.98", features = ["backtrace"] } +async-trait = "0.1.88" +bstr = "1.12.0" byte-unit = { version = "5.1.6", features = ["serde"] } -bytes = "1.9.0" -bumpalo = "3.16.0" -clap = { version = "4.5.24", features = ["derive", "env"] } +bytes = "1.10.1" +bumpalo = "3.18.1" +clap = { version = "4.5.40", features = ["derive", "env"] } crossbeam-channel = "0.5.15" deserr = { version = "0.6.3", features = ["actix-web"] } dump = { path = "../dump" } -either = "1.13.0" +either = "1.15.0" file-store = { path = "../file-store" } -flate2 = "1.0.35" +flate2 = "1.1.2" fst = "0.4.7" futures = "0.3.31" futures-util = "0.3.31" index-scheduler = { path = "../index-scheduler" } -indexmap = { version = "2.7.0", features = ["serde"] } -is-terminal = "0.4.13" +indexmap = { version = "2.9.0", features = ["serde"] } +is-terminal = "0.4.16" itertools = "0.14.0" -jsonwebtoken = "9.3.0" +jsonwebtoken = "9.3.1" lazy_static = "1.5.0" meilisearch-auth = { path = "../meilisearch-auth" } meilisearch-types = { path = "../meilisearch-types" } -mimalloc = { version = "0.1.43", default-features = false } +mimalloc = { version = "0.1.47", default-features = false } mime = "0.3.17" -num_cpus = "1.16.0" +num_cpus = "1.17.0" obkv = "0.3.0" -once_cell = "1.20.2" +once_cell = "1.21.3" ordered-float = "4.6.0" -parking_lot = "0.12.3" +parking_lot = "0.12.4" permissive-json-pointer = { path = "../permissive-json-pointer" } pin-project-lite = "0.2.16" platform-dirs = "0.3.0" @@ -65,44 +65,44 @@ prometheus = { version = "0.14.0", features = ["process"] } rand = "0.8.5" rayon = "1.10.0" regex = "1.11.1" -reqwest = { version = "0.12.12", features = [ +reqwest = { version = "0.12.20", features = [ "rustls-tls", "json", ], default-features = false } -rustls = { version = "0.23.20", features = ["ring"], default-features = false } -rustls-pki-types = { version = "1.10.1", features = ["alloc"] } +rustls = { version = "0.23.28", features = ["ring"], default-features = false } +rustls-pki-types = { version = "1.12.0", features = ["alloc"] } rustls-pemfile = "2.2.0" -segment = { version = "0.2.5" } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = { version = "1.0.135", features = ["preserve_order"] } -sha2 = "0.10.8" +segment = { version = "0.2.6" } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.140", features = ["preserve_order"] } +sha2 = "0.10.9" siphasher = "1.0.1" slice-group-by = "0.3.1" -static-files = { version = "0.2.4", optional = true } +static-files = { version = "0.2.5", optional = true } sysinfo = "0.33.1" -tar = "0.4.43" -tempfile = "3.15.0" -thiserror = "2.0.9" -time = { version = "0.3.37", features = [ +tar = "0.4.44" +tempfile = "3.20.0" +thiserror = "2.0.12" +time = { version = "0.3.41", features = [ "serde-well-known", "formatting", "parsing", "macros", ] } -tokio = { version = "1.43.1", features = ["full"] } -toml = "0.8.19" -uuid = { version = "1.11.0", features = ["serde", "v4"] } +tokio = { version = "1.45.1", features = ["full"] } +toml = "0.8.23" +uuid = { version = "1.17.0", features = ["serde", "v4"] } serde_urlencoded = "0.7.1" termcolor = "1.4.1" url = { version = "2.5.4", features = ["serde"] } tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["json"] } tracing-trace = { version = "0.1.0", path = "../tracing-trace" } -tracing-actix-web = "0.7.15" +tracing-actix-web = "0.7.18" build-info = { version = "1.7.0", path = "../build-info" } -roaring = "0.10.10" +roaring = "0.10.12" mopa-maintained = "0.2.3" -utoipa = { version = "5.3.1", features = [ +utoipa = { version = "5.4.0", features = [ "actix_extras", "macros", "non_strict_integers", @@ -126,21 +126,21 @@ maplit = "1.0.2" meili-snap = { path = "../meili-snap" } temp-env = "0.3.6" urlencoding = "2.1.3" -wiremock = "0.6.2" +wiremock = "0.6.3" yaup = "0.3.1" [build-dependencies] -anyhow = { version = "1.0.95", optional = true } +anyhow = { version = "1.0.98", optional = true } cargo_toml = { version = "0.21.0", optional = true } hex = { version = "0.4.3", optional = true } -reqwest = { version = "0.12.12", features = [ +reqwest = { version = "0.12.20", features = [ "blocking", "rustls-tls", ], default-features = false, optional = true } sha-1 = { version = "0.10.1", optional = true } -static-files = { version = "0.2.4", optional = true } -tempfile = { version = "3.15.0", optional = true } -zip = { version = "2.3.0", optional = true } +static-files = { version = "0.2.5", optional = true } +tempfile = { version = "3.20.0", optional = true } +zip = { version = "2.4.2", optional = true } [features] default = ["meilisearch-types/all-tokenizations", "mini-dashboard"] diff --git a/crates/meilitool/Cargo.toml b/crates/meilitool/Cargo.toml index 485177838..722f5f82b 100644 --- a/crates/meilitool/Cargo.toml +++ b/crates/meilitool/Cargo.toml @@ -9,15 +9,15 @@ edition.workspace = true license.workspace = true [dependencies] -anyhow = "1.0.95" -clap = { version = "4.5.24", features = ["derive"] } +anyhow = "1.0.98" +clap = { version = "4.5.40", features = ["derive"] } dump = { path = "../dump" } file-store = { path = "../file-store" } -indexmap = { version = "2.7.0", features = ["serde"] } +indexmap = { version = "2.9.0", features = ["serde"] } meilisearch-auth = { path = "../meilisearch-auth" } meilisearch-types = { path = "../meilisearch-types" } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = { version = "1.0.135", features = ["preserve_order"] } -tempfile = "3.15.0" -time = { version = "0.3.37", features = ["formatting", "parsing", "alloc"] } -uuid = { version = "1.11.0", features = ["v4"], default-features = false } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.140", features = ["preserve_order"] } +tempfile = "3.20.0" +time = { version = "0.3.41", features = ["formatting", "parsing", "alloc"] } +uuid = { version = "1.17.0", features = ["v4"], default-features = false } diff --git a/crates/milli/Cargo.toml b/crates/milli/Cargo.toml index 08e0c4728..0a117b5e6 100644 --- a/crates/milli/Cargo.toml +++ b/crates/milli/Cargo.toml @@ -15,15 +15,15 @@ license.workspace = true big_s = "1.0.2" bimap = { version = "0.6.3", features = ["serde"] } bincode = "1.3.3" -bstr = "1.11.3" -bytemuck = { version = "1.21.0", features = ["extern_crate_alloc"] } +bstr = "1.12.0" +bytemuck = { version = "1.23.1", features = ["extern_crate_alloc"] } byteorder = "1.5.0" charabia = { version = "0.9.6", default-features = false } concat-arrays = "0.1.2" convert_case = "0.6.0" crossbeam-channel = "0.5.15" deserr = "0.6.3" -either = { version = "1.13.0", features = ["serde"] } +either = { version = "1.15.0", features = ["serde"] } flatten-serde-json = { path = "../flatten-serde-json" } fst = "0.4.7" fxhash = "0.2.1" @@ -36,32 +36,32 @@ heed = { version = "0.22.0", default-features = false, features = [ "serde-json", "serde-bincode", ] } -indexmap = { version = "2.7.0", features = ["serde"] } +indexmap = { version = "2.9.0", features = ["serde"] } json-depth-checker = { path = "../json-depth-checker" } levenshtein_automata = { version = "0.2.1", features = ["fst_automaton"] } -memchr = "2.7.4" +memchr = "2.7.5" memmap2 = "0.9.5" obkv = "0.3.0" -once_cell = "1.20.2" +once_cell = "1.21.3" ordered-float = "4.6.0" rayon = "1.10.0" -roaring = { version = "0.10.10", features = ["serde"] } +roaring = { version = "0.10.12", features = ["serde"] } rstar = { version = "0.12.2", features = ["serde"] } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = { version = "1.0.135", features = ["preserve_order", "raw_value"] } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0.140", features = ["preserve_order", "raw_value"] } slice-group-by = "0.3.1" smallstr = { version = "0.3.0", features = ["serde"] } -smallvec = "1.13.2" +smallvec = "1.15.1" smartstring = "1.0.1" -tempfile = "3.15.0" -thiserror = "2.0.9" -time = { version = "0.3.37", features = [ +tempfile = "3.20.0" +thiserror = "2.0.12" +time = { version = "0.3.41", features = [ "serde-well-known", "formatting", "parsing", "macros", ] } -uuid = { version = "1.11.0", features = ["v4"] } +uuid = { version = "1.17.0", features = ["v4"] } filter-parser = { path = "../filter-parser" } @@ -69,9 +69,9 @@ filter-parser = { path = "../filter-parser" } itertools = "0.14.0" csv = "1.3.1" -candle-core = { version = "0.8.2" } -candle-transformers = { version = "0.8.2" } -candle-nn = { version = "0.8.2" } +candle-core = { version = "0.8.4" } +candle-transformers = { version = "0.8.4" } +candle-nn = { version = "0.8.4" } tokenizers = { git = "https://github.com/huggingface/tokenizers.git", tag = "v0.15.2", version = "0.15.2", default-features = false, features = [ "onig", ] } @@ -79,8 +79,8 @@ hf-hub = { git = "https://github.com/dureuill/hf-hub.git", branch = "rust_tls", "online", ] } tiktoken-rs = "0.6.0" -liquid = "0.26.9" -rhai = { git = "https://github.com/rhaiscript/rhai", rev = "ef3df63121d27aacd838f366f2b83fd65f20a1e4", features = [ +liquid = "0.26.11" +rhai = { version = "1.22.2", features = [ "serde", "no_module", "no_custom_syntax", @@ -93,17 +93,17 @@ tracing = "0.1.41" ureq = { version = "2.12.1", features = ["json"] } url = "2.5.4" rayon-par-bridge = "0.1.0" -hashbrown = "0.15.2" -bumpalo = "3.16.0" +hashbrown = "0.15.4" +bumpalo = "3.18.1" bumparaw-collections = "0.1.4" -thread_local = "1.1.8" +thread_local = "1.1.9" allocator-api2 = "0.2.21" -rustc-hash = "2.1.0" +rustc-hash = "2.1.1" uell = "0.1.0" enum-iterator = "2.1.0" bbqueue = { git = "https://github.com/meilisearch/bbqueue" } flume = { version = "0.11.1", default-features = false } -utoipa = { version = "5.3.1", features = [ +utoipa = { version = "5.4.0", features = [ "non_strict_integers", "preserve_order", "uuid", @@ -113,7 +113,7 @@ utoipa = { version = "5.3.1", features = [ lru = "0.13.0" [dev-dependencies] -mimalloc = { version = "0.1.43", default-features = false } +mimalloc = { version = "0.1.47", default-features = false } # fixed version due to format breakages in v1.40 insta = "=1.39.0" maplit = "1.0.2" diff --git a/crates/tracing-trace/Cargo.toml b/crates/tracing-trace/Cargo.toml index 2cd4f7a74..2d4729fb4 100644 --- a/crates/tracing-trace/Cargo.toml +++ b/crates/tracing-trace/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] color-spantrace = "0.2.1" fxprof-processed-profile = "0.7.0" -serde = { version = "1.0.217", features = ["derive"] } -serde_json = "1.0.135" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.140" tracing = "0.1.41" tracing-error = "0.2.1" tracing-subscriber = "0.3.19" @@ -18,7 +18,7 @@ byte-unit = { version = "5.1.6", default-features = false, features = [ "byte", "serde", ] } -tokio = { version = "1.43.1", features = ["sync"] } +tokio = { version = "1.45.1", features = ["sync"] } [target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] libproc = "0.14.10" diff --git a/crates/xtask/Cargo.toml b/crates/xtask/Cargo.toml index a9ef79cd6..9ea77f7f9 100644 --- a/crates/xtask/Cargo.toml +++ b/crates/xtask/Cargo.toml @@ -11,27 +11,27 @@ license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.95" +anyhow = "1.0.98" build-info = { version = "1.7.0", path = "../build-info" } -cargo_metadata = "0.19.1" -clap = { version = "4.5.24", features = ["derive"] } +cargo_metadata = "0.19.2" +clap = { version = "4.5.40", features = ["derive"] } futures-core = "0.3.31" futures-util = "0.3.31" -reqwest = { version = "0.12.12", features = [ +reqwest = { version = "0.12.20", features = [ "stream", "json", "rustls-tls", ], default-features = false } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = "1.0.135" -sha2 = "0.10.8" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.140" +sha2 = "0.10.9" sysinfo = "0.33.1" -time = { version = "0.3.37", features = [ +time = { version = "0.3.41", features = [ "serde", "serde-human-readable", "macros", ] } -tokio = { version = "1.43.1", features = [ +tokio = { version = "1.45.1", features = [ "rt", "net", "time", @@ -41,4 +41,4 @@ tokio = { version = "1.43.1", features = [ tracing = "0.1.41" tracing-subscriber = "0.3.19" tracing-trace = { version = "0.1.0", path = "../tracing-trace" } -uuid = { version = "1.11.0", features = ["v7", "serde"] } +uuid = { version = "1.17.0", features = ["v7", "serde"] } From 4069dbcfca5440ddecf96a440ff4cf4db02bcb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Renault?= Date: Tue, 17 Jun 2025 22:23:37 +0200 Subject: [PATCH 291/292] Upgrade incompatible dependencies --- Cargo.lock | 422 +++++++++++++++++---------- crates/benchmarks/Cargo.toml | 4 +- crates/benchmarks/build.rs | 2 +- crates/flatten-serde-json/Cargo.toml | 2 +- crates/index-scheduler/Cargo.toml | 2 +- crates/json-depth-checker/Cargo.toml | 2 +- crates/meilisearch-types/Cargo.toml | 2 +- crates/meilisearch/Cargo.toml | 10 +- crates/milli/Cargo.toml | 16 +- crates/tracing-trace/Cargo.toml | 2 +- crates/xtask/Cargo.toml | 4 +- 11 files changed, 294 insertions(+), 174 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45311fb88..7bf27bce4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,7 +47,7 @@ dependencies = [ "actix-utils", "base64 0.22.1", "bitflags 2.9.1", - "brotli 8.0.1", + "brotli", "bytes", "bytestring", "derive_more", @@ -344,6 +344,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "allocator-api2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78200ac3468a57d333cd0ea5dd398e25111194dcacd49208afca95c629a6311d" + [[package]] name = "anes" version = "0.1.6" @@ -448,7 +454,7 @@ dependencies = [ "heed", "memmap2", "nohash", - "ordered-float", + "ordered-float 4.6.0", "page_size", "rand 0.8.5", "rayon", @@ -561,12 +567,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -585,7 +585,7 @@ dependencies = [ "anyhow", "bumpalo", "bytes", - "convert_case", + "convert_case 0.8.0", "criterion", "csv", "flate2", @@ -736,17 +736,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "brotli" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 4.0.3", -] - [[package]] name = "brotli" version = "8.0.1" @@ -755,17 +744,7 @@ checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor 5.0.0", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", + "brotli-decompressor", ] [[package]] @@ -804,7 +783,7 @@ version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" dependencies = [ - "allocator-api2", + "allocator-api2 0.2.21", "serde", ] @@ -814,7 +793,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ce682bdc86c2e25ef5cd95881d9d6a1902214eddf74cf9ffea88fe1464377e8" dependencies = [ - "allocator-api2", + "allocator-api2 0.2.21", "bitpacking", "bumpalo", "hashbrown 0.15.4", @@ -932,9 +911,9 @@ dependencies = [ [[package]] name = "candle-core" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ccf5ee3532e66868516d9b315f73aec9f34ea1a37ae98514534d458915dbf1" +checksum = "a9f51e2ecf6efe9737af8f993433c839f956d2b6ed4fd2dd4a7c6d8b0fa667ff" dependencies = [ "byteorder", "candle-kernels", @@ -957,18 +936,18 @@ dependencies = [ [[package]] name = "candle-kernels" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a10885bd902fad1b8518ba2b22369aaed88a3d94e123533ad3ca73db33b1c8ca" +checksum = "9fcd989c2143aa754370b5bfee309e35fbd259e83d9ecf7a73d23d8508430775" dependencies = [ "bindgen_cuda", ] [[package]] name = "candle-nn" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1160c3b63f47d40d91110a3e1e1e566ae38edddbbf492a60b40ffc3bc1ff38" +checksum = "c1980d53280c8f9e2c6cbe1785855d7ff8010208b46e21252b978badf13ad69d" dependencies = [ "candle-core", "half", @@ -981,9 +960,9 @@ dependencies = [ [[package]] name = "candle-transformers" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a0900d49f8605e0e7e6693a1f560e6271279de98e5fa369e7abf3aac245020" +checksum = "186cb80045dbe47e0b387ea6d3e906f02fb3056297080d9922984c90e90a72b0" dependencies = [ "byteorder", "candle-core", @@ -1000,21 +979,38 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.9" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4" dependencies = [ "serde", ] [[package]] -name = "cargo_metadata" -version = "0.19.2" +name = "cargo-util-schemas" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +checksum = "e63d2780ac94487eb9f1fea7b0d56300abc9eb488800854ca217f102f5caccca" +dependencies = [ + "semver", + "serde", + "serde-untagged", + "serde-value", + "thiserror 1.0.69", + "toml", + "unicode-xid", + "url", +] + +[[package]] +name = "cargo_metadata" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502" dependencies = [ "camino", "cargo-platform", + "cargo-util-schemas", "semver", "serde", "serde_json", @@ -1023,9 +1019,9 @@ dependencies = [ [[package]] name = "cargo_toml" -version = "0.21.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" +checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257" dependencies = [ "serde", "toml", @@ -1200,9 +1196,9 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "color-spantrace" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" dependencies = [ "once_cell", "owo-colors", @@ -1275,6 +1271,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.16.2" @@ -1320,21 +1325,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - [[package]] name = "crc32fast" version = "1.4.2" @@ -1346,25 +1336,22 @@ dependencies = [ [[package]] name = "criterion" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "3bf7af66b0989381bd0be551bd7cc91912a655a58c6918420c9527b1fd8b4679" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", - "is-terminal", - "itertools 0.10.5", + "itertools 0.13.0", "num-traits", - "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -1462,9 +1449,9 @@ dependencies = [ [[package]] name = "cudarc" -version = "0.13.9" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486c221362668c63a1636cfa51463b09574433b39029326cff40864b3ba12b6e" +checksum = "f9574894139a982bf26fbb44473a9d416c015e779c51ef0fbc0789f1a1c17b25" dependencies = [ "half", "libloading", @@ -1706,7 +1693,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aadef696fce456c704f10186def1bdc0a40e646c9f4f18cf091477acadb731d8" dependencies = [ - "convert_case", + "convert_case 0.6.0", "proc-macro2", "quote", "syn 2.0.101", @@ -1963,6 +1950,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "erased-serde" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "errno" version = "0.3.12" @@ -2046,6 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide", ] @@ -2627,7 +2625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.12", - "allocator-api2", + "allocator-api2 0.2.21", ] [[package]] @@ -2636,7 +2634,7 @@ version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "allocator-api2", + "allocator-api2 0.2.21", "equivalent", "foldhash", "serde", @@ -3004,7 +3002,7 @@ dependencies = [ "bumpalo", "bumparaw-collections", "byte-unit", - "convert_case", + "convert_case 0.8.0", "crossbeam-channel", "csv", "derive_builder 0.20.2", @@ -3344,6 +3342,26 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "liblzma" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66352d7a8ac12d4877b6e6ea5a9b7650ee094257dc40889955bea5bc5b08c1d0" +dependencies = [ + "liblzma-sys", +] + +[[package]] +name = "liblzma-sys" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b9596486f6d60c3bbe644c0e1be1aa6ccc472ad630fe8927b456973d7cb736" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.15" @@ -3382,6 +3400,15 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "libz-rs-sys" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221" +dependencies = [ + "zlib-rs", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -3641,9 +3668,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198" dependencies = [ "hashbrown 0.15.4", ] @@ -3654,27 +3681,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - -[[package]] -name = "lzma-sys" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "macro_rules_attribute" version = "0.2.2" @@ -3739,7 +3745,7 @@ dependencies = [ "anyhow", "async-openai", "async-trait", - "brotli 6.0.0", + "brotli", "bstr", "build-info", "bumpalo", @@ -3775,7 +3781,7 @@ dependencies = [ "num_cpus", "obkv", "once_cell", - "ordered-float", + "ordered-float 5.0.0", "parking_lot", "permissive-json-pointer", "pin-project-lite", @@ -3819,7 +3825,7 @@ dependencies = [ "uuid", "wiremock", "yaup", - "zip 2.4.2", + "zip 4.1.0", ] [[package]] @@ -3849,7 +3855,7 @@ dependencies = [ "anyhow", "bumpalo", "bumparaw-collections", - "convert_case", + "convert_case 0.8.0", "csv", "deserr", "either", @@ -3913,7 +3919,7 @@ dependencies = [ name = "milli" version = "1.15.2" dependencies = [ - "allocator-api2", + "allocator-api2 0.3.0", "arroy", "bbqueue", "big_s", @@ -3929,7 +3935,7 @@ dependencies = [ "candle-transformers", "charabia", "concat-arrays", - "convert_case", + "convert_case 0.8.0", "crossbeam-channel", "csv", "deserr", @@ -3960,7 +3966,7 @@ dependencies = [ "mimalloc", "obkv", "once_cell", - "ordered-float", + "ordered-float 5.0.0", "rand 0.8.5", "rayon", "rayon-par-bridge", @@ -4255,6 +4261,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.36.7" @@ -4325,6 +4350,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-float" version = "4.6.0" @@ -4334,6 +4368,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -4342,9 +4385,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owo-colors" -version = "3.5.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" [[package]] name = "page_size" @@ -5449,6 +5492,27 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-untagged" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" +dependencies = [ + "erased-serde", + "serde", + "typeid", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float 2.10.1", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.219" @@ -5870,15 +5934,15 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.33.1" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" +checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e" dependencies = [ - "core-foundation-sys", "libc", "memchr", "ntapi", - "rayon", + "objc2-core-foundation", + "objc2-io-kit", "windows", ] @@ -5990,16 +6054,15 @@ dependencies = [ [[package]] name = "tiktoken-rs" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44075987ee2486402f0808505dd65692163d243a337fc54363d49afac41087f6" +checksum = "25563eeba904d770acf527e8b370fe9a5547bacd20ff84a0b6c3bc41288e5625" dependencies = [ "anyhow", - "base64 0.21.7", + "base64 0.22.1", "bstr", "fancy-regex", "lazy_static", - "parking_lot", "regex", "rustc-hash 1.1.0", ] @@ -6376,6 +6439,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" version = "1.18.0" @@ -6399,9 +6468,9 @@ dependencies = [ [[package]] name = "ug" -version = "0.1.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03719c61a91b51541f076dfdba45caacf750b230cefaa4b32d6f5411c3f7f437" +checksum = "90b70b37e9074642bc5f60bb23247fd072a84314ca9e71cdf8527593406a0dd3" dependencies = [ "gemm 0.18.2", "half", @@ -6420,9 +6489,9 @@ dependencies = [ [[package]] name = "ug-cuda" -version = "0.1.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50758486d7941f8b0a636ba7e29455c07071f41590beac1fd307ec893e8db69a" +checksum = "14053653d0b7fa7b21015aa9a62edc8af2f60aa6f9c54e66386ecce55f22ed29" dependencies = [ "cudarc", "half", @@ -6882,31 +6951,55 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.57.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ "windows-core", - "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.57.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", + "windows-link", "windows-result", - "windows-targets 0.52.6", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.57.0" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", @@ -6915,9 +7008,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.57.0" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", @@ -6925,12 +7018,37 @@ dependencies = [ ] [[package]] -name = "windows-result" -version = "0.1.2" +name = "windows-link" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-targets 0.52.6", + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", ] [[package]] @@ -6991,6 +7109,15 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -7171,15 +7298,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - [[package]] name = "yada" version = "0.5.1" @@ -7356,34 +7474,36 @@ dependencies = [ [[package]] name = "zip" -version = "2.4.2" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +checksum = "af7dcdb4229c0e79c2531a24de7726a0e980417a74fb4d030a35f535665439a0" dependencies = [ "aes", "arbitrary", "bzip2", "constant_time_eq", "crc32fast", - "crossbeam-utils", "deflate64", - "displaydoc", "flate2", "getrandom 0.3.3", "hmac", "indexmap", - "lzma-rs", + "liblzma", "memchr", "pbkdf2", "sha1", - "thiserror 2.0.12", "time", - "xz2", "zeroize", "zopfli", "zstd", ] +[[package]] +name = "zlib-rs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" + [[package]] name = "zopfli" version = "0.8.2" diff --git a/crates/benchmarks/Cargo.toml b/crates/benchmarks/Cargo.toml index f9ad77bf6..9dccc444b 100644 --- a/crates/benchmarks/Cargo.toml +++ b/crates/benchmarks/Cargo.toml @@ -21,7 +21,7 @@ serde_json = { version = "1.0.140", features = ["preserve_order"] } tempfile = "3.20.0" [dev-dependencies] -criterion = { version = "0.5.1", features = ["html_reports"] } +criterion = { version = "0.6.0", features = ["html_reports"] } rand = "0.8.5" rand_chacha = "0.3.1" roaring = "0.10.12" @@ -29,7 +29,7 @@ roaring = "0.10.12" [build-dependencies] anyhow = "1.0.98" bytes = "1.10.1" -convert_case = "0.6.0" +convert_case = "0.8.0" flate2 = "1.1.2" reqwest = { version = "0.12.20", features = ["blocking", "rustls-tls"], default-features = false } diff --git a/crates/benchmarks/build.rs b/crates/benchmarks/build.rs index d7b99db37..88d8e7c5f 100644 --- a/crates/benchmarks/build.rs +++ b/crates/benchmarks/build.rs @@ -67,7 +67,7 @@ fn main() -> anyhow::Result<()> { writeln!( &mut manifest_paths_file, r#"pub const {}: &str = {:?};"#, - dataset.to_case(Case::ScreamingSnake), + dataset.to_case(Case::UpperSnake), out_file.display(), )?; diff --git a/crates/flatten-serde-json/Cargo.toml b/crates/flatten-serde-json/Cargo.toml index 7b498ec4f..27a2c089f 100644 --- a/crates/flatten-serde-json/Cargo.toml +++ b/crates/flatten-serde-json/Cargo.toml @@ -16,7 +16,7 @@ license.workspace = true serde_json = "1.0" [dev-dependencies] -criterion = { version = "0.5.1", features = ["html_reports"] } +criterion = { version = "0.6.0", features = ["html_reports"] } [[bench]] name = "benchmarks" diff --git a/crates/index-scheduler/Cargo.toml b/crates/index-scheduler/Cargo.toml index 6ca1a0aa6..f4901b2f2 100644 --- a/crates/index-scheduler/Cargo.toml +++ b/crates/index-scheduler/Cargo.toml @@ -16,7 +16,7 @@ bincode = "1.3.3" byte-unit = "5.1.6" bumpalo = "3.18.1" bumparaw-collections = "0.1.4" -convert_case = "0.6.0" +convert_case = "0.8.0" csv = "1.3.1" derive_builder = "0.20.2" dump = { path = "../dump" } diff --git a/crates/json-depth-checker/Cargo.toml b/crates/json-depth-checker/Cargo.toml index b8162357b..68964354a 100644 --- a/crates/json-depth-checker/Cargo.toml +++ b/crates/json-depth-checker/Cargo.toml @@ -15,7 +15,7 @@ license.workspace = true serde_json = "1.0" [dev-dependencies] -criterion = "0.5.1" +criterion = "0.6.0" [[bench]] name = "depth" diff --git a/crates/meilisearch-types/Cargo.toml b/crates/meilisearch-types/Cargo.toml index fe5eb5d8f..f76044078 100644 --- a/crates/meilisearch-types/Cargo.toml +++ b/crates/meilisearch-types/Cargo.toml @@ -15,7 +15,7 @@ actix-web = { version = "4.11.0", default-features = false } anyhow = "1.0.98" bumpalo = "3.18.1" bumparaw-collections = "0.1.4" -convert_case = "0.6.0" +convert_case = "0.8.0" csv = "1.3.1" deserr = { version = "0.6.3", features = ["actix-web"] } either = { version = "1.15.0", features = ["serde"] } diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index 1bede5695..28ecb0147 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -56,7 +56,7 @@ mime = "0.3.17" num_cpus = "1.17.0" obkv = "0.3.0" once_cell = "1.21.3" -ordered-float = "4.6.0" +ordered-float = "5.0.0" parking_lot = "0.12.4" permissive-json-pointer = { path = "../permissive-json-pointer" } pin-project-lite = "0.2.16" @@ -79,7 +79,7 @@ sha2 = "0.10.9" siphasher = "1.0.1" slice-group-by = "0.3.1" static-files = { version = "0.2.5", optional = true } -sysinfo = "0.33.1" +sysinfo = "0.35.2" tar = "0.4.44" tempfile = "3.20.0" thiserror = "2.0.12" @@ -118,7 +118,7 @@ actix-web-lab = { version = "0.24.1", default-features = false } [dev-dependencies] actix-rt = "2.10.0" -brotli = "6.0.0" +brotli = "8.0.1" # fixed version due to format breakages in v1.40 insta = { version = "=1.39.0", features = ["redactions"] } manifest-dir-macros = "0.1.18" @@ -131,7 +131,7 @@ yaup = "0.3.1" [build-dependencies] anyhow = { version = "1.0.98", optional = true } -cargo_toml = { version = "0.21.0", optional = true } +cargo_toml = { version = "0.22.1", optional = true } hex = { version = "0.4.3", optional = true } reqwest = { version = "0.12.20", features = [ "blocking", @@ -140,7 +140,7 @@ reqwest = { version = "0.12.20", features = [ sha-1 = { version = "0.10.1", optional = true } static-files = { version = "0.2.5", optional = true } tempfile = { version = "3.20.0", optional = true } -zip = { version = "2.4.2", optional = true } +zip = { version = "4.1.0", optional = true } [features] default = ["meilisearch-types/all-tokenizations", "mini-dashboard"] diff --git a/crates/milli/Cargo.toml b/crates/milli/Cargo.toml index 0a117b5e6..b98725a8f 100644 --- a/crates/milli/Cargo.toml +++ b/crates/milli/Cargo.toml @@ -20,7 +20,7 @@ bytemuck = { version = "1.23.1", features = ["extern_crate_alloc"] } byteorder = "1.5.0" charabia = { version = "0.9.6", default-features = false } concat-arrays = "0.1.2" -convert_case = "0.6.0" +convert_case = "0.8.0" crossbeam-channel = "0.5.15" deserr = "0.6.3" either = { version = "1.15.0", features = ["serde"] } @@ -43,7 +43,7 @@ memchr = "2.7.5" memmap2 = "0.9.5" obkv = "0.3.0" once_cell = "1.21.3" -ordered-float = "4.6.0" +ordered-float = "5.0.0" rayon = "1.10.0" roaring = { version = "0.10.12", features = ["serde"] } rstar = { version = "0.12.2", features = ["serde"] } @@ -69,16 +69,16 @@ filter-parser = { path = "../filter-parser" } itertools = "0.14.0" csv = "1.3.1" -candle-core = { version = "0.8.4" } -candle-transformers = { version = "0.8.4" } -candle-nn = { version = "0.8.4" } +candle-core = { version = "0.9.1" } +candle-transformers = { version = "0.9.1" } +candle-nn = { version = "0.9.1" } tokenizers = { git = "https://github.com/huggingface/tokenizers.git", tag = "v0.15.2", version = "0.15.2", default-features = false, features = [ "onig", ] } hf-hub = { git = "https://github.com/dureuill/hf-hub.git", branch = "rust_tls", default-features = false, features = [ "online", ] } -tiktoken-rs = "0.6.0" +tiktoken-rs = "0.7.0" liquid = "0.26.11" rhai = { version = "1.22.2", features = [ "serde", @@ -97,7 +97,7 @@ hashbrown = "0.15.4" bumpalo = "3.18.1" bumparaw-collections = "0.1.4" thread_local = "1.1.9" -allocator-api2 = "0.2.21" +allocator-api2 = "0.3.0" rustc-hash = "2.1.1" uell = "0.1.0" enum-iterator = "2.1.0" @@ -110,7 +110,7 @@ utoipa = { version = "5.4.0", features = [ "time", "openapi_extensions", ] } -lru = "0.13.0" +lru = "0.14.0" [dev-dependencies] mimalloc = { version = "0.1.47", default-features = false } diff --git a/crates/tracing-trace/Cargo.toml b/crates/tracing-trace/Cargo.toml index 2d4729fb4..866a982a0 100644 --- a/crates/tracing-trace/Cargo.toml +++ b/crates/tracing-trace/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -color-spantrace = "0.2.1" +color-spantrace = "0.3.0" fxprof-processed-profile = "0.7.0" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" diff --git a/crates/xtask/Cargo.toml b/crates/xtask/Cargo.toml index 9ea77f7f9..5fdf157df 100644 --- a/crates/xtask/Cargo.toml +++ b/crates/xtask/Cargo.toml @@ -13,7 +13,7 @@ license.workspace = true [dependencies] anyhow = "1.0.98" build-info = { version = "1.7.0", path = "../build-info" } -cargo_metadata = "0.19.2" +cargo_metadata = "0.20.0" clap = { version = "4.5.40", features = ["derive"] } futures-core = "0.3.31" futures-util = "0.3.31" @@ -25,7 +25,7 @@ reqwest = { version = "0.12.20", features = [ serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" sha2 = "0.10.9" -sysinfo = "0.33.1" +sysinfo = "0.35.2" time = { version = "0.3.41", features = [ "serde", "serde-human-readable", From 138d20b277c5490669f317ab90f6b8897fcc59d0 Mon Sep 17 00:00:00 2001 From: Mubelotix Date: Wed, 18 Jun 2025 16:46:20 +0200 Subject: [PATCH 292/292] Remove old dependencies --- Cargo.lock | 21 --------------------- crates/meilisearch/Cargo.toml | 1 - crates/milli/Cargo.toml | 2 -- 3 files changed, 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7bf27bce4..7455ff1b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3744,7 +3744,6 @@ dependencies = [ "actix-web-lab", "anyhow", "async-openai", - "async-trait", "brotli", "bstr", "build-info", @@ -3969,7 +3968,6 @@ dependencies = [ "ordered-float 5.0.0", "rand 0.8.5", "rayon", - "rayon-par-bridge", "rhai", "roaring", "rstar", @@ -3987,7 +3985,6 @@ dependencies = [ "time", "tokenizers", "tracing", - "uell", "ureq", "url", "utoipa", @@ -5002,15 +4999,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "rayon-par-bridge" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6a14d8f65834aca6b0fe4cbbd7a27e639cd3efb1f2a32de9942368f1991de8" -dependencies = [ - "rayon", -] - [[package]] name = "reborrow" version = "0.5.5" @@ -6457,15 +6445,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "uell" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40de5982e28612e20330e77d81f1559b74f66caf3c7fc10b19ada4843f4b4fd7" -dependencies = [ - "bumpalo", -] - [[package]] name = "ug" version = "0.4.0" diff --git a/crates/meilisearch/Cargo.toml b/crates/meilisearch/Cargo.toml index 28ecb0147..fe00d9fee 100644 --- a/crates/meilisearch/Cargo.toml +++ b/crates/meilisearch/Cargo.toml @@ -28,7 +28,6 @@ actix-web = { version = "4.11.0", default-features = false, features = [ "rustls-0_23", ] } anyhow = { version = "1.0.98", features = ["backtrace"] } -async-trait = "0.1.88" bstr = "1.12.0" byte-unit = { version = "5.1.6", features = ["serde"] } bytes = "1.10.1" diff --git a/crates/milli/Cargo.toml b/crates/milli/Cargo.toml index b98725a8f..3d08252ac 100644 --- a/crates/milli/Cargo.toml +++ b/crates/milli/Cargo.toml @@ -92,14 +92,12 @@ rand = "0.8.5" tracing = "0.1.41" ureq = { version = "2.12.1", features = ["json"] } url = "2.5.4" -rayon-par-bridge = "0.1.0" hashbrown = "0.15.4" bumpalo = "3.18.1" bumparaw-collections = "0.1.4" thread_local = "1.1.9" allocator-api2 = "0.3.0" rustc-hash = "2.1.1" -uell = "0.1.0" enum-iterator = "2.1.0" bbqueue = { git = "https://github.com/meilisearch/bbqueue" } flume = { version = "0.11.1", default-features = false }