From 07e7ddbc5b929d9628f6a498e85a7044e3953c7c Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sat, 31 Aug 2024 13:18:59 +0300 Subject: [PATCH 01/21] Change Actions enum to bitflags --- Cargo.lock | 1 + meilisearch-types/Cargo.toml | 1 + meilisearch-types/src/keys.rs | 280 +++++++++++++++++++++++++--------- milli/src/vector/mod.rs | 2 +- 4 files changed, 211 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd67520ea..d6c674f68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3486,6 +3486,7 @@ version = "1.10.0" dependencies = [ "actix-web", "anyhow", + "bitflags 2.6.0", "convert_case 0.6.0", "csv", "deserr", diff --git a/meilisearch-types/Cargo.toml b/meilisearch-types/Cargo.toml index 73306c4dc..351aa9468 100644 --- a/meilisearch-types/Cargo.toml +++ b/meilisearch-types/Cargo.toml @@ -38,6 +38,7 @@ time = { version = "0.3.36", features = [ ] } tokio = "1.38" uuid = { version = "1.10.0", features = ["serde", "v4"] } +bitflags = {version = "2.6.0", features = ["serde"] } [dev-dependencies] insta = "1.39.0" diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index f7d80bbcb..483289b7d 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -2,7 +2,8 @@ use std::convert::Infallible; use std::hash::Hash; use std::str::FromStr; -use deserr::{DeserializeError, Deserr, MergeWithError, ValuePointerRef}; +use bitflags::bitflags; +use deserr::{take_cf_content, DeserializeError, Deserr, MergeWithError, ValuePointerRef}; use enum_iterator::Sequence; use milli::update::Setting; use serde::{Deserialize, Serialize}; @@ -179,113 +180,248 @@ fn parse_expiration_date( } } -#[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Sequence, Deserr)] -#[repr(u8)] -pub enum Action { +bitflags! { + #[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] + #[repr(transparent)] + pub struct Action: u8 { #[serde(rename = "*")] - #[deserr(rename = "*")] - All = 0, + const All = 0; #[serde(rename = "search")] - #[deserr(rename = "search")] - Search, + const Search = 1; #[serde(rename = "documents.*")] - #[deserr(rename = "documents.*")] - DocumentsAll, + const DocumentsAll = 2; #[serde(rename = "documents.add")] - #[deserr(rename = "documents.add")] - DocumentsAdd, + const DocumentsAdd = 3; #[serde(rename = "documents.get")] - #[deserr(rename = "documents.get")] - DocumentsGet, + const DocumentsGet = 4; #[serde(rename = "documents.delete")] - #[deserr(rename = "documents.delete")] - DocumentsDelete, + const DocumentsDelete = 5; #[serde(rename = "indexes.*")] - #[deserr(rename = "indexes.*")] - IndexesAll, + const IndexesAll = 6; #[serde(rename = "indexes.create")] - #[deserr(rename = "indexes.create")] - IndexesAdd, + const IndexesAdd = 7; #[serde(rename = "indexes.get")] - #[deserr(rename = "indexes.get")] - IndexesGet, + const IndexesGet = 8; #[serde(rename = "indexes.update")] - #[deserr(rename = "indexes.update")] - IndexesUpdate, + const IndexesUpdate = 9; #[serde(rename = "indexes.delete")] - #[deserr(rename = "indexes.delete")] - IndexesDelete, + const IndexesDelete = 10; #[serde(rename = "indexes.swap")] - #[deserr(rename = "indexes.swap")] - IndexesSwap, + const IndexesSwap = 11; #[serde(rename = "tasks.*")] - #[deserr(rename = "tasks.*")] - TasksAll, + const TasksAll = 12; #[serde(rename = "tasks.cancel")] - #[deserr(rename = "tasks.cancel")] - TasksCancel, + const TasksCancel = 13; #[serde(rename = "tasks.delete")] - #[deserr(rename = "tasks.delete")] - TasksDelete, + const TasksDelete = 14; #[serde(rename = "tasks.get")] - #[deserr(rename = "tasks.get")] - TasksGet, + const TasksGet = 15; #[serde(rename = "settings.*")] - #[deserr(rename = "settings.*")] - SettingsAll, + const SettingsAll = 16; #[serde(rename = "settings.get")] - #[deserr(rename = "settings.get")] - SettingsGet, + const SettingsGet = 17; #[serde(rename = "settings.update")] - #[deserr(rename = "settings.update")] - SettingsUpdate, + const SettingsUpdate = 18; #[serde(rename = "stats.*")] - #[deserr(rename = "stats.*")] - StatsAll, + const StatsAll = 19; #[serde(rename = "stats.get")] - #[deserr(rename = "stats.get")] - StatsGet, + const StatsGet = 20; #[serde(rename = "metrics.*")] - #[deserr(rename = "metrics.*")] - MetricsAll, + const MetricsAll = 21; #[serde(rename = "metrics.get")] - #[deserr(rename = "metrics.get")] - MetricsGet, + const MetricsGet = 22; #[serde(rename = "dumps.*")] - #[deserr(rename = "dumps.*")] - DumpsAll, + const DumpsAll = 23; #[serde(rename = "dumps.create")] - #[deserr(rename = "dumps.create")] - DumpsCreate, + const DumpsCreate = 24; #[serde(rename = "snapshots.*")] - #[deserr(rename = "snapshots.*")] - SnapshotsAll, + const SnapshotsAll = 25; #[serde(rename = "snapshots.create")] - #[deserr(rename = "snapshots.create")] - SnapshotsCreate, + const SnapshotsCreate = 26; #[serde(rename = "version")] - #[deserr(rename = "version")] - Version, + const Version = 27; #[serde(rename = "keys.create")] - #[deserr(rename = "keys.create")] - KeysAdd, + const KeysAdd = 28; #[serde(rename = "keys.get")] - #[deserr(rename = "keys.get")] - KeysGet, + const KeysGet = 29; #[serde(rename = "keys.update")] - #[deserr(rename = "keys.update")] - KeysUpdate, + const KeysUpdate = 30; #[serde(rename = "keys.delete")] - #[deserr(rename = "keys.delete")] - KeysDelete, + const KeysDelete = 31; #[serde(rename = "experimental.get")] - #[deserr(rename = "experimental.get")] - ExperimentalFeaturesGet, + const ExperimentalFeaturesGet = 32; #[serde(rename = "experimental.update")] - #[deserr(rename = "experimental.update")] - ExperimentalFeaturesUpdate, + const ExperimentalFeaturesUpdate = 33; + } } +impl Deserr for Action { + fn deserialize_from_value( + value: deserr::Value, + location: deserr::ValuePointerRef<'_>, + ) -> Result { + match value { + deserr::Value::String(s) => match s.as_str() { + "*" => Ok(Action::All), + "search" => Ok(Action::Search), + "documents.*" => Ok(Action::DocumentsAll), + "documents.add" => Ok(Action::DocumentsAdd), + "documents.get" => Ok(Action::DocumentsGet), + "documents.delete" => Ok(Action::DocumentsDelete), + "indexes.*" => Ok(Action::IndexesAll), + "indexes.create" => Ok(Action::IndexesAdd), + "indexes.get" => Ok(Action::IndexesGet), + "indexes.update" => Ok(Action::IndexesUpdate), + "indexes.delete" => Ok(Action::IndexesDelete), + "indexes.swap" => Ok(Action::IndexesSwap), + "tasks.*" => Ok(Action::TasksAll), + "tasks.cancel" => Ok(Action::TasksCancel), + "tasks.delete" => Ok(Action::TasksDelete), + "tasks.get" => Ok(Action::TasksGet), + "settings.*" => Ok(Action::SettingsAll), + "settings.get" => Ok(Action::SettingsGet), + "settings.update" => Ok(Action::SettingsUpdate), + "stats.*" => Ok(Action::StatsAll), + "stats.get" => Ok(Action::StatsGet), + "metrics.*" => Ok(Action::MetricsAll), + "metrics.get" => Ok(Action::MetricsGet), + "dumps.*" => Ok(Action::DumpsAll), + "dumps.create" => Ok(Action::DumpsCreate), + "snapshots.*" => Ok(Action::SnapshotsAll), + "snapshots.create" => Ok(Action::SnapshotsCreate), + "version" => Ok(Action::Version), + "keys.create" => Ok(Action::KeysAdd), + "keys.get" => Ok(Action::KeysGet), + "keys.update" => Ok(Action::KeysUpdate), + "keys.delete" => Ok(Action::KeysDelete), + "experimental.get" => Ok(Action::ExperimentalFeaturesGet), + "experimental.update" => Ok(Action::ExperimentalFeaturesUpdate), + _ => Err(deserr::take_cf_content(E::error::( + None, + deserr::ErrorKind::Unexpected { msg: format!("TODO {}", s) }, + location, + ))), + }, + + value => Err(take_cf_content(E::error( + None, + deserr::ErrorKind::IncorrectValueKind { + actual: value, + accepted: &[deserr::ValueKind::String], + }, + location, + ))), + } + } +} + +// #[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Sequence, Deserr)] +// #[repr(u8)] +// pub enum Action { +// #[serde(rename = "*")] +// #[deserr(rename = "*")] +// All = 0, +// #[serde(rename = "search")] +// #[deserr(rename = "search")] +// Search, +// #[serde(rename = "documents.*")] +// #[deserr(rename = "documents.*")] +// DocumentsAll, +// #[serde(rename = "documents.add")] +// #[deserr(rename = "documents.add")] +// DocumentsAdd, +// #[serde(rename = "documents.get")] +// #[deserr(rename = "documents.get")] +// DocumentsGet, +// #[serde(rename = "documents.delete")] +// #[deserr(rename = "documents.delete")] +// DocumentsDelete, +// #[serde(rename = "indexes.*")] +// #[deserr(rename = "indexes.*")] +// IndexesAll, +// #[serde(rename = "indexes.create")] +// #[deserr(rename = "indexes.create")] +// IndexesAdd, +// #[serde(rename = "indexes.get")] +// #[deserr(rename = "indexes.get")] +// IndexesGet, +// #[serde(rename = "indexes.update")] +// #[deserr(rename = "indexes.update")] +// IndexesUpdate, +// #[serde(rename = "indexes.delete")] +// #[deserr(rename = "indexes.delete")] +// IndexesDelete, +// #[serde(rename = "indexes.swap")] +// #[deserr(rename = "indexes.swap")] +// IndexesSwap, +// #[serde(rename = "tasks.*")] +// #[deserr(rename = "tasks.*")] +// TasksAll, +// #[serde(rename = "tasks.cancel")] +// #[deserr(rename = "tasks.cancel")] +// TasksCancel, +// #[serde(rename = "tasks.delete")] +// #[deserr(rename = "tasks.delete")] +// TasksDelete, +// #[serde(rename = "tasks.get")] +// #[deserr(rename = "tasks.get")] +// TasksGet, +// #[serde(rename = "settings.*")] +// #[deserr(rename = "settings.*")] +// SettingsAll, +// #[serde(rename = "settings.get")] +// #[deserr(rename = "settings.get")] +// SettingsGet, +// #[serde(rename = "settings.update")] +// #[deserr(rename = "settings.update")] +// SettingsUpdate, +// #[serde(rename = "stats.*")] +// #[deserr(rename = "stats.*")] +// StatsAll, +// #[serde(rename = "stats.get")] +// #[deserr(rename = "stats.get")] +// StatsGet, +// #[serde(rename = "metrics.*")] +// #[deserr(rename = "metrics.*")] +// MetricsAll, +// #[serde(rename = "metrics.get")] +// #[deserr(rename = "metrics.get")] +// MetricsGet, +// #[serde(rename = "dumps.*")] +// #[deserr(rename = "dumps.*")] +// DumpsAll, +// #[serde(rename = "dumps.create")] +// #[deserr(rename = "dumps.create")] +// DumpsCreate, +// #[serde(rename = "snapshots.*")] +// #[deserr(rename = "snapshots.*")] +// SnapshotsAll, +// #[serde(rename = "snapshots.create")] +// #[deserr(rename = "snapshots.create")] +// SnapshotsCreate, +// #[serde(rename = "version")] +// #[deserr(rename = "version")] +// Version, +// #[serde(rename = "keys.create")] +// #[deserr(rename = "keys.create")] +// KeysAdd, +// #[serde(rename = "keys.get")] +// #[deserr(rename = "keys.get")] +// KeysGet, +// #[serde(rename = "keys.update")] +// #[deserr(rename = "keys.update")] +// KeysUpdate, +// #[serde(rename = "keys.delete")] +// #[deserr(rename = "keys.delete")] +// KeysDelete, +// #[serde(rename = "experimental.get")] +// #[deserr(rename = "experimental.get")] +// ExperimentalFeaturesGet, +// #[serde(rename = "experimental.update")] +// #[deserr(rename = "experimental.update")] +// ExperimentalFeaturesUpdate, +// } + impl Action { pub const fn from_repr(repr: u8) -> Option { use actions::*; diff --git a/milli/src/vector/mod.rs b/milli/src/vector/mod.rs index caccb404b..349a59222 100644 --- a/milli/src/vector/mod.rs +++ b/milli/src/vector/mod.rs @@ -352,7 +352,7 @@ where None, deserr::ErrorKind::Unexpected { msg: format!( - "the distribution sigma must be in the range ]0, 1], got {}", + "the distribution sigma must be in the range [0, 1], got {}", value.sigma ), }, From 75969f9f68cb25716836c362a7d54fa690a4f9a4 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:14:47 +0300 Subject: [PATCH 02/21] Add manual serde Deserialize impl --- meilisearch-types/src/keys.rs | 371 ++++++++++++---------------------- 1 file changed, 132 insertions(+), 239 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 483289b7d..459fdf8ca 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -4,9 +4,8 @@ use std::str::FromStr; use bitflags::bitflags; use deserr::{take_cf_content, DeserializeError, Deserr, MergeWithError, ValuePointerRef}; -use enum_iterator::Sequence; use milli::update::Setting; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use time::format_description::well_known::Rfc3339; use time::macros::{format_description, time}; use time::{Date, OffsetDateTime, PrimitiveDateTime}; @@ -181,248 +180,84 @@ fn parse_expiration_date( } bitflags! { - #[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] + #[derive(Copy, Clone, Serialize, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] #[repr(transparent)] pub struct Action: u8 { - #[serde(rename = "*")] const All = 0; - #[serde(rename = "search")] const Search = 1; - #[serde(rename = "documents.*")] const DocumentsAll = 2; - #[serde(rename = "documents.add")] const DocumentsAdd = 3; - #[serde(rename = "documents.get")] const DocumentsGet = 4; - #[serde(rename = "documents.delete")] const DocumentsDelete = 5; - #[serde(rename = "indexes.*")] const IndexesAll = 6; - #[serde(rename = "indexes.create")] const IndexesAdd = 7; - #[serde(rename = "indexes.get")] const IndexesGet = 8; - #[serde(rename = "indexes.update")] const IndexesUpdate = 9; - #[serde(rename = "indexes.delete")] const IndexesDelete = 10; - #[serde(rename = "indexes.swap")] const IndexesSwap = 11; - #[serde(rename = "tasks.*")] const TasksAll = 12; - #[serde(rename = "tasks.cancel")] const TasksCancel = 13; - #[serde(rename = "tasks.delete")] const TasksDelete = 14; - #[serde(rename = "tasks.get")] const TasksGet = 15; - #[serde(rename = "settings.*")] const SettingsAll = 16; - #[serde(rename = "settings.get")] const SettingsGet = 17; - #[serde(rename = "settings.update")] const SettingsUpdate = 18; - #[serde(rename = "stats.*")] const StatsAll = 19; - #[serde(rename = "stats.get")] const StatsGet = 20; - #[serde(rename = "metrics.*")] const MetricsAll = 21; - #[serde(rename = "metrics.get")] const MetricsGet = 22; - #[serde(rename = "dumps.*")] const DumpsAll = 23; - #[serde(rename = "dumps.create")] const DumpsCreate = 24; - #[serde(rename = "snapshots.*")] const SnapshotsAll = 25; - #[serde(rename = "snapshots.create")] const SnapshotsCreate = 26; - #[serde(rename = "version")] const Version = 27; - #[serde(rename = "keys.create")] const KeysAdd = 28; - #[serde(rename = "keys.get")] const KeysGet = 29; - #[serde(rename = "keys.update")] const KeysUpdate = 30; - #[serde(rename = "keys.delete")] const KeysDelete = 31; - #[serde(rename = "experimental.get")] const ExperimentalFeaturesGet = 32; - #[serde(rename = "experimental.update")] const ExperimentalFeaturesUpdate = 33; } } -impl Deserr for Action { - fn deserialize_from_value( - value: deserr::Value, - location: deserr::ValuePointerRef<'_>, - ) -> Result { - match value { - deserr::Value::String(s) => match s.as_str() { - "*" => Ok(Action::All), - "search" => Ok(Action::Search), - "documents.*" => Ok(Action::DocumentsAll), - "documents.add" => Ok(Action::DocumentsAdd), - "documents.get" => Ok(Action::DocumentsGet), - "documents.delete" => Ok(Action::DocumentsDelete), - "indexes.*" => Ok(Action::IndexesAll), - "indexes.create" => Ok(Action::IndexesAdd), - "indexes.get" => Ok(Action::IndexesGet), - "indexes.update" => Ok(Action::IndexesUpdate), - "indexes.delete" => Ok(Action::IndexesDelete), - "indexes.swap" => Ok(Action::IndexesSwap), - "tasks.*" => Ok(Action::TasksAll), - "tasks.cancel" => Ok(Action::TasksCancel), - "tasks.delete" => Ok(Action::TasksDelete), - "tasks.get" => Ok(Action::TasksGet), - "settings.*" => Ok(Action::SettingsAll), - "settings.get" => Ok(Action::SettingsGet), - "settings.update" => Ok(Action::SettingsUpdate), - "stats.*" => Ok(Action::StatsAll), - "stats.get" => Ok(Action::StatsGet), - "metrics.*" => Ok(Action::MetricsAll), - "metrics.get" => Ok(Action::MetricsGet), - "dumps.*" => Ok(Action::DumpsAll), - "dumps.create" => Ok(Action::DumpsCreate), - "snapshots.*" => Ok(Action::SnapshotsAll), - "snapshots.create" => Ok(Action::SnapshotsCreate), - "version" => Ok(Action::Version), - "keys.create" => Ok(Action::KeysAdd), - "keys.get" => Ok(Action::KeysGet), - "keys.update" => Ok(Action::KeysUpdate), - "keys.delete" => Ok(Action::KeysDelete), - "experimental.get" => Ok(Action::ExperimentalFeaturesGet), - "experimental.update" => Ok(Action::ExperimentalFeaturesUpdate), - _ => Err(deserr::take_cf_content(E::error::( - None, - deserr::ErrorKind::Unexpected { msg: format!("TODO {}", s) }, - location, - ))), - }, - - value => Err(take_cf_content(E::error( - None, - deserr::ErrorKind::IncorrectValueKind { - actual: value, - accepted: &[deserr::ValueKind::String], - }, - location, - ))), - } - } -} - -// #[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Sequence, Deserr)] -// #[repr(u8)] -// pub enum Action { -// #[serde(rename = "*")] -// #[deserr(rename = "*")] -// All = 0, -// #[serde(rename = "search")] -// #[deserr(rename = "search")] -// Search, -// #[serde(rename = "documents.*")] -// #[deserr(rename = "documents.*")] -// DocumentsAll, -// #[serde(rename = "documents.add")] -// #[deserr(rename = "documents.add")] -// DocumentsAdd, -// #[serde(rename = "documents.get")] -// #[deserr(rename = "documents.get")] -// DocumentsGet, -// #[serde(rename = "documents.delete")] -// #[deserr(rename = "documents.delete")] -// DocumentsDelete, -// #[serde(rename = "indexes.*")] -// #[deserr(rename = "indexes.*")] -// IndexesAll, -// #[serde(rename = "indexes.create")] -// #[deserr(rename = "indexes.create")] -// IndexesAdd, -// #[serde(rename = "indexes.get")] -// #[deserr(rename = "indexes.get")] -// IndexesGet, -// #[serde(rename = "indexes.update")] -// #[deserr(rename = "indexes.update")] -// IndexesUpdate, -// #[serde(rename = "indexes.delete")] -// #[deserr(rename = "indexes.delete")] -// IndexesDelete, -// #[serde(rename = "indexes.swap")] -// #[deserr(rename = "indexes.swap")] -// IndexesSwap, -// #[serde(rename = "tasks.*")] -// #[deserr(rename = "tasks.*")] -// TasksAll, -// #[serde(rename = "tasks.cancel")] -// #[deserr(rename = "tasks.cancel")] -// TasksCancel, -// #[serde(rename = "tasks.delete")] -// #[deserr(rename = "tasks.delete")] -// TasksDelete, -// #[serde(rename = "tasks.get")] -// #[deserr(rename = "tasks.get")] -// TasksGet, -// #[serde(rename = "settings.*")] -// #[deserr(rename = "settings.*")] -// SettingsAll, -// #[serde(rename = "settings.get")] -// #[deserr(rename = "settings.get")] -// SettingsGet, -// #[serde(rename = "settings.update")] -// #[deserr(rename = "settings.update")] -// SettingsUpdate, -// #[serde(rename = "stats.*")] -// #[deserr(rename = "stats.*")] -// StatsAll, -// #[serde(rename = "stats.get")] -// #[deserr(rename = "stats.get")] -// StatsGet, -// #[serde(rename = "metrics.*")] -// #[deserr(rename = "metrics.*")] -// MetricsAll, -// #[serde(rename = "metrics.get")] -// #[deserr(rename = "metrics.get")] -// MetricsGet, -// #[serde(rename = "dumps.*")] -// #[deserr(rename = "dumps.*")] -// DumpsAll, -// #[serde(rename = "dumps.create")] -// #[deserr(rename = "dumps.create")] -// DumpsCreate, -// #[serde(rename = "snapshots.*")] -// #[deserr(rename = "snapshots.*")] -// SnapshotsAll, -// #[serde(rename = "snapshots.create")] -// #[deserr(rename = "snapshots.create")] -// SnapshotsCreate, -// #[serde(rename = "version")] -// #[deserr(rename = "version")] -// Version, -// #[serde(rename = "keys.create")] -// #[deserr(rename = "keys.create")] -// KeysAdd, -// #[serde(rename = "keys.get")] -// #[deserr(rename = "keys.get")] -// KeysGet, -// #[serde(rename = "keys.update")] -// #[deserr(rename = "keys.update")] -// KeysUpdate, -// #[serde(rename = "keys.delete")] -// #[deserr(rename = "keys.delete")] -// KeysDelete, -// #[serde(rename = "experimental.get")] -// #[deserr(rename = "experimental.get")] -// ExperimentalFeaturesGet, -// #[serde(rename = "experimental.update")] -// #[deserr(rename = "experimental.update")] -// ExperimentalFeaturesUpdate, -// } - impl Action { + const SERIALIZATION_MAP: [(&'static str, Self); 34] = [ + ("*", Self::All), + ("search", Self::Search), + ("documents.*", Self::DocumentsAll), + ("documents.add", Self::DocumentsAdd), + ("documents.get", Self::DocumentsGet), + ("documents.delete", Self::DocumentsDelete), + ("indexes.*", Self::IndexesAll), + ("indexes.create", Self::IndexesAdd), + ("indexes.get", Self::IndexesGet), + ("indexes.update", Self::IndexesUpdate), + ("indexes.delete", Self::IndexesDelete), + ("indexes.swap", Self::IndexesSwap), + ("tasks.*", Self::TasksAll), + ("tasks.cancel", Self::TasksCancel), + ("tasks.delete", Self::TasksDelete), + ("tasks.get", Self::TasksGet), + ("settings.*", Self::SettingsAll), + ("settings.get", Self::SettingsGet), + ("settings.update", Self::SettingsUpdate), + ("stats.*", Self::StatsAll), + ("stats.get", Self::StatsGet), + ("metrics.*", Self::MetricsAll), + ("metrics.get", Self::MetricsGet), + ("dumps.*", Self::DumpsAll), + ("dumps.create", Self::DumpsCreate), + ("snapshots.*", Self::SnapshotsAll), + ("snapshots.create", Self::SnapshotsCreate), + ("version", Self::Version), + ("keys.create", Self::KeysAdd), + ("keys.get", Self::KeysGet), + ("keys.update", Self::KeysUpdate), + ("keys.delete", Self::KeysDelete), + ("experimental.get", Self::ExperimentalFeaturesGet), + ("experimental.update", Self::ExperimentalFeaturesUpdate), + ]; + pub const fn from_repr(repr: u8) -> Option { use actions::*; match repr { @@ -464,44 +299,102 @@ impl Action { } pub const fn repr(&self) -> u8 { - *self as u8 + self.bits() + } +} + +impl Deserr for Action { + fn deserialize_from_value( + value: deserr::Value, + location: deserr::ValuePointerRef<'_>, + ) -> Result { + match value { + deserr::Value::String(s) => { + match Self::SERIALIZATION_MAP.iter().find(|(serialized, _)| s == *serialized) { + Some((_, action)) => Ok(*action), + None => Err(deserr::take_cf_content(E::error::( + None, + deserr::ErrorKind::Unexpected { msg: format!("TODO {}", s) }, + location, + ))), + } + } + _ => Err(take_cf_content(E::error( + None, + deserr::ErrorKind::IncorrectValueKind { + actual: value, + accepted: &[deserr::ValueKind::String], + }, + location, + ))), + } + } +} + +impl<'de> Deserialize<'de> for Action { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Visitor; + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Action; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "the name of a valid action (string)") + } + + fn visit_str(self, s: &str) -> Result + where + E: serde::de::Error, + { + // @TODO: Make a to_serialized and to_desiralized on Action + match Self::Value::SERIALIZATION_MAP.iter().find(|(serialized, _)| s == *serialized) + { + Some((_, action)) => Ok(*action), + None => Err(E::invalid_value(serde::de::Unexpected::Str(s), &"a valid action")), + } + } + } + + deserializer.deserialize_str(Visitor) } } pub mod actions { - use super::Action::*; + use super::Action as A; - pub(crate) const ALL: u8 = All.repr(); - pub const SEARCH: u8 = Search.repr(); - pub const DOCUMENTS_ALL: u8 = DocumentsAll.repr(); - pub const DOCUMENTS_ADD: u8 = DocumentsAdd.repr(); - pub const DOCUMENTS_GET: u8 = DocumentsGet.repr(); - pub const DOCUMENTS_DELETE: u8 = DocumentsDelete.repr(); - pub const INDEXES_ALL: u8 = IndexesAll.repr(); - pub const INDEXES_CREATE: u8 = IndexesAdd.repr(); - pub const INDEXES_GET: u8 = IndexesGet.repr(); - pub const INDEXES_UPDATE: u8 = IndexesUpdate.repr(); - pub const INDEXES_DELETE: u8 = IndexesDelete.repr(); - pub const INDEXES_SWAP: u8 = IndexesSwap.repr(); - pub const TASKS_ALL: u8 = TasksAll.repr(); - pub const TASKS_CANCEL: u8 = TasksCancel.repr(); - pub const TASKS_DELETE: u8 = TasksDelete.repr(); - pub const TASKS_GET: u8 = TasksGet.repr(); - pub const SETTINGS_ALL: u8 = SettingsAll.repr(); - pub const SETTINGS_GET: u8 = SettingsGet.repr(); - pub const SETTINGS_UPDATE: u8 = SettingsUpdate.repr(); - pub const STATS_ALL: u8 = StatsAll.repr(); - pub const STATS_GET: u8 = StatsGet.repr(); - pub const METRICS_ALL: u8 = MetricsAll.repr(); - pub const METRICS_GET: u8 = MetricsGet.repr(); - pub const DUMPS_ALL: u8 = DumpsAll.repr(); - pub const DUMPS_CREATE: u8 = DumpsCreate.repr(); - pub const SNAPSHOTS_CREATE: u8 = SnapshotsCreate.repr(); - pub const VERSION: u8 = Version.repr(); - pub const KEYS_CREATE: u8 = KeysAdd.repr(); - pub const KEYS_GET: u8 = KeysGet.repr(); - pub const KEYS_UPDATE: u8 = KeysUpdate.repr(); - pub const KEYS_DELETE: u8 = KeysDelete.repr(); - pub const EXPERIMENTAL_FEATURES_GET: u8 = ExperimentalFeaturesGet.repr(); - pub const EXPERIMENTAL_FEATURES_UPDATE: u8 = ExperimentalFeaturesUpdate.repr(); + pub(crate) const ALL: u8 = A::All.repr(); + pub const SEARCH: u8 = A::Search.repr(); + pub const DOCUMENTS_ALL: u8 = A::DocumentsAll.repr(); + pub const DOCUMENTS_ADD: u8 = A::DocumentsAdd.repr(); + pub const DOCUMENTS_GET: u8 = A::DocumentsGet.repr(); + pub const DOCUMENTS_DELETE: u8 = A::DocumentsDelete.repr(); + pub const INDEXES_ALL: u8 = A::IndexesAll.repr(); + pub const INDEXES_CREATE: u8 = A::IndexesAdd.repr(); + pub const INDEXES_GET: u8 = A::IndexesGet.repr(); + pub const INDEXES_UPDATE: u8 = A::IndexesUpdate.repr(); + pub const INDEXES_DELETE: u8 = A::IndexesDelete.repr(); + pub const INDEXES_SWAP: u8 = A::IndexesSwap.repr(); + pub const TASKS_ALL: u8 = A::TasksAll.repr(); + pub const TASKS_CANCEL: u8 = A::TasksCancel.repr(); + pub const TASKS_DELETE: u8 = A::TasksDelete.repr(); + pub const TASKS_GET: u8 = A::TasksGet.repr(); + pub const SETTINGS_ALL: u8 = A::SettingsAll.repr(); + pub const SETTINGS_GET: u8 = A::SettingsGet.repr(); + pub const SETTINGS_UPDATE: u8 = A::SettingsUpdate.repr(); + pub const STATS_ALL: u8 = A::StatsAll.repr(); + pub const STATS_GET: u8 = A::StatsGet.repr(); + pub const METRICS_ALL: u8 = A::MetricsAll.repr(); + pub const METRICS_GET: u8 = A::MetricsGet.repr(); + pub const DUMPS_ALL: u8 = A::DumpsAll.repr(); + pub const DUMPS_CREATE: u8 = A::DumpsCreate.repr(); + pub const SNAPSHOTS_CREATE: u8 = A::SnapshotsCreate.repr(); + pub const VERSION: u8 = A::Version.repr(); + pub const KEYS_CREATE: u8 = A::KeysAdd.repr(); + pub const KEYS_GET: u8 = A::KeysGet.repr(); + pub const KEYS_UPDATE: u8 = A::KeysUpdate.repr(); + pub const KEYS_DELETE: u8 = A::KeysDelete.repr(); + pub const EXPERIMENTAL_FEATURES_GET: u8 = A::ExperimentalFeaturesGet.repr(); + pub const EXPERIMENTAL_FEATURES_UPDATE: u8 = A::ExperimentalFeaturesUpdate.repr(); } From 6688604a934aa7c95475255ae8a1815da8fa5c00 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Tue, 17 Sep 2024 12:55:45 +0300 Subject: [PATCH 03/21] Add Serialize impl --- meilisearch-auth/src/store.rs | 2 +- meilisearch-types/src/keys.rs | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/meilisearch-auth/src/store.rs b/meilisearch-auth/src/store.rs index ef992e836..237570522 100644 --- a/meilisearch-auth/src/store.rs +++ b/meilisearch-auth/src/store.rs @@ -105,7 +105,7 @@ impl HeedAuthStore { let mut actions = HashSet::new(); for action in &key.actions { - match action { + match *action { Action::All => actions.extend(enum_iterator::all::()), Action::DocumentsAll => { actions.extend( diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 459fdf8ca..537567e5c 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -4,8 +4,9 @@ use std::str::FromStr; use bitflags::bitflags; use deserr::{take_cf_content, DeserializeError, Deserr, MergeWithError, ValuePointerRef}; +use enum_iterator::Sequence; use milli::update::Setting; -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use time::format_description::well_known::Rfc3339; use time::macros::{format_description, time}; use time::{Date, OffsetDateTime, PrimitiveDateTime}; @@ -180,7 +181,7 @@ fn parse_expiration_date( } bitflags! { - #[derive(Copy, Clone, Serialize, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] #[repr(transparent)] pub struct Action: u8 { const All = 0; @@ -361,6 +362,20 @@ impl<'de> Deserialize<'de> for Action { } } +impl Serialize for Action { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + Self::SERIALIZATION_MAP + .iter() + .find(|(_, action)| self == action) + .map(|(serialized, _)| serializer.serialize_str(serialized)) + // should always be found, so unwrap is safe to use + .unwrap() + } +} + pub mod actions { use super::Action as A; From b6c5a57932eb4d0fecab559b78dfb47dbbd89508 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:10:59 +0300 Subject: [PATCH 04/21] Add Sequence impl, other changes/adjustments --- meilisearch-auth/src/store.rs | 2 +- meilisearch-types/Cargo.toml | 2 +- meilisearch-types/src/keys.rs | 61 ++++++++++++++++++++++++++--------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/meilisearch-auth/src/store.rs b/meilisearch-auth/src/store.rs index 237570522..20198e497 100644 --- a/meilisearch-auth/src/store.rs +++ b/meilisearch-auth/src/store.rs @@ -144,7 +144,7 @@ impl HeedAuthStore { actions.insert(Action::MetricsGet); } other => { - actions.insert(*other); + actions.insert(other); } } } diff --git a/meilisearch-types/Cargo.toml b/meilisearch-types/Cargo.toml index 351aa9468..3a905f7f9 100644 --- a/meilisearch-types/Cargo.toml +++ b/meilisearch-types/Cargo.toml @@ -38,7 +38,7 @@ time = { version = "0.3.36", features = [ ] } tokio = "1.38" uuid = { version = "1.10.0", features = ["serde", "v4"] } -bitflags = {version = "2.6.0", features = ["serde"] } +bitflags = {version = "2.6.0" } [dev-dependencies] insta = "1.39.0" diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 537567e5c..fcbb8de05 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -222,7 +222,8 @@ bitflags! { } impl Action { - const SERIALIZATION_MAP: [(&'static str, Self); 34] = [ + // @TODO: Consider using https://github.com/rust-phf/rust-phf + const SERDE_MAP_ARR: [(&'static str, Self); 34] = [ ("*", Self::All), ("search", Self::Search), ("documents.*", Self::DocumentsAll), @@ -311,7 +312,7 @@ impl Deserr for Action { ) -> Result { match value { deserr::Value::String(s) => { - match Self::SERIALIZATION_MAP.iter().find(|(serialized, _)| s == *serialized) { + match Self::SERDE_MAP_ARR.iter().find(|(serialized, _)| s == *serialized) { Some((_, action)) => Ok(*action), None => Err(deserr::take_cf_content(E::error::( None, @@ -332,6 +333,20 @@ impl Deserr for Action { } } +impl Serialize for Action { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + Self::SERDE_MAP_ARR + .iter() + .find(|(_, action)| self == action) + .map(|(serialized, _)| serializer.serialize_str(serialized)) + // should always be found, so unwrap is safe to use + .unwrap() + } +} + impl<'de> Deserialize<'de> for Action { fn deserialize(deserializer: D) -> Result where @@ -349,9 +364,8 @@ impl<'de> Deserialize<'de> for Action { where E: serde::de::Error, { - // @TODO: Make a to_serialized and to_desiralized on Action - match Self::Value::SERIALIZATION_MAP.iter().find(|(serialized, _)| s == *serialized) - { + // @TODO: Make a to_serialized and to_desiralized on Action perhaps + match Self::Value::SERDE_MAP_ARR.iter().find(|(serialized, _)| s == *serialized) { Some((_, action)) => Ok(*action), None => Err(E::invalid_value(serde::de::Unexpected::Str(s), &"a valid action")), } @@ -362,17 +376,32 @@ impl<'de> Deserialize<'de> for Action { } } -impl Serialize for Action { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - Self::SERIALIZATION_MAP - .iter() - .find(|(_, action)| self == action) - .map(|(serialized, _)| serializer.serialize_str(serialized)) - // should always be found, so unwrap is safe to use - .unwrap() +impl Sequence for Action { + const CARDINALITY: usize = Self::SERDE_MAP_ARR.len(); + + fn next(&self) -> Option { + let next_index = self.bits() as usize + 1; + if next_index == Self::CARDINALITY { + None + } else { + Some(Self::SERDE_MAP_ARR[next_index].1) + } + } + + fn previous(&self) -> Option { + if self.bits() == 0 { + None + } else { + Some(Self::SERDE_MAP_ARR[self.bits() as usize - 1].1) + } + } + + fn first() -> Option { + Some(Self::SERDE_MAP_ARR[0].1) + } + + fn last() -> Option { + Some(Self::SERDE_MAP_ARR[Self::CARDINALITY - 1].1) } } From e54fbb0d1efec9e6f1e86779ddab962529505c06 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:54:15 +0300 Subject: [PATCH 05/21] Refactor --- meilisearch-types/Cargo.toml | 2 +- meilisearch-types/src/keys.rs | 47 +++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/meilisearch-types/Cargo.toml b/meilisearch-types/Cargo.toml index 3a905f7f9..3aae58b2b 100644 --- a/meilisearch-types/Cargo.toml +++ b/meilisearch-types/Cargo.toml @@ -38,7 +38,7 @@ time = { version = "0.3.36", features = [ ] } tokio = "1.38" uuid = { version = "1.10.0", features = ["serde", "v4"] } -bitflags = {version = "2.6.0" } +bitflags = "2.6.0" [dev-dependencies] insta = "1.39.0" diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index fcbb8de05..bfa48ffcb 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -260,6 +260,21 @@ impl Action { ("experimental.update", Self::ExperimentalFeaturesUpdate), ]; + fn ser_action_to_action(v: &str) -> Option { + Self::SERDE_MAP_ARR + .iter() + .find(|(ser_action, _)| &v == ser_action) + .map(|(_, action)| *action) + } + + fn action_to_ser_action(v: &Action) -> &'static str { + Self::SERDE_MAP_ARR + .iter() + .find(|(_, ref action)| v == action) + .map(|(ser_action, _)| ser_action) + .expect("`action_wanted` should always have a matching serialized value") + } + pub const fn from_repr(repr: u8) -> Option { use actions::*; match repr { @@ -311,16 +326,16 @@ impl Deserr for Action { location: deserr::ValuePointerRef<'_>, ) -> Result { match value { - deserr::Value::String(s) => { - match Self::SERDE_MAP_ARR.iter().find(|(serialized, _)| s == *serialized) { - Some((_, action)) => Ok(*action), - None => Err(deserr::take_cf_content(E::error::( - None, - deserr::ErrorKind::Unexpected { msg: format!("TODO {}", s) }, - location, - ))), - } - } + deserr::Value::String(s) => match Self::ser_action_to_action(&s) { + Some(action) => Ok(action), + None => Err(deserr::take_cf_content(E::error::( + None, + deserr::ErrorKind::Unexpected { + msg: format!("string must be a valid action, got {}", s), + }, + location, + ))), + }, _ => Err(take_cf_content(E::error( None, deserr::ErrorKind::IncorrectValueKind { @@ -338,12 +353,7 @@ impl Serialize for Action { where S: Serializer, { - Self::SERDE_MAP_ARR - .iter() - .find(|(_, action)| self == action) - .map(|(serialized, _)| serializer.serialize_str(serialized)) - // should always be found, so unwrap is safe to use - .unwrap() + serializer.serialize_str(Self::action_to_ser_action(self)) } } @@ -364,9 +374,8 @@ impl<'de> Deserialize<'de> for Action { where E: serde::de::Error, { - // @TODO: Make a to_serialized and to_desiralized on Action perhaps - match Self::Value::SERDE_MAP_ARR.iter().find(|(serialized, _)| s == *serialized) { - Some((_, action)) => Ok(*action), + match Self::Value::ser_action_to_action(s) { + Some(action) => Ok(action), None => Err(E::invalid_value(serde::de::Unexpected::Str(s), &"a valid action")), } } From f95bd11db2fd75cb74fdf513aec1f1ad1f97edf4 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:46:05 +0300 Subject: [PATCH 06/21] Improve deserr error for unknown values --- meilisearch-types/src/keys.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index bfa48ffcb..ec0ec60a5 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -330,8 +330,9 @@ impl Deserr for Action { Some(action) => Ok(action), None => Err(deserr::take_cf_content(E::error::( None, - deserr::ErrorKind::Unexpected { - msg: format!("string must be a valid action, got {}", s), + deserr::ErrorKind::UnknownValue { + value: &s, + accepted: &Self::SERDE_MAP_ARR.map(|(ser_action, _)| ser_action), }, location, ))), From a80bb8f77e90ff4632170a4a979a48f973e2fcbb Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:40:17 +0300 Subject: [PATCH 07/21] Misc --- meilisearch-types/src/keys.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index ec0ec60a5..13ca0ab10 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -222,7 +222,6 @@ bitflags! { } impl Action { - // @TODO: Consider using https://github.com/rust-phf/rust-phf const SERDE_MAP_ARR: [(&'static str, Self); 34] = [ ("*", Self::All), ("search", Self::Search), @@ -272,7 +271,8 @@ impl Action { .iter() .find(|(_, ref action)| v == action) .map(|(ser_action, _)| ser_action) - .expect("`action_wanted` should always have a matching serialized value") + // actions should always have matching serialized values + .unwrap() } pub const fn from_repr(repr: u8) -> Option { @@ -399,10 +399,11 @@ impl Sequence for Action { } fn previous(&self) -> Option { - if self.bits() == 0 { + let current_index = self.bits() as usize; + if current_index == 0 { None } else { - Some(Self::SERDE_MAP_ARR[self.bits() as usize - 1].1) + Some(Self::SERDE_MAP_ARR[current_index - 1].1) } } From 3d3ae5aa0c88bd2ddcca29956487914c2a543ae3 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:01:53 +0300 Subject: [PATCH 08/21] Refactoring --- meilisearch-types/src/keys.rs | 16 ++++++++-------- milli/src/vector/mod.rs | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 13ca0ab10..140b1ab36 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -259,18 +259,18 @@ impl Action { ("experimental.update", Self::ExperimentalFeaturesUpdate), ]; - fn ser_action_to_action(v: &str) -> Option { + fn get_action(v: &str) -> Option { Self::SERDE_MAP_ARR .iter() - .find(|(ser_action, _)| &v == ser_action) + .find(|(serde_name, _)| &v == serde_name) .map(|(_, action)| *action) } - fn action_to_ser_action(v: &Action) -> &'static str { + fn get_action_serde_name(v: &Action) -> &'static str { Self::SERDE_MAP_ARR .iter() - .find(|(_, ref action)| v == action) - .map(|(ser_action, _)| ser_action) + .find(|(_, action)| v == action) + .map(|(serde_name, _)| serde_name) // actions should always have matching serialized values .unwrap() } @@ -326,7 +326,7 @@ impl Deserr for Action { location: deserr::ValuePointerRef<'_>, ) -> Result { match value { - deserr::Value::String(s) => match Self::ser_action_to_action(&s) { + deserr::Value::String(s) => match Self::get_action(&s) { Some(action) => Ok(action), None => Err(deserr::take_cf_content(E::error::( None, @@ -354,7 +354,7 @@ impl Serialize for Action { where S: Serializer, { - serializer.serialize_str(Self::action_to_ser_action(self)) + serializer.serialize_str(Self::get_action_serde_name(self)) } } @@ -375,7 +375,7 @@ impl<'de> Deserialize<'de> for Action { where E: serde::de::Error, { - match Self::Value::ser_action_to_action(s) { + match Self::Value::get_action(s) { Some(action) => Ok(action), None => Err(E::invalid_value(serde::de::Unexpected::Str(s), &"a valid action")), } diff --git a/milli/src/vector/mod.rs b/milli/src/vector/mod.rs index 349a59222..caccb404b 100644 --- a/milli/src/vector/mod.rs +++ b/milli/src/vector/mod.rs @@ -352,7 +352,7 @@ where None, deserr::ErrorKind::Unexpected { msg: format!( - "the distribution sigma must be in the range [0, 1], got {}", + "the distribution sigma must be in the range ]0, 1], got {}", value.sigma ), }, From 56b5289b2fb2abec612a6564081e175b71ad07a3 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:26:49 +0300 Subject: [PATCH 09/21] Make Actions usable as bitflags --- meilisearch-types/src/keys.rs | 181 +++++++++++++++++++--------------- 1 file changed, 101 insertions(+), 80 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 140b1ab36..896efad4a 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -183,42 +183,60 @@ fn parse_expiration_date( bitflags! { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] #[repr(transparent)] - pub struct Action: u8 { - const All = 0; + pub struct Action: u32 { const Search = 1; - const DocumentsAll = 2; - const DocumentsAdd = 3; - const DocumentsGet = 4; - const DocumentsDelete = 5; - const IndexesAll = 6; - const IndexesAdd = 7; - const IndexesGet = 8; - const IndexesUpdate = 9; - const IndexesDelete = 10; - const IndexesSwap = 11; - const TasksAll = 12; - const TasksCancel = 13; - const TasksDelete = 14; - const TasksGet = 15; - const SettingsAll = 16; - const SettingsGet = 17; - const SettingsUpdate = 18; - const StatsAll = 19; - const StatsGet = 20; - const MetricsAll = 21; - const MetricsGet = 22; - const DumpsAll = 23; - const DumpsCreate = 24; - const SnapshotsAll = 25; - const SnapshotsCreate = 26; - const Version = 27; - const KeysAdd = 28; - const KeysGet = 29; - const KeysUpdate = 30; - const KeysDelete = 31; - const ExperimentalFeaturesGet = 32; - const ExperimentalFeaturesUpdate = 33; - } + // Documents + const DocumentsAdd = 1 << 1; + const DocumentsGet = 1 << 2; + const DocumentsDelete = 1 << 3; + const DocumentsAll = Self::DocumentsAdd.repr() | Self::DocumentsGet.repr() | Self::DocumentsDelete.repr(); + // Indexes + const IndexesAdd = 1 << 4; + const IndexesGet = 1 << 5; + const IndexesUpdate = 1 << 6; + const IndexesDelete = 1 << 7; + const IndexesSwap = 1 << 8; + const IndexesAll = Self::IndexesAdd.repr() | Self::IndexesGet.repr() | Self::IndexesUpdate.repr() | Self::IndexesDelete.repr() | Self::IndexesSwap.repr(); + // Tasks + const TasksCancel = 1 << 9; + const TasksDelete = 1 << 10; + const TasksGet = 1 << 11; + const TasksAll = Self::TasksCancel.repr() | Self::TasksDelete.repr() | Self::TasksGet.repr(); + // Settings + const SettingsGet = 1 << 12; + const SettingsUpdate = 1 << 13; + const SettingsAll = Self::SettingsGet.repr() | Self::SettingsUpdate.repr(); + // Stats + const StatsGet = 1 << 14; + const StatsAll = Self::StatsGet.repr(); + // Metrics + const MetricsGet = 1 << 15; + const MetricsAll = Self::MetricsGet.repr(); + // Dumps + const DumpsCreate = 1 << 16; + const DumpsAll = Self::DumpsCreate.repr(); + // Snapshots + const SnapshotsCreate = 1 << 17; + const SnapshotsAll = Self::SnapshotsCreate.repr(); + const Version = 1 << 18; + const KeysAdd = 1 << 19; + const KeysGet = 1 << 20; + const KeysUpdate = 1 << 21; + const KeysDelete = 1 << 22; + const ExperimentalFeaturesGet = 1 << 23; + const ExperimentalFeaturesUpdate = 1 << 24; + const All = { + let mut all = 0; + + let mut exp = 0; + while exp < 24 { + all |= 1 << exp; + exp += 1; + } + + all + }; +} } impl Action { @@ -271,38 +289,40 @@ impl Action { .iter() .find(|(_, action)| v == action) .map(|(serde_name, _)| serde_name) - // actions should always have matching serialized values - .unwrap() + .expect("an action doesn't have a matching serialized value") } - pub const fn from_repr(repr: u8) -> Option { + pub const fn from_repr(repr: u32) -> Option { use actions::*; match repr { - ALL => Some(Self::All), SEARCH => Some(Self::Search), - DOCUMENTS_ALL => Some(Self::DocumentsAll), DOCUMENTS_ADD => Some(Self::DocumentsAdd), DOCUMENTS_GET => Some(Self::DocumentsGet), DOCUMENTS_DELETE => Some(Self::DocumentsDelete), - INDEXES_ALL => Some(Self::IndexesAll), + DOCUMENTS_ALL => Some(Self::DocumentsAll), INDEXES_CREATE => Some(Self::IndexesAdd), INDEXES_GET => Some(Self::IndexesGet), INDEXES_UPDATE => Some(Self::IndexesUpdate), INDEXES_DELETE => Some(Self::IndexesDelete), INDEXES_SWAP => Some(Self::IndexesSwap), - TASKS_ALL => Some(Self::TasksAll), + INDEXES_ALL => Some(Self::IndexesAll), TASKS_CANCEL => Some(Self::TasksCancel), TASKS_DELETE => Some(Self::TasksDelete), TASKS_GET => Some(Self::TasksGet), - SETTINGS_ALL => Some(Self::SettingsAll), + TASKS_ALL => Some(Self::TasksAll), SETTINGS_GET => Some(Self::SettingsGet), SETTINGS_UPDATE => Some(Self::SettingsUpdate), - STATS_ALL => Some(Self::StatsAll), + SETTINGS_ALL => Some(Self::SettingsAll), STATS_GET => Some(Self::StatsGet), - METRICS_ALL => Some(Self::MetricsAll), + // @TODO: Issue: Since stats has only one element, all is the same as the one single element + // so this will never match all, because it matches that one and only element first + STATS_ALL => Some(Self::StatsAll), METRICS_GET => Some(Self::MetricsGet), - DUMPS_ALL => Some(Self::DumpsAll), + // @TODO: Same + METRICS_ALL => Some(Self::MetricsAll), DUMPS_CREATE => Some(Self::DumpsCreate), + // @TODO: Same + DUMPS_ALL => Some(Self::DumpsAll), SNAPSHOTS_CREATE => Some(Self::SnapshotsCreate), VERSION => Some(Self::Version), KEYS_CREATE => Some(Self::KeysAdd), @@ -311,11 +331,12 @@ impl Action { KEYS_DELETE => Some(Self::KeysDelete), EXPERIMENTAL_FEATURES_GET => Some(Self::ExperimentalFeaturesGet), EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), + ALL => Some(Self::All), _otherwise => None, } } - pub const fn repr(&self) -> u8 { + pub const fn repr(&self) -> u32 { self.bits() } } @@ -419,37 +440,37 @@ impl Sequence for Action { pub mod actions { use super::Action as A; - pub(crate) const ALL: u8 = A::All.repr(); - pub const SEARCH: u8 = A::Search.repr(); - pub const DOCUMENTS_ALL: u8 = A::DocumentsAll.repr(); - pub const DOCUMENTS_ADD: u8 = A::DocumentsAdd.repr(); - pub const DOCUMENTS_GET: u8 = A::DocumentsGet.repr(); - pub const DOCUMENTS_DELETE: u8 = A::DocumentsDelete.repr(); - pub const INDEXES_ALL: u8 = A::IndexesAll.repr(); - pub const INDEXES_CREATE: u8 = A::IndexesAdd.repr(); - pub const INDEXES_GET: u8 = A::IndexesGet.repr(); - pub const INDEXES_UPDATE: u8 = A::IndexesUpdate.repr(); - pub const INDEXES_DELETE: u8 = A::IndexesDelete.repr(); - pub const INDEXES_SWAP: u8 = A::IndexesSwap.repr(); - pub const TASKS_ALL: u8 = A::TasksAll.repr(); - pub const TASKS_CANCEL: u8 = A::TasksCancel.repr(); - pub const TASKS_DELETE: u8 = A::TasksDelete.repr(); - pub const TASKS_GET: u8 = A::TasksGet.repr(); - pub const SETTINGS_ALL: u8 = A::SettingsAll.repr(); - pub const SETTINGS_GET: u8 = A::SettingsGet.repr(); - pub const SETTINGS_UPDATE: u8 = A::SettingsUpdate.repr(); - pub const STATS_ALL: u8 = A::StatsAll.repr(); - pub const STATS_GET: u8 = A::StatsGet.repr(); - pub const METRICS_ALL: u8 = A::MetricsAll.repr(); - pub const METRICS_GET: u8 = A::MetricsGet.repr(); - pub const DUMPS_ALL: u8 = A::DumpsAll.repr(); - pub const DUMPS_CREATE: u8 = A::DumpsCreate.repr(); - pub const SNAPSHOTS_CREATE: u8 = A::SnapshotsCreate.repr(); - pub const VERSION: u8 = A::Version.repr(); - pub const KEYS_CREATE: u8 = A::KeysAdd.repr(); - pub const KEYS_GET: u8 = A::KeysGet.repr(); - pub const KEYS_UPDATE: u8 = A::KeysUpdate.repr(); - pub const KEYS_DELETE: u8 = A::KeysDelete.repr(); - pub const EXPERIMENTAL_FEATURES_GET: u8 = A::ExperimentalFeaturesGet.repr(); - pub const EXPERIMENTAL_FEATURES_UPDATE: u8 = A::ExperimentalFeaturesUpdate.repr(); + pub const SEARCH: u32 = A::Search.repr(); + pub const DOCUMENTS_ADD: u32 = A::DocumentsAdd.repr(); + pub const DOCUMENTS_GET: u32 = A::DocumentsGet.repr(); + pub const DOCUMENTS_DELETE: u32 = A::DocumentsDelete.repr(); + pub const DOCUMENTS_ALL: u32 = A::DocumentsAll.repr(); + pub const INDEXES_CREATE: u32 = A::IndexesAdd.repr(); + pub const INDEXES_GET: u32 = A::IndexesGet.repr(); + pub const INDEXES_UPDATE: u32 = A::IndexesUpdate.repr(); + pub const INDEXES_DELETE: u32 = A::IndexesDelete.repr(); + pub const INDEXES_SWAP: u32 = A::IndexesSwap.repr(); + pub const INDEXES_ALL: u32 = A::IndexesAll.repr(); + pub const TASKS_CANCEL: u32 = A::TasksCancel.repr(); + pub const TASKS_DELETE: u32 = A::TasksDelete.repr(); + pub const TASKS_GET: u32 = A::TasksGet.repr(); + pub const TASKS_ALL: u32 = A::TasksAll.repr(); + pub const SETTINGS_GET: u32 = A::SettingsGet.repr(); + pub const SETTINGS_UPDATE: u32 = A::SettingsUpdate.repr(); + pub const SETTINGS_ALL: u32 = A::SettingsAll.repr(); + pub const STATS_GET: u32 = A::StatsGet.repr(); + pub const STATS_ALL: u32 = A::StatsAll.repr(); + pub const METRICS_GET: u32 = A::MetricsGet.repr(); + pub const METRICS_ALL: u32 = A::MetricsAll.repr(); + pub const DUMPS_CREATE: u32 = A::DumpsCreate.repr(); + pub const DUMPS_ALL: u32 = A::DumpsAll.repr(); + pub const SNAPSHOTS_CREATE: u32 = A::SnapshotsCreate.repr(); + pub const VERSION: u32 = A::Version.repr(); + pub const KEYS_CREATE: u32 = A::KeysAdd.repr(); + pub const KEYS_GET: u32 = A::KeysGet.repr(); + pub const KEYS_UPDATE: u32 = A::KeysUpdate.repr(); + pub const KEYS_DELETE: u32 = A::KeysDelete.repr(); + pub const EXPERIMENTAL_FEATURES_GET: u32 = A::ExperimentalFeaturesGet.repr(); + pub const EXPERIMENTAL_FEATURES_UPDATE: u32 = A::ExperimentalFeaturesUpdate.repr(); + pub(crate) const ALL: u32 = A::All.repr(); } From 0403ec0a5647bc2db7b45c80b797d8b023ca7151 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:33:35 +0300 Subject: [PATCH 10/21] Fix All flag --- meilisearch-types/src/keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 896efad4a..f645c87e6 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -229,7 +229,7 @@ bitflags! { let mut all = 0; let mut exp = 0; - while exp < 24 { + while exp <= 24 { all |= 1 << exp; exp += 1; } From e9668eff79422763bf18e95330f174e944ea0766 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sat, 5 Oct 2024 13:40:38 +0300 Subject: [PATCH 11/21] Misc --- meilisearch-types/src/keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index f645c87e6..ec3c5246c 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -230,7 +230,7 @@ bitflags! { let mut exp = 0; while exp <= 24 { - all |= 1 << exp; + all = (all << 1) + 1; exp += 1; } From 04d86a4d9eab892848be325c157752efd53c4173 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sun, 20 Oct 2024 10:18:09 +0300 Subject: [PATCH 12/21] Adapt code to new flags structure --- meilisearch-auth/src/store.rs | 22 ++++++++++++------- meilisearch-types/src/keys.rs | 8 +++---- .../src/extractors/authentication/mod.rs | 10 ++++----- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/meilisearch-auth/src/store.rs b/meilisearch-auth/src/store.rs index 20198e497..62f2f9180 100644 --- a/meilisearch-auth/src/store.rs +++ b/meilisearch-auth/src/store.rs @@ -293,18 +293,24 @@ impl HeedAuthStore { /// optionally on a specific index, for a given key. pub struct KeyIdActionCodec; +impl KeyIdActionCodec { + fn action_parts_to_repr([p1, p2, p3, p4]: &[u8; 4]) -> u32 { + ((p1 << 24) | (p2 << 16) | (p3 << 8) | p4) as u32 + } +} + impl<'a> milli::heed::BytesDecode<'a> for KeyIdActionCodec { type DItem = (KeyId, Action, Option<&'a [u8]>); fn bytes_decode(bytes: &'a [u8]) -> StdResult { let (key_id_bytes, action_bytes) = try_split_array_at(bytes).ok_or(SliceTooShortError)?; - let (&action_byte, index) = - match try_split_array_at(action_bytes).ok_or(SliceTooShortError)? { - ([action], []) => (action, None), - ([action], index) => (action, Some(index)), + let (action_repr, index) = + match try_split_array_at::(action_bytes).ok_or(SliceTooShortError)? { + (action_parts, []) => (Self::action_parts_to_repr(action_parts), None), + (action_parts, index) => (Self::action_parts_to_repr(action_parts), Some(index)), }; let key_id = Uuid::from_bytes(*key_id_bytes); - let action = Action::from_repr(action_byte).ok_or(InvalidActionError { action_byte })?; + let action = Action::from_repr(action_repr).ok_or(InvalidActionError { action_repr })?; Ok((key_id, action, index)) } @@ -317,7 +323,7 @@ impl<'a> milli::heed::BytesEncode<'a> for KeyIdActionCodec { let mut bytes = Vec::new(); bytes.extend_from_slice(key_id.as_bytes()); - let action_bytes = u8::to_be_bytes(action.repr()); + let action_bytes = u32::to_be_bytes(action.repr()); bytes.extend_from_slice(&action_bytes); if let Some(index) = index { bytes.extend_from_slice(index); @@ -332,9 +338,9 @@ impl<'a> milli::heed::BytesEncode<'a> for KeyIdActionCodec { pub struct SliceTooShortError; #[derive(Error, Debug)] -#[error("cannot construct a valid Action from {action_byte}")] +#[error("cannot construct a valid Action from {action_repr}")] pub struct InvalidActionError { - pub action_byte: u8, + pub action_repr: u32, } pub fn generate_key_as_hexa(uid: Uuid, master_key: &[u8]) -> String { diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index ec3c5246c..e93edb402 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -314,14 +314,14 @@ impl Action { SETTINGS_UPDATE => Some(Self::SettingsUpdate), SETTINGS_ALL => Some(Self::SettingsAll), STATS_GET => Some(Self::StatsGet), - // @TODO: Issue: Since stats has only one element, all is the same as the one single element + // TODO: Issue: Since stats has only one element, all is the same as the one single element // so this will never match all, because it matches that one and only element first STATS_ALL => Some(Self::StatsAll), METRICS_GET => Some(Self::MetricsGet), - // @TODO: Same + // TODO: Same METRICS_ALL => Some(Self::MetricsAll), DUMPS_CREATE => Some(Self::DumpsCreate), - // @TODO: Same + // TODO: Same DUMPS_ALL => Some(Self::DumpsAll), SNAPSHOTS_CREATE => Some(Self::SnapshotsCreate), VERSION => Some(Self::Version), @@ -332,7 +332,7 @@ impl Action { EXPERIMENTAL_FEATURES_GET => Some(Self::ExperimentalFeaturesGet), EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), ALL => Some(Self::All), - _otherwise => None, + _ => None, } } diff --git a/meilisearch/src/extractors/authentication/mod.rs b/meilisearch/src/extractors/authentication/mod.rs index 28a6d770e..6917f86d8 100644 --- a/meilisearch/src/extractors/authentication/mod.rs +++ b/meilisearch/src/extractors/authentication/mod.rs @@ -171,7 +171,7 @@ pub mod policies { #[error("Could not decode tenant token, {0}.")] CouldNotDecodeTenantToken(jsonwebtoken::errors::Error), #[error("Invalid action `{0}`.")] - InternalInvalidAction(u8), + InternalInvalidAction(u32), } impl From for AuthError { @@ -214,14 +214,14 @@ pub mod policies { Ok(api_key_uid) } - fn is_keys_action(action: u8) -> bool { + fn is_keys_action(action: u32) -> bool { use actions::*; matches!(action, KEYS_GET | KEYS_CREATE | KEYS_UPDATE | KEYS_DELETE) } - pub struct ActionPolicy; + pub struct ActionPolicy; - impl Policy for ActionPolicy { + impl Policy for ActionPolicy { /// Attempts to grant authentication from a bearer token (that can be a tenant token or an API key), the requested Action, /// and a list of requested indexes. /// @@ -294,7 +294,7 @@ pub mod policies { } } - impl ActionPolicy { + impl ActionPolicy { fn authenticate_tenant_token( auth: &AuthController, token: &str, From e4745a61a8377b7beb8d8e63e9b5facbe34468de Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sun, 20 Oct 2024 15:37:13 +0300 Subject: [PATCH 13/21] Resolve clippy error temporarily --- meilisearch-types/src/keys.rs | 84 +++++++++++++++++------------------ 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index e93edb402..035016f96 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -316,13 +316,11 @@ impl Action { STATS_GET => Some(Self::StatsGet), // TODO: Issue: Since stats has only one element, all is the same as the one single element // so this will never match all, because it matches that one and only element first - STATS_ALL => Some(Self::StatsAll), + // STATS_ALL => Some(Self::StatsAll), METRICS_GET => Some(Self::MetricsGet), - // TODO: Same - METRICS_ALL => Some(Self::MetricsAll), + // METRICS_ALL => Some(Self::MetricsAll), DUMPS_CREATE => Some(Self::DumpsCreate), - // TODO: Same - DUMPS_ALL => Some(Self::DumpsAll), + // DUMPS_ALL => Some(Self::DumpsAll), SNAPSHOTS_CREATE => Some(Self::SnapshotsCreate), VERSION => Some(Self::Version), KEYS_CREATE => Some(Self::KeysAdd), @@ -341,6 +339,44 @@ impl Action { } } +pub mod actions { + use super::Action as A; + + pub const SEARCH: u32 = A::Search.repr(); + pub const DOCUMENTS_ADD: u32 = A::DocumentsAdd.repr(); + pub const DOCUMENTS_GET: u32 = A::DocumentsGet.repr(); + pub const DOCUMENTS_DELETE: u32 = A::DocumentsDelete.repr(); + pub const DOCUMENTS_ALL: u32 = A::DocumentsAll.repr(); + pub const INDEXES_CREATE: u32 = A::IndexesAdd.repr(); + pub const INDEXES_GET: u32 = A::IndexesGet.repr(); + pub const INDEXES_UPDATE: u32 = A::IndexesUpdate.repr(); + pub const INDEXES_DELETE: u32 = A::IndexesDelete.repr(); + pub const INDEXES_SWAP: u32 = A::IndexesSwap.repr(); + pub const INDEXES_ALL: u32 = A::IndexesAll.repr(); + pub const TASKS_CANCEL: u32 = A::TasksCancel.repr(); + pub const TASKS_DELETE: u32 = A::TasksDelete.repr(); + pub const TASKS_GET: u32 = A::TasksGet.repr(); + pub const TASKS_ALL: u32 = A::TasksAll.repr(); + pub const SETTINGS_GET: u32 = A::SettingsGet.repr(); + pub const SETTINGS_UPDATE: u32 = A::SettingsUpdate.repr(); + pub const SETTINGS_ALL: u32 = A::SettingsAll.repr(); + pub const STATS_GET: u32 = A::StatsGet.repr(); + pub const STATS_ALL: u32 = A::StatsAll.repr(); + pub const METRICS_GET: u32 = A::MetricsGet.repr(); + pub const METRICS_ALL: u32 = A::MetricsAll.repr(); + pub const DUMPS_CREATE: u32 = A::DumpsCreate.repr(); + pub const DUMPS_ALL: u32 = A::DumpsAll.repr(); + pub const SNAPSHOTS_CREATE: u32 = A::SnapshotsCreate.repr(); + pub const VERSION: u32 = A::Version.repr(); + pub const KEYS_CREATE: u32 = A::KeysAdd.repr(); + pub const KEYS_GET: u32 = A::KeysGet.repr(); + pub const KEYS_UPDATE: u32 = A::KeysUpdate.repr(); + pub const KEYS_DELETE: u32 = A::KeysDelete.repr(); + pub const EXPERIMENTAL_FEATURES_GET: u32 = A::ExperimentalFeaturesGet.repr(); + pub const EXPERIMENTAL_FEATURES_UPDATE: u32 = A::ExperimentalFeaturesUpdate.repr(); + pub(crate) const ALL: u32 = A::All.repr(); +} + impl Deserr for Action { fn deserialize_from_value( value: deserr::Value, @@ -436,41 +472,3 @@ impl Sequence for Action { Some(Self::SERDE_MAP_ARR[Self::CARDINALITY - 1].1) } } - -pub mod actions { - use super::Action as A; - - pub const SEARCH: u32 = A::Search.repr(); - pub const DOCUMENTS_ADD: u32 = A::DocumentsAdd.repr(); - pub const DOCUMENTS_GET: u32 = A::DocumentsGet.repr(); - pub const DOCUMENTS_DELETE: u32 = A::DocumentsDelete.repr(); - pub const DOCUMENTS_ALL: u32 = A::DocumentsAll.repr(); - pub const INDEXES_CREATE: u32 = A::IndexesAdd.repr(); - pub const INDEXES_GET: u32 = A::IndexesGet.repr(); - pub const INDEXES_UPDATE: u32 = A::IndexesUpdate.repr(); - pub const INDEXES_DELETE: u32 = A::IndexesDelete.repr(); - pub const INDEXES_SWAP: u32 = A::IndexesSwap.repr(); - pub const INDEXES_ALL: u32 = A::IndexesAll.repr(); - pub const TASKS_CANCEL: u32 = A::TasksCancel.repr(); - pub const TASKS_DELETE: u32 = A::TasksDelete.repr(); - pub const TASKS_GET: u32 = A::TasksGet.repr(); - pub const TASKS_ALL: u32 = A::TasksAll.repr(); - pub const SETTINGS_GET: u32 = A::SettingsGet.repr(); - pub const SETTINGS_UPDATE: u32 = A::SettingsUpdate.repr(); - pub const SETTINGS_ALL: u32 = A::SettingsAll.repr(); - pub const STATS_GET: u32 = A::StatsGet.repr(); - pub const STATS_ALL: u32 = A::StatsAll.repr(); - pub const METRICS_GET: u32 = A::MetricsGet.repr(); - pub const METRICS_ALL: u32 = A::MetricsAll.repr(); - pub const DUMPS_CREATE: u32 = A::DumpsCreate.repr(); - pub const DUMPS_ALL: u32 = A::DumpsAll.repr(); - pub const SNAPSHOTS_CREATE: u32 = A::SnapshotsCreate.repr(); - pub const VERSION: u32 = A::Version.repr(); - pub const KEYS_CREATE: u32 = A::KeysAdd.repr(); - pub const KEYS_GET: u32 = A::KeysGet.repr(); - pub const KEYS_UPDATE: u32 = A::KeysUpdate.repr(); - pub const KEYS_DELETE: u32 = A::KeysDelete.repr(); - pub const EXPERIMENTAL_FEATURES_GET: u32 = A::ExperimentalFeaturesGet.repr(); - pub const EXPERIMENTAL_FEATURES_UPDATE: u32 = A::ExperimentalFeaturesUpdate.repr(); - pub(crate) const ALL: u32 = A::All.repr(); -} From 0419b93032178844549369a28f721acb61f9d77c Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Sun, 20 Oct 2024 21:46:39 +0300 Subject: [PATCH 14/21] Try fix Sequence impl, refactor, improve --- meilisearch-auth/src/store.rs | 10 +- meilisearch-types/src/keys.rs | 156 +++++++----------- .../src/extractors/authentication/mod.rs | 2 +- 3 files changed, 65 insertions(+), 103 deletions(-) diff --git a/meilisearch-auth/src/store.rs b/meilisearch-auth/src/store.rs index 62f2f9180..1bcee31e8 100644 --- a/meilisearch-auth/src/store.rs +++ b/meilisearch-auth/src/store.rs @@ -304,13 +304,13 @@ impl<'a> milli::heed::BytesDecode<'a> for KeyIdActionCodec { fn bytes_decode(bytes: &'a [u8]) -> StdResult { let (key_id_bytes, action_bytes) = try_split_array_at(bytes).ok_or(SliceTooShortError)?; - let (action_repr, index) = + let (action_bits, index) = match try_split_array_at::(action_bytes).ok_or(SliceTooShortError)? { (action_parts, []) => (Self::action_parts_to_repr(action_parts), None), (action_parts, index) => (Self::action_parts_to_repr(action_parts), Some(index)), }; let key_id = Uuid::from_bytes(*key_id_bytes); - let action = Action::from_repr(action_repr).ok_or(InvalidActionError { action_repr })?; + let action = Action::from_bits(action_bits).ok_or(InvalidActionError { action_bits })?; Ok((key_id, action, index)) } @@ -323,7 +323,7 @@ impl<'a> milli::heed::BytesEncode<'a> for KeyIdActionCodec { let mut bytes = Vec::new(); bytes.extend_from_slice(key_id.as_bytes()); - let action_bytes = u32::to_be_bytes(action.repr()); + let action_bytes = u32::to_be_bytes(action.bits()); bytes.extend_from_slice(&action_bytes); if let Some(index) = index { bytes.extend_from_slice(index); @@ -338,9 +338,9 @@ impl<'a> milli::heed::BytesEncode<'a> for KeyIdActionCodec { pub struct SliceTooShortError; #[derive(Error, Debug)] -#[error("cannot construct a valid Action from {action_repr}")] +#[error("cannot construct a valid Action from {action_bits}")] pub struct InvalidActionError { - pub action_repr: u32, + pub action_bits: u32, } pub fn generate_key_as_hexa(uid: Uuid, master_key: &[u8]) -> String { diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 035016f96..0af4be1c1 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -189,35 +189,35 @@ bitflags! { const DocumentsAdd = 1 << 1; const DocumentsGet = 1 << 2; const DocumentsDelete = 1 << 3; - const DocumentsAll = Self::DocumentsAdd.repr() | Self::DocumentsGet.repr() | Self::DocumentsDelete.repr(); + const DocumentsAll = Self::DocumentsAdd.bits() | Self::DocumentsGet.bits() | Self::DocumentsDelete.bits(); // Indexes const IndexesAdd = 1 << 4; const IndexesGet = 1 << 5; const IndexesUpdate = 1 << 6; const IndexesDelete = 1 << 7; const IndexesSwap = 1 << 8; - const IndexesAll = Self::IndexesAdd.repr() | Self::IndexesGet.repr() | Self::IndexesUpdate.repr() | Self::IndexesDelete.repr() | Self::IndexesSwap.repr(); + const IndexesAll = Self::IndexesAdd.bits() | Self::IndexesGet.bits() | Self::IndexesUpdate.bits() | Self::IndexesDelete.bits() | Self::IndexesSwap.bits(); // Tasks const TasksCancel = 1 << 9; const TasksDelete = 1 << 10; const TasksGet = 1 << 11; - const TasksAll = Self::TasksCancel.repr() | Self::TasksDelete.repr() | Self::TasksGet.repr(); + const TasksAll = Self::TasksCancel.bits() | Self::TasksDelete.bits() | Self::TasksGet.bits(); // Settings const SettingsGet = 1 << 12; const SettingsUpdate = 1 << 13; - const SettingsAll = Self::SettingsGet.repr() | Self::SettingsUpdate.repr(); + const SettingsAll = Self::SettingsGet.bits() | Self::SettingsUpdate.bits(); // Stats const StatsGet = 1 << 14; - const StatsAll = Self::StatsGet.repr(); + const StatsAll = Self::StatsGet.bits(); // Metrics const MetricsGet = 1 << 15; - const MetricsAll = Self::MetricsGet.repr(); + const MetricsAll = Self::MetricsGet.bits(); // Dumps const DumpsCreate = 1 << 16; - const DumpsAll = Self::DumpsCreate.repr(); + const DumpsAll = Self::DumpsCreate.bits(); // Snapshots const SnapshotsCreate = 1 << 17; - const SnapshotsAll = Self::SnapshotsCreate.repr(); + const SnapshotsAll = Self::SnapshotsCreate.bits(); const Version = 1 << 18; const KeysAdd = 1 << 19; const KeysGet = 1 << 20; @@ -241,33 +241,32 @@ bitflags! { impl Action { const SERDE_MAP_ARR: [(&'static str, Self); 34] = [ - ("*", Self::All), ("search", Self::Search), - ("documents.*", Self::DocumentsAll), ("documents.add", Self::DocumentsAdd), ("documents.get", Self::DocumentsGet), ("documents.delete", Self::DocumentsDelete), - ("indexes.*", Self::IndexesAll), + ("documents.*", Self::DocumentsAll), ("indexes.create", Self::IndexesAdd), ("indexes.get", Self::IndexesGet), ("indexes.update", Self::IndexesUpdate), ("indexes.delete", Self::IndexesDelete), ("indexes.swap", Self::IndexesSwap), - ("tasks.*", Self::TasksAll), + ("indexes.*", Self::IndexesAll), ("tasks.cancel", Self::TasksCancel), ("tasks.delete", Self::TasksDelete), ("tasks.get", Self::TasksGet), - ("settings.*", Self::SettingsAll), + ("tasks.*", Self::TasksAll), ("settings.get", Self::SettingsGet), ("settings.update", Self::SettingsUpdate), - ("stats.*", Self::StatsAll), + ("settings.*", Self::SettingsAll), ("stats.get", Self::StatsGet), - ("metrics.*", Self::MetricsAll), + ("stats.*", Self::StatsAll), ("metrics.get", Self::MetricsGet), - ("dumps.*", Self::DumpsAll), + ("metrics.*", Self::MetricsAll), ("dumps.create", Self::DumpsCreate), - ("snapshots.*", Self::SnapshotsAll), + ("dumps.*", Self::DumpsAll), ("snapshots.create", Self::SnapshotsCreate), + ("snapshots.*", Self::SnapshotsAll), ("version", Self::Version), ("keys.create", Self::KeysAdd), ("keys.get", Self::KeysGet), @@ -275,6 +274,7 @@ impl Action { ("keys.delete", Self::KeysDelete), ("experimental.get", Self::ExperimentalFeaturesGet), ("experimental.update", Self::ExperimentalFeaturesUpdate), + ("*", Self::All), ]; fn get_action(v: &str) -> Option { @@ -289,92 +289,54 @@ impl Action { .iter() .find(|(_, action)| v == action) .map(|(serde_name, _)| serde_name) - .expect("an action doesn't have a matching serialized value") + .expect("an action is missing a matching serialized value") } - pub const fn from_repr(repr: u32) -> Option { - use actions::*; - match repr { - SEARCH => Some(Self::Search), - DOCUMENTS_ADD => Some(Self::DocumentsAdd), - DOCUMENTS_GET => Some(Self::DocumentsGet), - DOCUMENTS_DELETE => Some(Self::DocumentsDelete), - DOCUMENTS_ALL => Some(Self::DocumentsAll), - INDEXES_CREATE => Some(Self::IndexesAdd), - INDEXES_GET => Some(Self::IndexesGet), - INDEXES_UPDATE => Some(Self::IndexesUpdate), - INDEXES_DELETE => Some(Self::IndexesDelete), - INDEXES_SWAP => Some(Self::IndexesSwap), - INDEXES_ALL => Some(Self::IndexesAll), - TASKS_CANCEL => Some(Self::TasksCancel), - TASKS_DELETE => Some(Self::TasksDelete), - TASKS_GET => Some(Self::TasksGet), - TASKS_ALL => Some(Self::TasksAll), - SETTINGS_GET => Some(Self::SettingsGet), - SETTINGS_UPDATE => Some(Self::SettingsUpdate), - SETTINGS_ALL => Some(Self::SettingsAll), - STATS_GET => Some(Self::StatsGet), - // TODO: Issue: Since stats has only one element, all is the same as the one single element - // so this will never match all, because it matches that one and only element first - // STATS_ALL => Some(Self::StatsAll), - METRICS_GET => Some(Self::MetricsGet), - // METRICS_ALL => Some(Self::MetricsAll), - DUMPS_CREATE => Some(Self::DumpsCreate), - // DUMPS_ALL => Some(Self::DumpsAll), - SNAPSHOTS_CREATE => Some(Self::SnapshotsCreate), - VERSION => Some(Self::Version), - KEYS_CREATE => Some(Self::KeysAdd), - KEYS_GET => Some(Self::KeysGet), - KEYS_UPDATE => Some(Self::KeysUpdate), - KEYS_DELETE => Some(Self::KeysDelete), - EXPERIMENTAL_FEATURES_GET => Some(Self::ExperimentalFeaturesGet), - EXPERIMENTAL_FEATURES_UPDATE => Some(Self::ExperimentalFeaturesUpdate), - ALL => Some(Self::All), - _ => None, - } - } - - pub const fn repr(&self) -> u32 { - self.bits() + fn get_index(&self) -> usize { + Self::SERDE_MAP_ARR + .iter() + .enumerate() + .find(|(_, (_, action))| action == self) + .map(|(i, _)| i) + .unwrap() } } pub mod actions { use super::Action as A; - pub const SEARCH: u32 = A::Search.repr(); - pub const DOCUMENTS_ADD: u32 = A::DocumentsAdd.repr(); - pub const DOCUMENTS_GET: u32 = A::DocumentsGet.repr(); - pub const DOCUMENTS_DELETE: u32 = A::DocumentsDelete.repr(); - pub const DOCUMENTS_ALL: u32 = A::DocumentsAll.repr(); - pub const INDEXES_CREATE: u32 = A::IndexesAdd.repr(); - pub const INDEXES_GET: u32 = A::IndexesGet.repr(); - pub const INDEXES_UPDATE: u32 = A::IndexesUpdate.repr(); - pub const INDEXES_DELETE: u32 = A::IndexesDelete.repr(); - pub const INDEXES_SWAP: u32 = A::IndexesSwap.repr(); - pub const INDEXES_ALL: u32 = A::IndexesAll.repr(); - pub const TASKS_CANCEL: u32 = A::TasksCancel.repr(); - pub const TASKS_DELETE: u32 = A::TasksDelete.repr(); - pub const TASKS_GET: u32 = A::TasksGet.repr(); - pub const TASKS_ALL: u32 = A::TasksAll.repr(); - pub const SETTINGS_GET: u32 = A::SettingsGet.repr(); - pub const SETTINGS_UPDATE: u32 = A::SettingsUpdate.repr(); - pub const SETTINGS_ALL: u32 = A::SettingsAll.repr(); - pub const STATS_GET: u32 = A::StatsGet.repr(); - pub const STATS_ALL: u32 = A::StatsAll.repr(); - pub const METRICS_GET: u32 = A::MetricsGet.repr(); - pub const METRICS_ALL: u32 = A::MetricsAll.repr(); - pub const DUMPS_CREATE: u32 = A::DumpsCreate.repr(); - pub const DUMPS_ALL: u32 = A::DumpsAll.repr(); - pub const SNAPSHOTS_CREATE: u32 = A::SnapshotsCreate.repr(); - pub const VERSION: u32 = A::Version.repr(); - pub const KEYS_CREATE: u32 = A::KeysAdd.repr(); - pub const KEYS_GET: u32 = A::KeysGet.repr(); - pub const KEYS_UPDATE: u32 = A::KeysUpdate.repr(); - pub const KEYS_DELETE: u32 = A::KeysDelete.repr(); - pub const EXPERIMENTAL_FEATURES_GET: u32 = A::ExperimentalFeaturesGet.repr(); - pub const EXPERIMENTAL_FEATURES_UPDATE: u32 = A::ExperimentalFeaturesUpdate.repr(); - pub(crate) const ALL: u32 = A::All.repr(); + pub const SEARCH: u32 = A::Search.bits(); + pub const DOCUMENTS_ADD: u32 = A::DocumentsAdd.bits(); + pub const DOCUMENTS_GET: u32 = A::DocumentsGet.bits(); + pub const DOCUMENTS_DELETE: u32 = A::DocumentsDelete.bits(); + pub const DOCUMENTS_ALL: u32 = A::DocumentsAll.bits(); + pub const INDEXES_CREATE: u32 = A::IndexesAdd.bits(); + pub const INDEXES_GET: u32 = A::IndexesGet.bits(); + pub const INDEXES_UPDATE: u32 = A::IndexesUpdate.bits(); + pub const INDEXES_DELETE: u32 = A::IndexesDelete.bits(); + pub const INDEXES_SWAP: u32 = A::IndexesSwap.bits(); + pub const INDEXES_ALL: u32 = A::IndexesAll.bits(); + pub const TASKS_CANCEL: u32 = A::TasksCancel.bits(); + pub const TASKS_DELETE: u32 = A::TasksDelete.bits(); + pub const TASKS_GET: u32 = A::TasksGet.bits(); + pub const TASKS_ALL: u32 = A::TasksAll.bits(); + pub const SETTINGS_GET: u32 = A::SettingsGet.bits(); + pub const SETTINGS_UPDATE: u32 = A::SettingsUpdate.bits(); + pub const SETTINGS_ALL: u32 = A::SettingsAll.bits(); + pub const STATS_GET: u32 = A::StatsGet.bits(); + pub const STATS_ALL: u32 = A::StatsAll.bits(); + pub const METRICS_GET: u32 = A::MetricsGet.bits(); + pub const METRICS_ALL: u32 = A::MetricsAll.bits(); + pub const DUMPS_CREATE: u32 = A::DumpsCreate.bits(); + pub const DUMPS_ALL: u32 = A::DumpsAll.bits(); + pub const SNAPSHOTS_CREATE: u32 = A::SnapshotsCreate.bits(); + pub const VERSION: u32 = A::Version.bits(); + pub const KEYS_CREATE: u32 = A::KeysAdd.bits(); + pub const KEYS_GET: u32 = A::KeysGet.bits(); + pub const KEYS_UPDATE: u32 = A::KeysUpdate.bits(); + pub const KEYS_DELETE: u32 = A::KeysDelete.bits(); + pub const EXPERIMENTAL_FEATURES_GET: u32 = A::ExperimentalFeaturesGet.bits(); + pub const EXPERIMENTAL_FEATURES_UPDATE: u32 = A::ExperimentalFeaturesUpdate.bits(); } impl Deserr for Action { @@ -447,7 +409,7 @@ impl Sequence for Action { const CARDINALITY: usize = Self::SERDE_MAP_ARR.len(); fn next(&self) -> Option { - let next_index = self.bits() as usize + 1; + let next_index = self.get_index() + 1; if next_index == Self::CARDINALITY { None } else { @@ -456,7 +418,7 @@ impl Sequence for Action { } fn previous(&self) -> Option { - let current_index = self.bits() as usize; + let current_index = self.get_index(); if current_index == 0 { None } else { diff --git a/meilisearch/src/extractors/authentication/mod.rs b/meilisearch/src/extractors/authentication/mod.rs index 6917f86d8..e10ad2bd1 100644 --- a/meilisearch/src/extractors/authentication/mod.rs +++ b/meilisearch/src/extractors/authentication/mod.rs @@ -255,7 +255,7 @@ pub mod policies { }; // check that the indexes are allowed - let action = Action::from_repr(A).ok_or(AuthError::InternalInvalidAction(A))?; + let action = Action::from_bits(A).ok_or(AuthError::InternalInvalidAction(A))?; let auth_filter = auth .get_key_filters(key_uuid, search_rules) .map_err(|_e| AuthError::InvalidApiKey)?; From 544961372c7b8b0c6bc60b8686ff237e3f8587f3 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Mon, 21 Oct 2024 00:19:33 +0300 Subject: [PATCH 15/21] Attempt pushing bad code in order to stop stuck GitHub action --- meilisearch-types/src/keys.rs | 58 ++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 0af4be1c1..a6343999f 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -2,7 +2,7 @@ use std::convert::Infallible; use std::hash::Hash; use std::str::FromStr; -use bitflags::bitflags; +use bitflags::{bitflags, Flags}; use deserr::{take_cf_content, DeserializeError, Deserr, MergeWithError, ValuePointerRef}; use enum_iterator::Sequence; use milli::update::Setting; @@ -291,15 +291,6 @@ impl Action { .map(|(serde_name, _)| serde_name) .expect("an action is missing a matching serialized value") } - - fn get_index(&self) -> usize { - Self::SERDE_MAP_ARR - .iter() - .enumerate() - .find(|(_, (_, action))| action == self) - .map(|(i, _)| i) - .unwrap() - } } pub mod actions { @@ -409,28 +400,51 @@ impl Sequence for Action { const CARDINALITY: usize = Self::SERDE_MAP_ARR.len(); fn next(&self) -> Option { - let next_index = self.get_index() + 1; - if next_index == Self::CARDINALITY { - None - } else { - Some(Self::SERDE_MAP_ARR[next_index].1) + let mut iter = Self::FLAGS.iter(); + while let Some(action) = iter.next() { + if action.value() == self { + if let Some(action) = iter.next() { + return Some(*action.value()); + } + + break; + } } + + Non } fn previous(&self) -> Option { - let current_index = self.get_index(); - if current_index == 0 { - None - } else { - Some(Self::SERDE_MAP_ARR[current_index - 1].1) + let mut iter = Self::FLAGS.iter().peekable(); + + if let Some(action) = iter.next() { + if action.value() == self { + return None; + } + + if let Some(next_action) = iter.peek() { + if next_action.value() == self { + return Some(*action.value()); + } + } } + + while let Some(action) = iter.next() { + if let Some(next_action) = iter.peek() { + if next_action.value() == self { + return Some(*action.value()); + } + } + } + + None } fn first() -> Option { - Some(Self::SERDE_MAP_ARR[0].1) + Self::FLAGS.first().map(|v| *v.value()) } fn last() -> Option { - Some(Self::SERDE_MAP_ARR[Self::CARDINALITY - 1].1) + Self::FLAGS.last().map(|v| *v.value()) } } From b89fd49d632098297c81a2171e4c6ceb3e741ef0 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:12:47 +0300 Subject: [PATCH 16/21] Fix some 'all' flags making problems --- dump/src/reader/compat/v5_to_v6.rs | 6 +++--- meilisearch-auth/src/store.rs | 20 ++++---------------- meilisearch-types/src/keys.rs | 19 ++----------------- 3 files changed, 9 insertions(+), 36 deletions(-) diff --git a/dump/src/reader/compat/v5_to_v6.rs b/dump/src/reader/compat/v5_to_v6.rs index 40a055465..2f6f52937 100644 --- a/dump/src/reader/compat/v5_to_v6.rs +++ b/dump/src/reader/compat/v5_to_v6.rs @@ -405,11 +405,11 @@ impl From for v6::Action { v5::Action::SettingsAll => v6::Action::SettingsAll, v5::Action::SettingsGet => v6::Action::SettingsGet, v5::Action::SettingsUpdate => v6::Action::SettingsUpdate, - v5::Action::StatsAll => v6::Action::StatsAll, + v5::Action::StatsAll => v6::Action::StatsGet, v5::Action::StatsGet => v6::Action::StatsGet, - v5::Action::MetricsAll => v6::Action::MetricsAll, + v5::Action::MetricsAll => v6::Action::MetricsGet, v5::Action::MetricsGet => v6::Action::MetricsGet, - v5::Action::DumpsAll => v6::Action::DumpsAll, + v5::Action::DumpsAll => v6::Action::DumpsCreate, v5::Action::DumpsCreate => v6::Action::DumpsCreate, v5::Action::Version => v6::Action::Version, v5::Action::KeysAdd => v6::Action::KeysAdd, diff --git a/meilisearch-auth/src/store.rs b/meilisearch-auth/src/store.rs index 1bcee31e8..62aa445fa 100644 --- a/meilisearch-auth/src/store.rs +++ b/meilisearch-auth/src/store.rs @@ -128,21 +128,9 @@ impl HeedAuthStore { Action::SettingsAll => { actions.extend([Action::SettingsGet, Action::SettingsUpdate].iter()); } - Action::DumpsAll => { - actions.insert(Action::DumpsCreate); - } - Action::SnapshotsAll => { - actions.insert(Action::SnapshotsCreate); - } Action::TasksAll => { actions.extend([Action::TasksGet, Action::TasksDelete, Action::TasksCancel]); } - Action::StatsAll => { - actions.insert(Action::StatsGet); - } - Action::MetricsAll => { - actions.insert(Action::MetricsGet); - } other => { actions.insert(other); } @@ -294,8 +282,8 @@ impl HeedAuthStore { pub struct KeyIdActionCodec; impl KeyIdActionCodec { - fn action_parts_to_repr([p1, p2, p3, p4]: &[u8; 4]) -> u32 { - ((p1 << 24) | (p2 << 16) | (p3 << 8) | p4) as u32 + fn action_parts_to_32bits([p1, p2, p3, p4]: &[u8; 4]) -> u32 { + ((*p1 as u32) << 24) | ((*p2 as u32) << 16) | ((*p3 as u32) << 8) | (*p4 as u32) } } @@ -306,8 +294,8 @@ impl<'a> milli::heed::BytesDecode<'a> for KeyIdActionCodec { let (key_id_bytes, action_bytes) = try_split_array_at(bytes).ok_or(SliceTooShortError)?; let (action_bits, index) = match try_split_array_at::(action_bytes).ok_or(SliceTooShortError)? { - (action_parts, []) => (Self::action_parts_to_repr(action_parts), None), - (action_parts, index) => (Self::action_parts_to_repr(action_parts), Some(index)), + (action_parts, []) => (Self::action_parts_to_32bits(action_parts), None), + (action_parts, index) => (Self::action_parts_to_32bits(action_parts), Some(index)), }; let key_id = Uuid::from_bytes(*key_id_bytes); let action = Action::from_bits(action_bits).ok_or(InvalidActionError { action_bits })?; diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index a6343999f..b33a6f26a 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -206,18 +206,10 @@ bitflags! { const SettingsGet = 1 << 12; const SettingsUpdate = 1 << 13; const SettingsAll = Self::SettingsGet.bits() | Self::SettingsUpdate.bits(); - // Stats const StatsGet = 1 << 14; - const StatsAll = Self::StatsGet.bits(); - // Metrics const MetricsGet = 1 << 15; - const MetricsAll = Self::MetricsGet.bits(); - // Dumps const DumpsCreate = 1 << 16; - const DumpsAll = Self::DumpsCreate.bits(); - // Snapshots const SnapshotsCreate = 1 << 17; - const SnapshotsAll = Self::SnapshotsCreate.bits(); const Version = 1 << 18; const KeysAdd = 1 << 19; const KeysGet = 1 << 20; @@ -240,7 +232,7 @@ bitflags! { } impl Action { - const SERDE_MAP_ARR: [(&'static str, Self); 34] = [ + const SERDE_MAP_ARR: [(&'static str, Self); 30] = [ ("search", Self::Search), ("documents.add", Self::DocumentsAdd), ("documents.get", Self::DocumentsGet), @@ -260,13 +252,9 @@ impl Action { ("settings.update", Self::SettingsUpdate), ("settings.*", Self::SettingsAll), ("stats.get", Self::StatsGet), - ("stats.*", Self::StatsAll), ("metrics.get", Self::MetricsGet), - ("metrics.*", Self::MetricsAll), ("dumps.create", Self::DumpsCreate), - ("dumps.*", Self::DumpsAll), ("snapshots.create", Self::SnapshotsCreate), - ("snapshots.*", Self::SnapshotsAll), ("version", Self::Version), ("keys.create", Self::KeysAdd), ("keys.get", Self::KeysGet), @@ -315,11 +303,8 @@ pub mod actions { pub const SETTINGS_UPDATE: u32 = A::SettingsUpdate.bits(); pub const SETTINGS_ALL: u32 = A::SettingsAll.bits(); pub const STATS_GET: u32 = A::StatsGet.bits(); - pub const STATS_ALL: u32 = A::StatsAll.bits(); pub const METRICS_GET: u32 = A::MetricsGet.bits(); - pub const METRICS_ALL: u32 = A::MetricsAll.bits(); pub const DUMPS_CREATE: u32 = A::DumpsCreate.bits(); - pub const DUMPS_ALL: u32 = A::DumpsAll.bits(); pub const SNAPSHOTS_CREATE: u32 = A::SnapshotsCreate.bits(); pub const VERSION: u32 = A::Version.bits(); pub const KEYS_CREATE: u32 = A::KeysAdd.bits(); @@ -411,7 +396,7 @@ impl Sequence for Action { } } - Non + None } fn previous(&self) -> Option { From ba045a0000205dd26c17b467af337f1b66ab8b1e Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:43:58 +0300 Subject: [PATCH 17/21] Adapt tests --- meilisearch-types/src/keys.rs | 2 +- meilisearch/tests/auth/api_keys.rs | 2 +- meilisearch/tests/auth/authorization.rs | 14 +++++++------- meilisearch/tests/auth/errors.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index b33a6f26a..58754d12d 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -382,7 +382,7 @@ impl<'de> Deserialize<'de> for Action { } impl Sequence for Action { - const CARDINALITY: usize = Self::SERDE_MAP_ARR.len(); + const CARDINALITY: usize = Self::FLAGS.len(); fn next(&self) -> Option { let mut iter = Self::FLAGS.iter(); diff --git a/meilisearch/tests/auth/api_keys.rs b/meilisearch/tests/auth/api_keys.rs index 253929428..8d272f29d 100644 --- a/meilisearch/tests/auth/api_keys.rs +++ b/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`", + "message": "Unknown value `doc.add` at `.actions[0]`: expected one of `search`, `documents.add`, `documents.get`, `documents.delete`, `documents.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `indexes.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `tasks.*`, `settings.get`, `settings.update`, `settings.*`, `stats.get`, `metrics.get`, `dumps.create`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `*`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" diff --git a/meilisearch/tests/auth/authorization.rs b/meilisearch/tests/auth/authorization.rs index 609b7d01b..cb2510663 100644 --- a/meilisearch/tests/auth/authorization.rs +++ b/meilisearch/tests/auth/authorization.rs @@ -53,14 +53,14 @@ pub static AUTHORIZATIONS: Lazy hashset!{"settings.update", "settings.*", "*"}, ("PUT", "/indexes/products/settings/stop-words") => hashset!{"settings.update", "settings.*", "*"}, ("PUT", "/indexes/products/settings/synonyms") => hashset!{"settings.update", "settings.*", "*"}, - ("GET", "/indexes/products/stats") => hashset!{"stats.get", "stats.*", "*"}, - ("GET", "/stats") => hashset!{"stats.get", "stats.*", "*"}, - ("POST", "/dumps") => hashset!{"dumps.create", "dumps.*", "*"}, - ("POST", "/snapshots") => hashset!{"snapshots.create", "snapshots.*", "*"}, + ("GET", "/indexes/products/stats") => hashset!{"stats.get", "*"}, + ("GET", "/stats") => hashset!{"stats.get", "*"}, + ("POST", "/dumps") => hashset!{"dumps.create", "*"}, + ("POST", "/snapshots") => hashset!{"snapshots.create", "*"}, ("GET", "/version") => hashset!{"version", "*"}, - ("GET", "/metrics") => hashset!{"metrics.get", "metrics.*", "*"}, - ("POST", "/logs/stream") => hashset!{"metrics.get", "metrics.*", "*"}, - ("DELETE", "/logs/stream") => hashset!{"metrics.get", "metrics.*", "*"}, + ("GET", "/metrics") => hashset!{"metrics.get", "*"}, + ("POST", "/logs/stream") => hashset!{"metrics.get", "*"}, + ("DELETE", "/logs/stream") => hashset!{"metrics.get", "*"}, ("PATCH", "/keys/mykey/") => hashset!{"keys.update", "*"}, ("GET", "/keys/mykey/") => hashset!{"keys.get", "*"}, ("DELETE", "/keys/mykey/") => hashset!{"keys.delete", "*"}, diff --git a/meilisearch/tests/auth/errors.rs b/meilisearch/tests/auth/errors.rs index c063b2aac..1d41f286c 100644 --- a/meilisearch/tests/auth/errors.rs +++ b/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`", + "message": "Unknown value `doggo` at `.actions[0]`: expected one of `search`, `documents.add`, `documents.get`, `documents.delete`, `documents.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `indexes.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `tasks.*`, `settings.get`, `settings.update`, `settings.*`, `stats.get`, `metrics.get`, `dumps.create`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `*`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" From 146c87bd6fb7aa5559e2cf12b2a801336851eb8b Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 13 Nov 2024 10:59:42 +0200 Subject: [PATCH 18/21] Make Sequence impl work without changing dumps --- crates/dump/src/reader/compat/v5_to_v6.rs | 6 +- crates/meilisearch-types/src/keys.rs | 169 ++++++++++++---------- 2 files changed, 99 insertions(+), 76 deletions(-) diff --git a/crates/dump/src/reader/compat/v5_to_v6.rs b/crates/dump/src/reader/compat/v5_to_v6.rs index 2f6f52937..40a055465 100644 --- a/crates/dump/src/reader/compat/v5_to_v6.rs +++ b/crates/dump/src/reader/compat/v5_to_v6.rs @@ -405,11 +405,11 @@ impl From for v6::Action { v5::Action::SettingsAll => v6::Action::SettingsAll, v5::Action::SettingsGet => v6::Action::SettingsGet, v5::Action::SettingsUpdate => v6::Action::SettingsUpdate, - v5::Action::StatsAll => v6::Action::StatsGet, + v5::Action::StatsAll => v6::Action::StatsAll, v5::Action::StatsGet => v6::Action::StatsGet, - v5::Action::MetricsAll => v6::Action::MetricsGet, + v5::Action::MetricsAll => v6::Action::MetricsAll, v5::Action::MetricsGet => v6::Action::MetricsGet, - v5::Action::DumpsAll => v6::Action::DumpsCreate, + v5::Action::DumpsAll => v6::Action::DumpsAll, v5::Action::DumpsCreate => v6::Action::DumpsCreate, v5::Action::Version => v6::Action::Version, v5::Action::KeysAdd => v6::Action::KeysAdd, diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 58754d12d..76b675bb7 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -183,56 +183,57 @@ fn parse_expiration_date( bitflags! { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] #[repr(transparent)] + // NOTE: For `Sequence` impl to work, the values of these must be in ascending order pub struct Action: u32 { - const Search = 1; - // Documents - const DocumentsAdd = 1 << 1; - const DocumentsGet = 1 << 2; - const DocumentsDelete = 1 << 3; - const DocumentsAll = Self::DocumentsAdd.bits() | Self::DocumentsGet.bits() | Self::DocumentsDelete.bits(); - // Indexes - const IndexesAdd = 1 << 4; - const IndexesGet = 1 << 5; - const IndexesUpdate = 1 << 6; - const IndexesDelete = 1 << 7; - const IndexesSwap = 1 << 8; - const IndexesAll = Self::IndexesAdd.bits() | Self::IndexesGet.bits() | Self::IndexesUpdate.bits() | Self::IndexesDelete.bits() | Self::IndexesSwap.bits(); - // Tasks - const TasksCancel = 1 << 9; - const TasksDelete = 1 << 10; - const TasksGet = 1 << 11; - const TasksAll = Self::TasksCancel.bits() | Self::TasksDelete.bits() | Self::TasksGet.bits(); - // Settings - const SettingsGet = 1 << 12; - const SettingsUpdate = 1 << 13; - const SettingsAll = Self::SettingsGet.bits() | Self::SettingsUpdate.bits(); - const StatsGet = 1 << 14; - const MetricsGet = 1 << 15; - const DumpsCreate = 1 << 16; - const SnapshotsCreate = 1 << 17; - const Version = 1 << 18; - const KeysAdd = 1 << 19; - const KeysGet = 1 << 20; - const KeysUpdate = 1 << 21; - const KeysDelete = 1 << 22; - const ExperimentalFeaturesGet = 1 << 23; - const ExperimentalFeaturesUpdate = 1 << 24; - const All = { - let mut all = 0; - - let mut exp = 0; - while exp <= 24 { - all = (all << 1) + 1; - exp += 1; - } - - all - }; -} + const Search = 1; + // Documents + const DocumentsAdd = 1 << 1; + const DocumentsGet = 1 << 2; + const DocumentsDelete = 1 << 3; + const DocumentsAll = Self::DocumentsAdd.bits() | Self::DocumentsGet.bits() | Self::DocumentsDelete.bits(); + // Indexes + const IndexesAdd = 1 << 4; + const IndexesGet = 1 << 5; + const IndexesUpdate = 1 << 6; + const IndexesDelete = 1 << 7; + const IndexesSwap = 1 << 8; + const IndexesAll = Self::IndexesAdd.bits() | Self::IndexesGet.bits() | Self::IndexesUpdate.bits() | Self::IndexesDelete.bits() | Self::IndexesSwap.bits(); + // Tasks + const TasksCancel = 1 << 9; + const TasksDelete = 1 << 10; + const TasksGet = 1 << 11; + const TasksAll = Self::TasksCancel.bits() | Self::TasksDelete.bits() | Self::TasksGet.bits(); + // Settings + const SettingsGet = 1 << 12; + const SettingsUpdate = 1 << 13; + const SettingsAll = Self::SettingsGet.bits() | Self::SettingsUpdate.bits(); + // Stats + const StatsGet = 1 << 14; + const StatsAll = Self::StatsGet.bits(); + // Metrics + const MetricsGet = 1 << 15; + const MetricsAll = Self::MetricsGet.bits(); + // Dumps + const DumpsCreate = 1 << 16; + const DumpsAll = Self::DumpsCreate.bits(); + // Snapshots + const SnapshotsCreate = 1 << 17; + const SnapshotsAll = Self::SnapshotsCreate.bits(); + // Keys without an "all" version + const Version = 1 << 18; + const KeysAdd = 1 << 19; + const KeysGet = 1 << 20; + const KeysUpdate = 1 << 21; + const KeysDelete = 1 << 22; + const ExperimentalFeaturesGet = 1 << 23; + const ExperimentalFeaturesUpdate = 1 << 24; + // All + const All = 0xFFFFFFFF >> (32 - 1 - 24); + } } impl Action { - const SERDE_MAP_ARR: [(&'static str, Self); 30] = [ + const SERDE_MAP_ARR: [(&'static str, Self); 34] = [ ("search", Self::Search), ("documents.add", Self::DocumentsAdd), ("documents.get", Self::DocumentsGet), @@ -252,9 +253,13 @@ impl Action { ("settings.update", Self::SettingsUpdate), ("settings.*", Self::SettingsAll), ("stats.get", Self::StatsGet), + ("stats.*", Self::StatsAll), ("metrics.get", Self::MetricsGet), + ("metrics.*", Self::MetricsAll), ("dumps.create", Self::DumpsCreate), + ("dumps.*", Self::DumpsAll), ("snapshots.create", Self::SnapshotsCreate), + ("snapshots.*", Self::SnapshotsAll), ("version", Self::Version), ("keys.create", Self::KeysAdd), ("keys.get", Self::KeysGet), @@ -279,6 +284,19 @@ impl Action { .map(|(serde_name, _)| serde_name) .expect("an action is missing a matching serialized value") } + + // when we remove "all" flags, this will give us the exact index + fn get_potential_index(&self) -> usize { + if self.is_empty() { + return 0; + } + + // most significant bit for u32 + let msb = 1u32 << (31 - self.bits().leading_zeros()); + + // index of the single set bit + msb.trailing_zeros() as usize + } } pub mod actions { @@ -303,9 +321,13 @@ pub mod actions { pub const SETTINGS_UPDATE: u32 = A::SettingsUpdate.bits(); pub const SETTINGS_ALL: u32 = A::SettingsAll.bits(); pub const STATS_GET: u32 = A::StatsGet.bits(); + pub const STATS_ALL: u32 = A::StatsAll.bits(); pub const METRICS_GET: u32 = A::MetricsGet.bits(); + pub const METRICS_ALL: u32 = A::MetricsAll.bits(); pub const DUMPS_CREATE: u32 = A::DumpsCreate.bits(); + pub const DUMPS_ALL: u32 = A::DumpsAll.bits(); pub const SNAPSHOTS_CREATE: u32 = A::SnapshotsCreate.bits(); + pub const SNAPSHOTS_ALL: u32 = A::SnapshotsAll.bits(); pub const VERSION: u32 = A::Version.bits(); pub const KEYS_CREATE: u32 = A::KeysAdd.bits(); pub const KEYS_GET: u32 = A::KeysGet.bits(); @@ -313,6 +335,7 @@ pub mod actions { pub const KEYS_DELETE: u32 = A::KeysDelete.bits(); pub const EXPERIMENTAL_FEATURES_GET: u32 = A::ExperimentalFeaturesGet.bits(); pub const EXPERIMENTAL_FEATURES_UPDATE: u32 = A::ExperimentalFeaturesUpdate.bits(); + pub const ALL: u32 = A::All.bits(); } impl Deserr for Action { @@ -381,48 +404,48 @@ impl<'de> Deserialize<'de> for Action { } } +// TODO: Once "all" type flags are removed, simplify +// Essentially `get_potential_index` will give the exact index, +1 the exact next, -1 the exact previous impl Sequence for Action { const CARDINALITY: usize = Self::FLAGS.len(); fn next(&self) -> Option { - let mut iter = Self::FLAGS.iter(); - while let Some(action) = iter.next() { - if action.value() == self { - if let Some(action) = iter.next() { - return Some(*action.value()); + let mut potential_next_index = self.get_potential_index() + 1; + + loop { + if let Some(next_flag) = Self::FLAGS.get(potential_next_index) { + let next_flag_value = next_flag.value(); + + if next_flag_value > self { + return Some(*next_flag_value); } - break; + potential_next_index += 1; + } else { + return None; } } - - None } fn previous(&self) -> Option { - let mut iter = Self::FLAGS.iter().peekable(); + // -2 because of "all" type flags that represent a single flag, otherwise -1 would suffice + let mut potential_previous_index = self.get_potential_index() - 2; + let mut previous_item: Option = None; - if let Some(action) = iter.next() { - if action.value() == self { + loop { + if let Some(next_flag) = Self::FLAGS.get(potential_previous_index) { + let next_flag_value = next_flag.value(); + + if next_flag_value > self { + return previous_item; + } + + previous_item = Some(*next_flag_value); + potential_previous_index += 1; + } else { return None; } - - if let Some(next_action) = iter.peek() { - if next_action.value() == self { - return Some(*action.value()); - } - } } - - while let Some(action) = iter.next() { - if let Some(next_action) = iter.peek() { - if next_action.value() == self { - return Some(*action.value()); - } - } - } - - None } fn first() -> Option { From ccd79b07f7c368dd8785571a175e243acfbe9eef Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:13:27 +0200 Subject: [PATCH 19/21] Fix test snapshots --- crates/meilisearch/tests/auth/api_keys.rs | 2 +- crates/meilisearch/tests/auth/errors.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/auth/api_keys.rs b/crates/meilisearch/tests/auth/api_keys.rs index 8d272f29d..a465b022a 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.add`, `documents.get`, `documents.delete`, `documents.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `indexes.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `tasks.*`, `settings.get`, `settings.update`, `settings.*`, `stats.get`, `metrics.get`, `dumps.create`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `*`", + "message": "Unknown value `doc.add` at `.actions[0]`: expected one of `search`, `documents.add`, `documents.get`, `documents.delete`, `documents.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `indexes.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `tasks.*`, `settings.get`, `settings.update`, `settings.*`, `stats.get`, `stats.*`, `metrics.get`, `metrics.*`, `dumps.create`, `dumps.*`, `snapshots.create`, `snapshots.*`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `*`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" diff --git a/crates/meilisearch/tests/auth/errors.rs b/crates/meilisearch/tests/auth/errors.rs index 1d41f286c..4ba9874bc 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.add`, `documents.get`, `documents.delete`, `documents.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `indexes.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `tasks.*`, `settings.get`, `settings.update`, `settings.*`, `stats.get`, `metrics.get`, `dumps.create`, `snapshots.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `*`", + "message": "Unknown value `doggo` at `.actions[0]`: expected one of `search`, `documents.add`, `documents.get`, `documents.delete`, `documents.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `indexes.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `tasks.*`, `settings.get`, `settings.update`, `settings.*`, `stats.get`, `stats.*`, `metrics.get`, `metrics.*`, `dumps.create`, `dumps.*`, `snapshots.create`, `snapshots.*`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`, `experimental.get`, `experimental.update`, `*`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" From c2b14b8f8fa490a9aa4fa9f038aad1758a80ae93 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:08:55 +0200 Subject: [PATCH 20/21] Fix erroneous Sequence impl --- crates/meilisearch-types/src/keys.rs | 29 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 76b675bb7..942215099 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -413,11 +413,9 @@ impl Sequence for Action { let mut potential_next_index = self.get_potential_index() + 1; loop { - if let Some(next_flag) = Self::FLAGS.get(potential_next_index) { - let next_flag_value = next_flag.value(); - - if next_flag_value > self { - return Some(*next_flag_value); + if let Some(next_flag) = Self::FLAGS.get(potential_next_index).map(|v| v.value()) { + if next_flag > self { + return Some(*next_flag); } potential_next_index += 1; @@ -429,18 +427,25 @@ impl Sequence for Action { fn previous(&self) -> Option { // -2 because of "all" type flags that represent a single flag, otherwise -1 would suffice - let mut potential_previous_index = self.get_potential_index() - 2; + let initial_potential_index = self.get_potential_index(); + if initial_potential_index == 0 { + return None; + } + + let mut potential_previous_index: usize = + if initial_potential_index == 1 { 0 } else { initial_potential_index - 2 }; + let mut previous_item: Option = None; + let mut pre_previous_item: Option = None; loop { - if let Some(next_flag) = Self::FLAGS.get(potential_previous_index) { - let next_flag_value = next_flag.value(); - - if next_flag_value > self { - return previous_item; + if let Some(next_flag) = Self::FLAGS.get(potential_previous_index).map(|v| v.value()) { + if next_flag > self { + return pre_previous_item; } - previous_item = Some(*next_flag_value); + pre_previous_item = previous_item; + previous_item = Some(*next_flag); potential_previous_index += 1; } else { return None; From 78828197957c90d82d1980608210fa722519b387 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:58:54 +0200 Subject: [PATCH 21/21] Fix erroneous Sequence impl --- crates/meilisearch-types/src/keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch-types/src/keys.rs b/crates/meilisearch-types/src/keys.rs index 942215099..436854d7d 100644 --- a/crates/meilisearch-types/src/keys.rs +++ b/crates/meilisearch-types/src/keys.rs @@ -448,7 +448,7 @@ impl Sequence for Action { previous_item = Some(*next_flag); potential_previous_index += 1; } else { - return None; + return pre_previous_item; } } }