clean code, and fix errors

This commit is contained in:
mpostma 2020-12-22 14:02:41 +01:00
parent 29b1f55bb0
commit 7c9eaaeadb
20 changed files with 3723 additions and 474 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# the milli project is a library
/target

3447
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,16 @@
[package] [package]
name = "meilisearch-http" authors = ["Quentin de Quelen <quentin@dequelen.me>", "Clément Renault <clement@meilisearch.com>"]
description = "MeiliSearch HTTP server" description = "MeiliSearch HTTP server"
version = "0.17.0"
license = "MIT"
authors = [
"Quentin de Quelen <quentin@dequelen.me>",
"Clément Renault <clement@meilisearch.com>",
]
edition = "2018" edition = "2018"
license = "MIT"
name = "meilisearch-http"
version = "0.17.0"
[[bin]] [[bin]]
name = "meilisearch" name = "meilisearch"
path = "src/main.rs" path = "src/main.rs"
[features] [build-dependencies]
default = ["sentry"] vergen = "3.1.0"
[dependencies] [dependencies]
actix-cors = "0.5.3" actix-cors = "0.5.3"
@ -22,6 +18,7 @@ actix-http = "2"
actix-rt = "1" actix-rt = "1"
actix-service = "1.0.6" actix-service = "1.0.6"
actix-web = { version = "3.3.2", features = ["rustls"] } actix-web = { version = "3.3.2", features = ["rustls"] }
byte-unit = { version = "4.0.9", default-features = false, features = ["std"] }
bytes = "0.6.0" bytes = "0.6.0"
chrono = { version = "0.4.19", features = ["serde"] } chrono = { version = "0.4.19", features = ["serde"] }
crossbeam-channel = "0.5.0" crossbeam-channel = "0.5.0"
@ -29,19 +26,16 @@ env_logger = "0.8.2"
flate2 = "1.0.18" flate2 = "1.0.18"
futures = "0.3.7" futures = "0.3.7"
http = "0.2.1" http = "0.2.1"
indexmap = { version = "1.3.2", features = ["serde-1"] } indexmap = { version = "1.3.2", features = ["serde-1"] }
log = "0.4.8" log = "0.4.8"
main_error = "0.1.0" main_error = "0.1.0"
meilisearch-core = { path = "../meilisearch-core", version = "0.17.0" } milli = { path = "../milli" }
meilisearch-error = { path = "../meilisearch-error", version = "0.17.0" }
meilisearch-schema = { path = "../meilisearch-schema", version = "0.17.0" }
meilisearch-tokenizer = {path = "../meilisearch-tokenizer", version = "0.17.0"}
mime = "0.3.16" mime = "0.3.16"
once_cell = "1.5.2" once_cell = "1.5.2"
rand = "0.7.3" rand = "0.7.3"
regex = "1.4.2" regex = "1.4.2"
rustls = "0.18" rustls = "0.18"
serde = { version = "1.0.117", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0.59", features = ["preserve_order"] } serde_json = { version = "1.0.59", features = ["preserve_order"] }
serde_qs = "0.8.1" serde_qs = "0.8.1"
sha2 = "0.9.1" sha2 = "0.9.1"
@ -50,37 +44,27 @@ slice-group-by = "0.2.6"
structopt = "0.3.20" structopt = "0.3.20"
tar = "0.4.29" tar = "0.4.29"
tempfile = "3.1.0" tempfile = "3.1.0"
tokio = { version = "0.2.18", features = ["macros"] } tokio = "*"
ureq = { version = "1.5.1", features = ["tls"], default-features = false } ureq = { version = "1.5.1", default-features = false, features = ["tls"] }
walkdir = "2.3.1" walkdir = "2.3.1"
whoami = "1.0.0" whoami = "1.0.0"
meilisearch-error = { path = "../MeiliSearch/meilisearch-error" }
[dependencies.sentry] [dependencies.sentry]
version = "0.18.1"
default-features = false default-features = false
features = [ features = ["with_client_implementation", "with_panic", "with_failure", "with_device_info", "with_rust_info", "with_reqwest_transport", "with_rustls", "with_env_logger"]
"with_client_implementation",
"with_panic",
"with_failure",
"with_device_info",
"with_rust_info",
"with_reqwest_transport",
"with_rustls",
"with_env_logger"
]
optional = true optional = true
version = "0.18.1"
[dev-dependencies] [dev-dependencies]
serde_url_params = "0.2.0" serde_url_params = "0.2.0"
tempdir = "0.3.7" tempdir = "0.3.7"
assert-json-diff = { branch = "master", git = "https://github.com/qdequele/assert-json-diff" }
tokio = { version = "0.2.18", features = ["macros", "time"] } tokio = { version = "0.2.18", features = ["macros", "time"] }
[dev-dependencies.assert-json-diff] [features]
git = "https://github.com/qdequele/assert-json-diff" default = ["sentry"]
branch = "master"
[build-dependencies]
vergen = "3.1.0"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
jemallocator = "0.3.2" jemallocator = "0.3.2"

View File

@ -3,12 +3,11 @@ use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use meilisearch_core::{Database, DatabaseOptions, Index};
use sha2::Digest; use sha2::Digest;
use milli::Index;
use crate::error::{Error as MSError, ResponseError};
use crate::index_update_callback;
use crate::option::Opt; use crate::option::Opt;
use crate::updates::UpdateQueue;
#[derive(Clone)] #[derive(Clone)]
pub struct Data { pub struct Data {
@ -25,7 +24,8 @@ impl Deref for Data {
#[derive(Clone)] #[derive(Clone)]
pub struct DataInner { pub struct DataInner {
pub db: Arc<Database>, pub indexes: Arc<Index>,
pub update_store: UpdateQueue,
pub db_path: String, pub db_path: String,
pub dumps_dir: PathBuf, pub dumps_dir: PathBuf,
pub dump_batch_size: usize, pub dump_batch_size: usize,
@ -59,104 +59,7 @@ impl ApiKeys {
} }
impl Data { impl Data {
pub fn new(opt: Opt) -> Result<Data, Box<dyn Error>> { pub fn new(_opt: Opt) -> Result<Data, Box<dyn Error>> {
let db_path = opt.db_path.clone(); todo!()
let dumps_dir = opt.dumps_dir.clone();
let dump_batch_size = opt.dump_batch_size;
let server_pid = std::process::id();
let db_opt = DatabaseOptions {
main_map_size: opt.max_mdb_size,
update_map_size: opt.max_udb_size,
};
let http_payload_size_limit = opt.http_payload_size_limit;
let db = Arc::new(Database::open_or_create(opt.db_path, db_opt)?);
let mut api_keys = ApiKeys {
master: opt.master_key,
private: None,
public: None,
};
api_keys.generate_missing_api_keys();
let inner_data = DataInner {
db: db.clone(),
db_path,
dumps_dir,
dump_batch_size,
api_keys,
server_pid,
http_payload_size_limit,
};
let data = Data {
inner: Arc::new(inner_data),
};
let callback_context = data.clone();
db.set_update_callback(Box::new(move |index_uid, status| {
index_update_callback(&index_uid, &callback_context, status);
}));
Ok(data)
}
fn create_index(&self, uid: &str) -> Result<Index, ResponseError> {
if !uid
.chars()
.all(|x| x.is_ascii_alphanumeric() || x == '-' || x == '_')
{
return Err(MSError::InvalidIndexUid.into());
}
let created_index = self.db.create_index(&uid).map_err(|e| match e {
meilisearch_core::Error::IndexAlreadyExists => e.into(),
_ => ResponseError::from(MSError::create_index(e)),
})?;
self.db.main_write::<_, _, ResponseError>(|mut writer| {
created_index.main.put_name(&mut writer, uid)?;
created_index
.main
.created_at(&writer)?
.ok_or(MSError::internal("Impossible to read created at"))?;
created_index
.main
.updated_at(&writer)?
.ok_or(MSError::internal("Impossible to read updated at"))?;
Ok(())
})?;
Ok(created_index)
}
pub fn get_or_create_index<F, R>(&self, uid: &str, f: F) -> Result<R, ResponseError>
where
F: FnOnce(&Index) -> Result<R, ResponseError>,
{
let mut index_has_been_created = false;
let index = match self.db.open_index(&uid) {
Some(index) => index,
None => {
index_has_been_created = true;
self.create_index(&uid)?
}
};
match f(&index) {
Ok(r) => Ok(r),
Err(err) => {
if index_has_been_created {
let _ = self.db.delete_index(&uid);
}
Err(err)
}
}
} }
} }

View File

@ -8,9 +8,6 @@ use actix_web::web;
use chrono::offset::Utc; use chrono::offset::Utc;
use indexmap::IndexMap; use indexmap::IndexMap;
use log::{error, info}; use log::{error, info};
use meilisearch_core::{MainWriter, MainReader, UpdateReader};
use meilisearch_core::settings::Settings;
use meilisearch_core::update::{apply_settings_update, apply_documents_addition};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
@ -20,6 +17,7 @@ use crate::Data;
use crate::error::{Error, ResponseError}; use crate::error::{Error, ResponseError};
use crate::helpers::compression; use crate::helpers::compression;
use crate::routes::index; use crate::routes::index;
use crate::routes::setting::Settings;
use crate::routes::index::IndexResponse; use crate::routes::index::IndexResponse;
// Mutex to share dump progress. // Mutex to share dump progress.

View File

@ -6,9 +6,9 @@ use actix_web as aweb;
use actix_web::error::{JsonPayloadError, QueryPayloadError}; use actix_web::error::{JsonPayloadError, QueryPayloadError};
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use serde::ser::{Serialize, Serializer, SerializeStruct}; use serde::ser::{Serialize, Serializer, SerializeStruct};
use meilisearch_error::{ErrorCode, Code}; use meilisearch_error::{ErrorCode, Code};
#[derive(Debug)] #[derive(Debug)]
pub struct ResponseError { pub struct ResponseError {
inner: Box<dyn ErrorCode>, inner: Box<dyn ErrorCode>,
@ -34,18 +34,6 @@ impl From<Error> for ResponseError {
} }
} }
impl From<meilisearch_core::Error> for ResponseError {
fn from(err: meilisearch_core::Error) -> ResponseError {
ResponseError { inner: Box::new(err) }
}
}
impl From<meilisearch_schema::Error> for ResponseError {
fn from(err: meilisearch_schema::Error) -> ResponseError {
ResponseError { inner: Box::new(err) }
}
}
impl From<FacetCountError> for ResponseError { impl From<FacetCountError> for ResponseError {
fn from(err: FacetCountError) -> ResponseError { fn from(err: FacetCountError) -> ResponseError {
ResponseError { inner: Box::new(err) } ResponseError { inner: Box::new(err) }
@ -123,8 +111,9 @@ impl ErrorCode for Error {
SearchDocuments(_) => Code::SearchDocuments, SearchDocuments(_) => Code::SearchDocuments,
PayloadTooLarge => Code::PayloadTooLarge, PayloadTooLarge => Code::PayloadTooLarge,
UnsupportedMediaType => Code::UnsupportedMediaType, UnsupportedMediaType => Code::UnsupportedMediaType,
DumpAlreadyInProgress => Code::DumpAlreadyInProgress, _ => unreachable!()
DumpProcessFailed(_) => Code::DumpProcessFailed, //DumpAlreadyInProgress => Code::DumpAlreadyInProgress,
//DumpProcessFailed(_) => Code::DumpProcessFailed,
} }
} }
} }
@ -270,12 +259,6 @@ impl From<actix_http::Error> for Error {
} }
} }
impl From<meilisearch_core::Error> for Error {
fn from(err: meilisearch_core::Error) -> Error {
Error::Internal(err.to_string())
}
}
impl From<serde_json::error::Error> for Error { impl From<serde_json::error::Error> for Error {
fn from(err: serde_json::error::Error) -> Error { fn from(err: serde_json::error::Error) -> Error {
Error::Internal(err.to_string()) Error::Internal(err.to_string())

View File

@ -3,24 +3,20 @@
pub mod data; pub mod data;
pub mod error; pub mod error;
pub mod helpers; pub mod helpers;
pub mod models;
pub mod option; pub mod option;
pub mod routes; pub mod routes;
pub mod analytics; mod updates;
pub mod snapshot; //pub mod analytics;
pub mod dump; //pub mod snapshot;
//pub mod dump;
use actix_http::Error; use actix_http::Error;
use actix_service::ServiceFactory; use actix_service::ServiceFactory;
use actix_web::{dev, web, App}; use actix_web::{dev, web, App};
use chrono::Utc;
use log::error;
use meilisearch_core::{Index, MainWriter, ProcessedUpdateResult};
pub use option::Opt; pub use option::Opt;
pub use self::data::Data; pub use self::data::Data;
use self::error::{payload_error_handler, ResponseError}; use self::error::payload_error_handler;
pub fn create_app( pub fn create_app(
data: &Data, data: &Data,
@ -55,8 +51,8 @@ pub fn create_app(
.configure(routes::synonym::services) .configure(routes::synonym::services)
.configure(routes::health::services) .configure(routes::health::services)
.configure(routes::stats::services) .configure(routes::stats::services)
.configure(routes::key::services) .configure(routes::key::services);
.configure(routes::dump::services); //.configure(routes::dump::services);
if enable_frontend { if enable_frontend {
app app
.service(routes::load_html) .service(routes::load_html)
@ -65,40 +61,3 @@ pub fn create_app(
app app
} }
} }
pub fn index_update_callback_txn(index: Index, index_uid: &str, data: &Data, mut writer: &mut MainWriter) -> Result<(), String> {
if let Err(e) = data.db.compute_stats(&mut writer, index_uid) {
return Err(format!("Impossible to compute stats; {}", e));
}
if let Err(e) = data.db.set_last_update(&mut writer, &Utc::now()) {
return Err(format!("Impossible to update last_update; {}", e));
}
if let Err(e) = index.main.put_updated_at(&mut writer) {
return Err(format!("Impossible to update updated_at; {}", e));
}
Ok(())
}
pub fn index_update_callback(index_uid: &str, data: &Data, status: ProcessedUpdateResult) {
if status.error.is_some() {
return;
}
if let Some(index) = data.db.open_index(index_uid) {
let db = &data.db;
let res = db.main_write::<_, _, ResponseError>(|mut writer| {
if let Err(e) = index_update_callback_txn(index, index_uid, data, &mut writer) {
error!("{}", e);
}
Ok(())
});
match res {
Ok(_) => (),
Err(e) => error!("{}", e),
}
}
}

View File

@ -1,14 +1,13 @@
use std::{env, thread}; use std::env;
use actix_cors::Cors; use actix_cors::Cors;
use actix_web::{middleware, HttpServer}; use actix_web::{middleware, HttpServer};
use main_error::MainError; use main_error::MainError;
use meilisearch_http::helpers::NormalizePath; use meilisearch_http::helpers::NormalizePath;
use meilisearch_http::{create_app, index_update_callback, Data, Opt}; use meilisearch_http::{create_app, Data, Opt};
use structopt::StructOpt; use structopt::StructOpt;
use meilisearch_http::{snapshot, dump};
mod analytics; //mod analytics;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
#[global_allocator] #[global_allocator]
@ -52,31 +51,25 @@ async fn main() -> Result<(), MainError> {
_ => unreachable!(), _ => unreachable!(),
} }
if let Some(path) = &opt.import_snapshot { //if let Some(path) = &opt.import_snapshot {
snapshot::load_snapshot(&opt.db_path, path, opt.ignore_snapshot_if_db_exists, opt.ignore_missing_snapshot)?; //snapshot::load_snapshot(&opt.db_path, path, opt.ignore_snapshot_if_db_exists, opt.ignore_missing_snapshot)?;
} //}
let data = Data::new(opt.clone())?; let data = Data::new(opt.clone())?;
if !opt.no_analytics { //if !opt.no_analytics {
let analytics_data = data.clone(); //let analytics_data = data.clone();
let analytics_opt = opt.clone(); //let analytics_opt = opt.clone();
thread::spawn(move || analytics::analytics_sender(analytics_data, analytics_opt)); //thread::spawn(move || analytics::analytics_sender(analytics_data, analytics_opt));
} //}
let data_cloned = data.clone(); //if let Some(path) = &opt.import_dump {
data.db.set_update_callback(Box::new(move |name, status| { //dump::import_dump(&data, path, opt.dump_batch_size)?;
index_update_callback(name, &data_cloned, status); //}
}));
//if opt.schedule_snapshot {
if let Some(path) = &opt.import_dump { //snapshot::schedule_snapshot(data.clone(), &opt.snapshot_dir, opt.snapshot_interval_sec.unwrap_or(86400))?;
dump::import_dump(&data, path, opt.dump_batch_size)?; //}
}
if opt.schedule_snapshot {
snapshot::schedule_snapshot(data.clone(), &opt.snapshot_dir, opt.snapshot_interval_sec.unwrap_or(86400))?;
}
print_launch_resume(&opt, &data); print_launch_resume(&opt, &data);

View File

@ -3,6 +3,7 @@ use std::io::{BufReader, Read};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use byte_unit::Byte;
use rustls::internal::pemfile::{certs, pkcs8_private_keys, rsa_private_keys}; use rustls::internal::pemfile::{certs, pkcs8_private_keys, rsa_private_keys};
use rustls::{ use rustls::{
AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth, AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth,
@ -12,7 +13,7 @@ use structopt::StructOpt;
const POSSIBLE_ENV: [&str; 2] = ["development", "production"]; const POSSIBLE_ENV: [&str; 2] = ["development", "production"];
#[derive(Debug, Default, Clone, StructOpt)] #[derive(Debug, Clone, StructOpt)]
pub struct Opt { pub struct Opt {
/// The destination where the database must be created. /// The destination where the database must be created.
#[structopt(long, env = "MEILI_DB_PATH", default_value = "./data.ms")] #[structopt(long, env = "MEILI_DB_PATH", default_value = "./data.ms")]
@ -49,16 +50,16 @@ pub struct Opt {
pub no_analytics: bool, pub no_analytics: bool,
/// The maximum size, in bytes, of the main lmdb database directory /// The maximum size, in bytes, of the main lmdb database directory
#[structopt(long, env = "MEILI_MAX_MDB_SIZE", default_value = "107374182400")] // 100GB #[structopt(long, env = "MEILI_MAX_MDB_SIZE", default_value = "100 GiB")]
pub max_mdb_size: usize, pub max_mdb_size: Byte,
/// The maximum size, in bytes, of the update lmdb database directory /// The maximum size, in bytes, of the update lmdb database directory
#[structopt(long, env = "MEILI_MAX_UDB_SIZE", default_value = "107374182400")] // 100GB #[structopt(long, env = "MEILI_MAX_UDB_SIZE", default_value = "10 GiB")]
pub max_udb_size: usize, pub max_udb_size: Byte,
/// The maximum size, in bytes, of accepted JSON payloads /// The maximum size, in bytes, of accepted JSON payloads
#[structopt(long, env = "MEILI_HTTP_PAYLOAD_SIZE_LIMIT", default_value = "10485760")] // 10MB #[structopt(long, env = "MEILI_HTTP_PAYLOAD_SIZE_LIMIT", default_value = "10 MiB")]
pub http_payload_size_limit: usize, pub http_payload_size_limit: Byte,
/// Read server certificates from CERTFILE. /// Read server certificates from CERTFILE.
/// This should contain PEM-format certificates /// This should contain PEM-format certificates

View File

@ -1,23 +1,20 @@
use std::collections::{BTreeSet, HashSet};
use actix_web::{delete, get, post, put}; use actix_web::{delete, get, post, put};
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
use indexmap::IndexMap; use indexmap::IndexMap;
use meilisearch_core::{update, MainReader};
use serde_json::Value; use serde_json::Value;
use serde::Deserialize; use serde::Deserialize;
use crate::Data; use crate::Data;
use crate::error::{Error, ResponseError}; use crate::error::ResponseError;
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::{IndexParam, IndexUpdateResponse}; use crate::routes::IndexParam;
type Document = IndexMap<String, Value>; type Document = IndexMap<String, Value>;
#[derive(Deserialize)] #[derive(Deserialize)]
struct DocumentParam { struct DocumentParam {
index_uid: String, _index_uid: String,
document_id: String, _document_id: String,
} }
pub fn services(cfg: &mut web::ServiceConfig) { pub fn services(cfg: &mut web::ServiceConfig) {
@ -35,8 +32,8 @@ pub fn services(cfg: &mut web::ServiceConfig) {
wrap = "Authentication::Public" wrap = "Authentication::Public"
)] )]
async fn get_document( async fn get_document(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<DocumentParam>, _path: web::Path<DocumentParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -46,8 +43,8 @@ async fn get_document(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete_document( async fn delete_document(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<DocumentParam>, _path: web::Path<DocumentParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -55,62 +52,51 @@ async fn delete_document(
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)]
struct BrowseQuery { struct BrowseQuery {
offset: Option<usize>, _offset: Option<usize>,
limit: Option<usize>, _limit: Option<usize>,
attributes_to_retrieve: Option<String>, _attributes_to_retrieve: Option<String>,
}
pub fn get_all_documents_sync(
data: &web::Data<Data>,
reader: &MainReader,
index_uid: &str,
offset: usize,
limit: usize,
attributes_to_retrieve: Option<&String>
) -> Result<Vec<Document>, Error> {
todo!()
} }
#[get("/indexes/{index_uid}/documents", wrap = "Authentication::Public")] #[get("/indexes/{index_uid}/documents", wrap = "Authentication::Public")]
async fn get_all_documents( async fn get_all_documents(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
params: web::Query<BrowseQuery>, _params: web::Query<BrowseQuery>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
fn find_primary_key(document: &IndexMap<String, Value>) -> Option<String> { //fn find_primary_key(document: &IndexMap<String, Value>) -> Option<String> {
for key in document.keys() { //for key in document.keys() {
if key.to_lowercase().contains("id") { //if key.to_lowercase().contains("id") {
return Some(key.to_string()); //return Some(key.to_string());
} //}
} //}
None //None
} //}
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)]
struct UpdateDocumentsQuery { struct UpdateDocumentsQuery {
primary_key: Option<String>, _primary_key: Option<String>,
} }
async fn update_multiple_documents( async fn update_multiple_documents(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
params: web::Query<UpdateDocumentsQuery>, _params: web::Query<UpdateDocumentsQuery>,
body: web::Json<Vec<Document>>, _body: web::Json<Vec<Document>>,
is_partial: bool, _is_partial: bool,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
#[post("/indexes/{index_uid}/documents", wrap = "Authentication::Private")] #[post("/indexes/{index_uid}/documents", wrap = "Authentication::Private")]
async fn add_documents( async fn add_documents(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
params: web::Query<UpdateDocumentsQuery>, _params: web::Query<UpdateDocumentsQuery>,
body: web::Json<Vec<Document>>, _body: web::Json<Vec<Document>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -130,17 +116,17 @@ async fn update_documents(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete_documents( async fn delete_documents(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
body: web::Json<Vec<Value>>, _body: web::Json<Vec<Value>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
#[delete("/indexes/{index_uid}/documents", wrap = "Authentication::Private")] #[delete("/indexes/{index_uid}/documents", wrap = "Authentication::Private")]
async fn clear_all_documents( async fn clear_all_documents(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }

View File

@ -1,14 +1,10 @@
use actix_web::{delete, get, post, put}; use actix_web::{delete, get, post, put};
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use log::error;
use meilisearch_core::{Database, MainReader, UpdateReader};
use meilisearch_core::update::UpdateStatus;
use rand::seq::SliceRandom;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Data; use crate::Data;
use crate::error::{Error, ResponseError}; use crate::error::ResponseError;
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::IndexParam; use crate::routes::IndexParam;
@ -22,10 +18,6 @@ pub fn services(cfg: &mut web::ServiceConfig) {
.service(get_all_updates_status); .service(get_all_updates_status);
} }
fn generate_uid() -> String {
todo!()
}
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct IndexResponse { pub struct IndexResponse {
@ -36,22 +28,15 @@ pub struct IndexResponse {
pub primary_key: Option<String>, pub primary_key: Option<String>,
} }
pub fn list_indexes_sync(data: &web::Data<Data>, reader: &MainReader) -> Result<Vec<IndexResponse>, ResponseError> {
todo!()
}
#[get("/indexes", wrap = "Authentication::Private")] #[get("/indexes", wrap = "Authentication::Private")]
async fn list_indexes(data: web::Data<Data>) -> Result<HttpResponse, ResponseError> { async fn list_indexes(_data: web::Data<Data>) -> Result<HttpResponse, ResponseError> {
let reader = data.db.main_read_txn()?; todo!()
let indexes = list_indexes_sync(&data, &reader)?;
Ok(HttpResponse::Ok().json(indexes))
} }
#[get("/indexes/{index_uid}", wrap = "Authentication::Private")] #[get("/indexes/{index_uid}", wrap = "Authentication::Private")]
async fn get_index( async fn get_index(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -64,20 +49,10 @@ struct IndexCreateRequest {
primary_key: Option<String>, primary_key: Option<String>,
} }
pub fn create_index_sync(
database: &std::sync::Arc<Database>,
uid: String,
name: String,
primary_key: Option<String>,
) -> Result<IndexResponse, Error> {
todo!()
}
#[post("/indexes", wrap = "Authentication::Private")] #[post("/indexes", wrap = "Authentication::Private")]
async fn create_index( async fn create_index(
data: web::Data<Data>, _data: web::Data<Data>,
body: web::Json<IndexCreateRequest>, _body: web::Json<IndexCreateRequest>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -101,25 +76,25 @@ struct UpdateIndexResponse {
#[put("/indexes/{index_uid}", wrap = "Authentication::Private")] #[put("/indexes/{index_uid}", wrap = "Authentication::Private")]
async fn update_index( async fn update_index(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
body: web::Json<IndexCreateRequest>, _body: web::Json<IndexCreateRequest>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
#[delete("/indexes/{index_uid}", wrap = "Authentication::Private")] #[delete("/indexes/{index_uid}", wrap = "Authentication::Private")]
async fn delete_index( async fn delete_index(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
#[derive(Deserialize)] #[derive(Deserialize)]
struct UpdateParam { struct UpdateParam {
index_uid: String, _index_uid: String,
update_id: u64, _update_id: u64,
} }
#[get( #[get(
@ -127,23 +102,16 @@ struct UpdateParam {
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get_update_status( async fn get_update_status(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<UpdateParam>, _path: web::Path<UpdateParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
pub fn get_all_updates_status_sync(
data: &web::Data<Data>,
reader: &UpdateReader,
index_uid: &str,
) -> Result<Vec<UpdateStatus>, Error> {
todo!()
}
#[get("/indexes/{index_uid}/updates", wrap = "Authentication::Private")] #[get("/indexes/{index_uid}/updates", wrap = "Authentication::Private")]
async fn get_all_updates_status( async fn get_all_updates_status(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }

View File

@ -17,6 +17,6 @@ struct KeysResponse {
} }
#[get("/keys", wrap = "Authentication::Admin")] #[get("/keys", wrap = "Authentication::Admin")]
async fn list(data: web::Data<Data>) -> HttpResponse { async fn list(_data: web::Data<Data>) -> HttpResponse {
todo!() todo!()
} }

View File

@ -10,11 +10,11 @@ pub mod setting;
pub mod stats; pub mod stats;
pub mod stop_words; pub mod stop_words;
pub mod synonym; pub mod synonym;
pub mod dump; //pub mod dump;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct IndexParam { pub struct IndexParam {
index_uid: String, _index_uid: String,
} }
#[derive(Serialize)] #[derive(Serialize)]

View File

@ -1,19 +1,12 @@
use std::collections::{HashMap, HashSet};
use actix_web::{get, post, web, HttpResponse}; use actix_web::{get, post, web, HttpResponse};
use log::warn;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use crate::error::{Error, FacetCountError, ResponseError}; use crate::error::ResponseError;
use crate::helpers::meilisearch::{IndexSearchExt, SearchResult};
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::IndexParam; use crate::routes::IndexParam;
use crate::Data; use crate::Data;
use meilisearch_core::facets::FacetFilter;
use meilisearch_schema::{FieldId, Schema};
pub fn services(cfg: &mut web::ServiceConfig) { pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(search_with_post).service(search_with_url_query); cfg.service(search_with_post).service(search_with_url_query);
} }
@ -36,9 +29,9 @@ pub struct SearchQuery {
#[get("/indexes/{index_uid}/search", wrap = "Authentication::Public")] #[get("/indexes/{index_uid}/search", wrap = "Authentication::Public")]
async fn search_with_url_query( async fn search_with_url_query(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
params: web::Query<SearchQuery>, _params: web::Query<SearchQuery>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -46,53 +39,24 @@ async fn search_with_url_query(
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct SearchQueryPost { pub struct SearchQueryPost {
q: Option<String>, _q: Option<String>,
offset: Option<usize>, _offset: Option<usize>,
limit: Option<usize>, _limit: Option<usize>,
attributes_to_retrieve: Option<Vec<String>>, _attributes_to_retrieve: Option<Vec<String>>,
attributes_to_crop: Option<Vec<String>>, _attributes_to_crop: Option<Vec<String>>,
crop_length: Option<usize>, _crop_length: Option<usize>,
attributes_to_highlight: Option<Vec<String>>, _attributes_to_highlight: Option<Vec<String>>,
filters: Option<String>, _filters: Option<String>,
matches: Option<bool>, _matches: Option<bool>,
facet_filters: Option<Value>, _facet_filters: Option<Value>,
facets_distribution: Option<Vec<String>>, _facets_distribution: Option<Vec<String>>,
}
impl From<SearchQueryPost> for SearchQuery {
fn from(other: SearchQueryPost) -> SearchQuery {
SearchQuery {
q: other.q,
offset: other.offset,
limit: other.limit,
attributes_to_retrieve: other.attributes_to_retrieve.map(|attrs| attrs.join(",")),
attributes_to_crop: other.attributes_to_crop.map(|attrs| attrs.join(",")),
crop_length: other.crop_length,
attributes_to_highlight: other.attributes_to_highlight.map(|attrs| attrs.join(",")),
filters: other.filters,
matches: other.matches,
facet_filters: other.facet_filters.map(|f| f.to_string()),
facets_distribution: other.facets_distribution.map(|f| format!("{:?}", f)),
}
}
} }
#[post("/indexes/{index_uid}/search", wrap = "Authentication::Public")] #[post("/indexes/{index_uid}/search", wrap = "Authentication::Public")]
async fn search_with_post( async fn search_with_post(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
params: web::Json<SearchQueryPost>, _params: web::Json<SearchQueryPost>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
let query: SearchQuery = params.0.into();
let search_result = query.search(&path.index_uid, data)?;
Ok(HttpResponse::Ok().json(search_result))
}
impl SearchQuery {
fn search(
&self,
index_uid: &str,
data: web::Data<Data>,
) -> Result<SearchResult, ResponseError> {
todo!() todo!()
} }

View File

@ -1,15 +1,12 @@
use std::collections::{BTreeMap, BTreeSet}; use std::collections::BTreeSet;
use actix_web::{delete, get, post}; use actix_web::{delete, get, post};
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
use meilisearch_core::{MainReader, UpdateWriter};
use meilisearch_core::settings::{Settings, SettingsUpdate, UpdateState, DEFAULT_RANKING_RULES};
use meilisearch_schema::Schema;
use crate::Data; use crate::Data;
use crate::error::{Error, ResponseError}; use crate::error::ResponseError;
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::{IndexParam, IndexUpdateResponse}; use crate::updates::Settings;
pub fn services(cfg: &mut web::ServiceConfig) { pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(update_all) cfg.service(update_all)
@ -32,27 +29,28 @@ pub fn services(cfg: &mut web::ServiceConfig) {
.service(update_attributes_for_faceting); .service(update_attributes_for_faceting);
} }
#[post("/indexes/{index_uid}/settings", wrap = "Authentication::Private")] #[post("/indexes/{index_uid}/settings", wrap = "Authentication::Private")]
async fn update_all( async fn update_all(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
body: web::Json<Settings>, _body: web::Json<Settings>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
#[get("/indexes/{index_uid}/settings", wrap = "Authentication::Private")] #[get("/indexes/{index_uid}/settings", wrap = "Authentication::Private")]
async fn get_all( async fn get_all(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
#[delete("/indexes/{index_uid}/settings", wrap = "Authentication::Private")] #[delete("/indexes/{index_uid}/settings", wrap = "Authentication::Private")]
async fn delete_all( async fn delete_all(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -62,8 +60,8 @@ async fn delete_all(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get_rules( async fn get_rules(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -73,9 +71,9 @@ async fn get_rules(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn update_rules( async fn update_rules(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
body: web::Json<Option<Vec<String>>>, _body: web::Json<Option<Vec<String>>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -85,8 +83,8 @@ async fn update_rules(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete_rules( async fn delete_rules(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -96,8 +94,8 @@ async fn delete_rules(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get_distinct( async fn get_distinct(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -107,9 +105,9 @@ async fn get_distinct(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn update_distinct( async fn update_distinct(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
body: web::Json<Option<String>>, _body: web::Json<Option<String>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -119,8 +117,8 @@ async fn update_distinct(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete_distinct( async fn delete_distinct(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -130,8 +128,8 @@ async fn delete_distinct(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get_searchable( async fn get_searchable(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -141,9 +139,9 @@ async fn get_searchable(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn update_searchable( async fn update_searchable(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
body: web::Json<Option<Vec<String>>>, _body: web::Json<Option<Vec<String>>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -153,8 +151,8 @@ async fn update_searchable(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete_searchable( async fn delete_searchable(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -164,8 +162,8 @@ async fn delete_searchable(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get_displayed( async fn get_displayed(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -175,9 +173,9 @@ async fn get_displayed(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn update_displayed( async fn update_displayed(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
body: web::Json<Option<BTreeSet<String>>>, _body: web::Json<Option<BTreeSet<String>>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -187,8 +185,8 @@ async fn update_displayed(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete_displayed( async fn delete_displayed(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -198,8 +196,8 @@ async fn delete_displayed(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get_attributes_for_faceting( async fn get_attributes_for_faceting(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -209,9 +207,9 @@ async fn get_attributes_for_faceting(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn update_attributes_for_faceting( async fn update_attributes_for_faceting(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
body: web::Json<Option<Vec<String>>>, _body: web::Json<Option<Vec<String>>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -221,8 +219,8 @@ async fn update_attributes_for_faceting(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete_attributes_for_faceting( async fn delete_attributes_for_faceting(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }

View File

@ -4,11 +4,9 @@ use actix_web::web;
use actix_web::HttpResponse; use actix_web::HttpResponse;
use actix_web::get; use actix_web::get;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use log::error;
use serde::Serialize; use serde::Serialize;
use walkdir::WalkDir;
use crate::error::{Error, ResponseError}; use crate::error::ResponseError;
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::IndexParam; use crate::routes::IndexParam;
use crate::Data; use crate::Data;
@ -29,8 +27,8 @@ struct IndexStatsResponse {
#[get("/indexes/{index_uid}/stats", wrap = "Authentication::Private")] #[get("/indexes/{index_uid}/stats", wrap = "Authentication::Private")]
async fn index_stats( async fn index_stats(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -44,7 +42,7 @@ struct StatsResult {
} }
#[get("/stats", wrap = "Authentication::Private")] #[get("/stats", wrap = "Authentication::Private")]
async fn get_stats(data: web::Data<Data>) -> Result<HttpResponse, ResponseError> { async fn get_stats(_data: web::Data<Data>) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }

View File

@ -1,11 +1,10 @@
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
use actix_web::{delete, get, post}; use actix_web::{delete, get, post};
use meilisearch_core::settings::{SettingsUpdate, UpdateState};
use std::collections::BTreeSet; use std::collections::BTreeSet;
use crate::error::{Error, ResponseError}; use crate::error::ResponseError;
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::{IndexParam, IndexUpdateResponse}; use crate::routes::IndexParam;
use crate::Data; use crate::Data;
pub fn services(cfg: &mut web::ServiceConfig) { pub fn services(cfg: &mut web::ServiceConfig) {
@ -17,8 +16,8 @@ pub fn services(cfg: &mut web::ServiceConfig) {
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get( async fn get(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -28,9 +27,9 @@ async fn get(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn update( async fn update(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
body: web::Json<BTreeSet<String>>, _body: web::Json<BTreeSet<String>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -40,8 +39,8 @@ async fn update(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete( async fn delete(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }

View File

@ -2,12 +2,10 @@ use std::collections::BTreeMap;
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
use actix_web::{delete, get, post}; use actix_web::{delete, get, post};
use indexmap::IndexMap;
use meilisearch_core::settings::{SettingsUpdate, UpdateState};
use crate::error::{Error, ResponseError}; use crate::error::ResponseError;
use crate::helpers::Authentication; use crate::helpers::Authentication;
use crate::routes::{IndexParam, IndexUpdateResponse}; use crate::routes::IndexParam;
use crate::Data; use crate::Data;
pub fn services(cfg: &mut web::ServiceConfig) { pub fn services(cfg: &mut web::ServiceConfig) {
@ -19,8 +17,8 @@ pub fn services(cfg: &mut web::ServiceConfig) {
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn get( async fn get(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -30,9 +28,9 @@ async fn get(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn update( async fn update(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
body: web::Json<BTreeMap<String, Vec<String>>>, _body: web::Json<BTreeMap<String, Vec<String>>>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }
@ -42,8 +40,8 @@ async fn update(
wrap = "Authentication::Private" wrap = "Authentication::Private"
)] )]
async fn delete( async fn delete(
data: web::Data<Data>, _data: web::Data<Data>,
path: web::Path<IndexParam>, _path: web::Path<IndexParam>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
todo!() todo!()
} }

17
src/updates/mod.rs Normal file
View File

@ -0,0 +1,17 @@
mod settings;
pub use settings::{Settings, Facets};
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
enum UpdateMeta {
DocumentsAddition { method: String, format: String },
ClearDocuments,
Settings(Settings),
Facets(Facets),
}
#[derive(Clone, Debug)]
pub struct UpdateQueue;

51
src/updates/settings.rs Normal file
View File

@ -0,0 +1,51 @@
use std::num::NonZeroUsize;
use std::collections::HashMap;
use serde::{Serialize, Deserialize, de::Deserializer};
// Any value that is present is considered Some value, including null.
fn deserialize_some<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where T: Deserialize<'de>,
D: Deserializer<'de>
{
Deserialize::deserialize(deserializer).map(Some)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "camelCase")]
pub struct Settings {
#[serde(
default,
deserialize_with = "deserialize_some",
skip_serializing_if = "Option::is_none",
)]
displayed_attributes: Option<Option<Vec<String>>>,
#[serde(
default,
deserialize_with = "deserialize_some",
skip_serializing_if = "Option::is_none",
)]
searchable_attributes: Option<Option<Vec<String>>>,
#[serde(default)]
faceted_attributes: Option<HashMap<String, String>>,
#[serde(
default,
deserialize_with = "deserialize_some",
skip_serializing_if = "Option::is_none",
)]
criteria: Option<Option<Vec<String>>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "camelCase")]
pub struct Facets {
level_group_size: Option<NonZeroUsize>,
min_level_size: Option<NonZeroUsize>,
}