Merge branch 'main' into render-route

This commit is contained in:
Mubelotix
2025-08-18 12:31:04 +02:00
198 changed files with 4327 additions and 739 deletions

View File

@ -212,7 +212,6 @@ ImmutableApiKeyKey , InvalidRequest , BAD_REQU
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;
@ -335,6 +334,7 @@ InvalidState , Internal , INTERNAL
InvalidStoreFile , Internal , INTERNAL_SERVER_ERROR ;
InvalidSwapDuplicateIndexFound , InvalidRequest , BAD_REQUEST ;
InvalidSwapIndexes , InvalidRequest , BAD_REQUEST ;
InvalidSwapRename , InvalidRequest , BAD_REQUEST ;
InvalidTaskAfterEnqueuedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskAfterFinishedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskAfterStartedAt , InvalidRequest , BAD_REQUEST ;
@ -428,7 +428,16 @@ InvalidRenderInputDocumentId , InvalidRequest , BAD_REQU
InvalidRenderInputInline , InvalidRequest , BAD_REQUEST ;
RenderDocumentNotFound , InvalidRequest , NOT_FOUND ;
TemplateParsingError , InvalidRequest , BAD_REQUEST ;
TemplateRenderingError , InvalidRequest , BAD_REQUEST
TemplateRenderingError , InvalidRequest , BAD_REQUEST ;
// Webhooks
InvalidWebhooks , InvalidRequest , BAD_REQUEST ;
InvalidWebhookUrl , InvalidRequest , BAD_REQUEST ;
InvalidWebhookHeaders , InvalidRequest , BAD_REQUEST ;
ImmutableWebhook , InvalidRequest , BAD_REQUEST ;
InvalidWebhookUuid , InvalidRequest , BAD_REQUEST ;
WebhookNotFound , InvalidRequest , NOT_FOUND ;
ImmutableWebhookUuid , InvalidRequest , BAD_REQUEST ;
ImmutableWebhookIsEditable , InvalidRequest , BAD_REQUEST
}
impl ErrorCode for JoinError {

View File

@ -365,6 +365,21 @@ pub enum Action {
#[serde(rename = "*.get")]
#[deserr(rename = "*.get")]
AllGet,
#[serde(rename = "webhooks.get")]
#[deserr(rename = "webhooks.get")]
WebhooksGet,
#[serde(rename = "webhooks.update")]
#[deserr(rename = "webhooks.update")]
WebhooksUpdate,
#[serde(rename = "webhooks.delete")]
#[deserr(rename = "webhooks.delete")]
WebhooksDelete,
#[serde(rename = "webhooks.create")]
#[deserr(rename = "webhooks.create")]
WebhooksCreate,
#[serde(rename = "webhooks.*")]
#[deserr(rename = "webhooks.*")]
WebhooksAll,
}
impl Action {
@ -416,6 +431,11 @@ impl Action {
NETWORK_GET => Some(Self::NetworkGet),
NETWORK_UPDATE => Some(Self::NetworkUpdate),
ALL_GET => Some(Self::AllGet),
WEBHOOKS_GET => Some(Self::WebhooksGet),
WEBHOOKS_UPDATE => Some(Self::WebhooksUpdate),
WEBHOOKS_DELETE => Some(Self::WebhooksDelete),
WEBHOOKS_CREATE => Some(Self::WebhooksCreate),
WEBHOOKS_ALL => Some(Self::WebhooksAll),
_otherwise => None,
}
}
@ -428,7 +448,9 @@ impl Action {
match self {
// Any action that expands to others must return false, as it wouldn't be able to expand recursively.
All | AllGet | DocumentsAll | IndexesAll | ChatsAll | TasksAll | SettingsAll
| StatsAll | MetricsAll | DumpsAll | SnapshotsAll | ChatsSettingsAll => false,
| StatsAll | MetricsAll | DumpsAll | SnapshotsAll | ChatsSettingsAll | WebhooksAll => {
false
}
Search => true,
DocumentsAdd => false,
@ -463,6 +485,10 @@ impl Action {
ChatsDelete => false,
ChatsSettingsGet => true,
ChatsSettingsUpdate => false,
WebhooksGet => true,
WebhooksUpdate => false,
WebhooksDelete => false,
WebhooksCreate => false,
}
}
@ -522,6 +548,12 @@ pub mod actions {
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 WEBHOOKS_GET: u8 = WebhooksGet.repr();
pub const WEBHOOKS_UPDATE: u8 = WebhooksUpdate.repr();
pub const WEBHOOKS_DELETE: u8 = WebhooksDelete.repr();
pub const WEBHOOKS_CREATE: u8 = WebhooksCreate.repr();
pub const WEBHOOKS_ALL: u8 = WebhooksAll.repr();
}
#[cfg(test)]
@ -577,6 +609,11 @@ pub(crate) mod test {
assert!(ChatsSettingsGet.repr() == 42 && CHATS_SETTINGS_GET == 42);
assert!(ChatsSettingsUpdate.repr() == 43 && CHATS_SETTINGS_UPDATE == 43);
assert!(AllGet.repr() == 44 && ALL_GET == 44);
assert!(WebhooksGet.repr() == 45 && WEBHOOKS_GET == 45);
assert!(WebhooksUpdate.repr() == 46 && WEBHOOKS_UPDATE == 46);
assert!(WebhooksDelete.repr() == 47 && WEBHOOKS_DELETE == 47);
assert!(WebhooksCreate.repr() == 48 && WEBHOOKS_CREATE == 48);
assert!(WebhooksAll.repr() == 49 && WEBHOOKS_ALL == 49);
}
#[test]

View File

@ -15,6 +15,7 @@ pub mod star_or;
pub mod task_view;
pub mod tasks;
pub mod versioning;
pub mod webhooks;
pub use milli::{heed, Index};
use uuid::Uuid;
pub use versioning::VERSION_FILE_NAME;

View File

@ -132,6 +132,11 @@ pub struct DetailsView {
pub payload_size: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indexes: Option<BTreeMap<String, DetailsExportIndexSettings>>,
// index rename
#[serde(skip_serializing_if = "Option::is_none")]
pub old_index_uid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub new_index_uid: Option<String>,
}
impl DetailsView {
@ -292,6 +297,18 @@ impl DetailsView {
(None, Some(to)) | (Some(to), None) => Some(to),
(Some(_), Some(to)) => Some(to),
},
old_index_uid: match (self.old_index_uid.clone(), other.old_index_uid.clone()) {
(None, None) => None,
(None, Some(uid)) | (Some(uid), None) => Some(uid),
// We should never be able to batch multiple renames at the same time.
(Some(left), Some(_right)) => Some(left),
},
new_index_uid: match (self.new_index_uid.clone(), other.new_index_uid.clone()) {
(None, None) => None,
(None, Some(uid)) | (Some(uid), None) => Some(uid),
// We should never be able to batch multiple renames at the same time.
(Some(left), Some(_right)) => Some(left),
},
}
}
}
@ -324,9 +341,12 @@ impl From<Details> for DetailsView {
settings.hide_secrets();
DetailsView { settings: Some(settings), ..DetailsView::default() }
}
Details::IndexInfo { primary_key } => {
DetailsView { primary_key: Some(primary_key), ..DetailsView::default() }
}
Details::IndexInfo { primary_key, new_index_uid, old_index_uid } => DetailsView {
primary_key: Some(primary_key),
new_index_uid: new_index_uid.clone(),
old_index_uid: old_index_uid.clone(),
..DetailsView::default()
},
Details::DocumentDeletion {
provided_ids: received_document_ids,
deleted_documents,

View File

@ -140,6 +140,7 @@ pub enum KindWithContent {
IndexUpdate {
index_uid: String,
primary_key: Option<String>,
new_index_uid: Option<String>,
},
IndexSwap {
swaps: Vec<IndexSwap>,
@ -172,6 +173,8 @@ pub enum KindWithContent {
#[serde(rename_all = "camelCase")]
pub struct IndexSwap {
pub indexes: (String, String),
#[serde(default)]
pub rename: bool,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
@ -220,8 +223,14 @@ impl KindWithContent {
| DocumentClear { index_uid }
| SettingsUpdate { index_uid, .. }
| IndexCreation { index_uid, .. }
| IndexUpdate { index_uid, .. }
| IndexDeletion { index_uid } => vec![index_uid],
IndexUpdate { index_uid, new_index_uid, .. } => {
let mut indexes = vec![index_uid.as_str()];
if let Some(new_uid) = new_index_uid {
indexes.push(new_uid.as_str());
}
indexes
}
IndexSwap { swaps } => {
let mut indexes = HashSet::<&str>::default();
for swap in swaps {
@ -270,9 +279,17 @@ impl KindWithContent {
KindWithContent::SettingsUpdate { new_settings, .. } => {
Some(Details::SettingsUpdate { settings: new_settings.clone() })
}
KindWithContent::IndexCreation { primary_key, .. }
| KindWithContent::IndexUpdate { primary_key, .. } => {
Some(Details::IndexInfo { primary_key: primary_key.clone() })
KindWithContent::IndexCreation { primary_key, .. } => Some(Details::IndexInfo {
primary_key: primary_key.clone(),
old_index_uid: None,
new_index_uid: None,
}),
KindWithContent::IndexUpdate { primary_key, new_index_uid, index_uid } => {
Some(Details::IndexInfo {
primary_key: primary_key.clone(),
old_index_uid: new_index_uid.as_ref().map(|_| index_uid.clone()),
new_index_uid: new_index_uid.clone(),
})
}
KindWithContent::IndexSwap { swaps } => {
Some(Details::IndexSwap { swaps: swaps.clone() })
@ -344,9 +361,17 @@ impl KindWithContent {
Some(Details::SettingsUpdate { settings: new_settings.clone() })
}
KindWithContent::IndexDeletion { .. } => None,
KindWithContent::IndexCreation { primary_key, .. }
| KindWithContent::IndexUpdate { primary_key, .. } => {
Some(Details::IndexInfo { primary_key: primary_key.clone() })
KindWithContent::IndexCreation { primary_key, .. } => Some(Details::IndexInfo {
primary_key: primary_key.clone(),
old_index_uid: None,
new_index_uid: None,
}),
KindWithContent::IndexUpdate { primary_key, new_index_uid, index_uid } => {
Some(Details::IndexInfo {
primary_key: primary_key.clone(),
old_index_uid: new_index_uid.as_ref().map(|_| index_uid.clone()),
new_index_uid: new_index_uid.clone(),
})
}
KindWithContent::IndexSwap { .. } => {
todo!()
@ -400,11 +425,17 @@ impl From<&KindWithContent> for Option<Details> {
Some(Details::SettingsUpdate { settings: new_settings.clone() })
}
KindWithContent::IndexDeletion { .. } => None,
KindWithContent::IndexCreation { primary_key, .. } => {
Some(Details::IndexInfo { primary_key: primary_key.clone() })
}
KindWithContent::IndexUpdate { primary_key, .. } => {
Some(Details::IndexInfo { primary_key: primary_key.clone() })
KindWithContent::IndexCreation { primary_key, .. } => Some(Details::IndexInfo {
primary_key: primary_key.clone(),
new_index_uid: None,
old_index_uid: None,
}),
KindWithContent::IndexUpdate { primary_key, new_index_uid, index_uid } => {
Some(Details::IndexInfo {
primary_key: primary_key.clone(),
old_index_uid: new_index_uid.as_ref().map(|_| index_uid.clone()),
new_index_uid: new_index_uid.clone(),
})
}
KindWithContent::IndexSwap { .. } => None,
KindWithContent::TaskCancelation { query, tasks } => Some(Details::TaskCancelation {
@ -657,6 +688,8 @@ pub enum Details {
},
IndexInfo {
primary_key: Option<String>,
new_index_uid: Option<String>,
old_index_uid: Option<String>,
},
DocumentDeletion {
provided_ids: usize,

View File

@ -0,0 +1,28 @@
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Webhook {
pub url: String,
#[serde(default)]
pub headers: BTreeMap<String, String>,
}
#[derive(Debug, Serialize, Default, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct WebhooksView {
#[serde(default)]
pub webhooks: BTreeMap<Uuid, Webhook>,
}
// Same as the WebhooksView instead it should never contains the CLI webhooks.
// It's the right structure to use in the dump
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct WebhooksDumpView {
#[serde(default)]
pub webhooks: BTreeMap<Uuid, Webhook>,
}