Upgraded to actix-web 4
This commit is contained in:
35
Cargo.toml
35
Cargo.toml
@@ -18,31 +18,28 @@ license = "MIT"
|
|||||||
|
|
||||||
include = ["Cargo.toml", "README.md", "LICENSE", "ACKNOWLEDGEMENTS", "src/**/*.rs"]
|
include = ["Cargo.toml", "README.md", "LICENSE", "ACKNOWLEDGEMENTS", "src/**/*.rs"]
|
||||||
|
|
||||||
|
#[profile.release]
|
||||||
|
#lto = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
static-error-pages = []
|
static-error-pages = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "^1.0"
|
actix-web = "4.8"
|
||||||
actix-files = "^0.1"
|
actix-files = "0.6"
|
||||||
actix-service = "^0.4"
|
actix-cors = "0.7"
|
||||||
actix-cors = "^0.1"
|
glob = "0.3"
|
||||||
glob = "^0.3"
|
|
||||||
|
|
||||||
measure_time = "^0.6"
|
measure_time = "0.8"
|
||||||
memmap = "^0.7"
|
memmap = "0.7"
|
||||||
|
|
||||||
mercator_db = "^0.1"
|
mercator_db = "0.1"
|
||||||
mercator_parser = "^0.1"
|
mercator_parser = "0.1"
|
||||||
|
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "^1.0"
|
serde_json = "1.0"
|
||||||
bincode = "^1.1"
|
bincode = "1.3"
|
||||||
|
|
||||||
# Logging macros API
|
# Logging macros API
|
||||||
log = { version = "^0.4", features = ["max_level_trace", "release_max_level_trace"] }
|
log = { version = "0.4", features = ["max_level_trace", "release_max_level_trace"] }
|
||||||
pretty_env_logger = "^0.3" # Logger implementation
|
pretty_env_logger = "0.5" # Logger implementation
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
# Only for tests
|
|
||||||
actix-server-config = "^0.1"
|
|
||||||
actix-http = "^0.2"
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.42.0"
|
channel = "1.80.0"
|
||||||
|
|||||||
27
src/main.rs
27
src/main.rs
@@ -50,7 +50,8 @@ fn into_bool(string: &str) -> bool {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn main() {
|
#[actix_web::main]
|
||||||
|
async fn main() -> std::io::Result<()> {
|
||||||
// If RUST_LOG is unset, set it to INFO, otherwise keep it as-is.
|
// If RUST_LOG is unset, set it to INFO, otherwise keep it as-is.
|
||||||
if std::env::var("RUST_LOG").is_err() {
|
if std::env::var("RUST_LOG").is_err() {
|
||||||
std::env::set_var("RUST_LOG", "info");
|
std::env::set_var("RUST_LOG", "info");
|
||||||
@@ -78,21 +79,17 @@ fn main() {
|
|||||||
std::env::set_var("MERCATOR_DATA", ".");
|
std::env::set_var("MERCATOR_DATA", ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
let hostname;
|
let hostname = match std::env::var("MERCATOR_HOST") {
|
||||||
let port;
|
Ok(val) => val,
|
||||||
let data;
|
|
||||||
|
|
||||||
match std::env::var("MERCATOR_HOST") {
|
|
||||||
Ok(val) => hostname = val,
|
|
||||||
Err(val) => {
|
Err(val) => {
|
||||||
error!("Invalid environment {} : `{}`", "MERCATOR_HOST", val);
|
error!("Invalid environment {} : `{}`", "MERCATOR_HOST", val);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match std::env::var("MERCATOR_PORT") {
|
let port = match std::env::var("MERCATOR_PORT") {
|
||||||
Ok(val) => match val.parse::<u16>() {
|
Ok(val) => match val.parse::<u16>() {
|
||||||
Ok(v) => port = v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Could not convert to u16 {} : `{}`", "MERCATOR_PORT", e);
|
error!("Could not convert to u16 {} : `{}`", "MERCATOR_PORT", e);
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -104,8 +101,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match std::env::var("MERCATOR_DATA") {
|
let data = match std::env::var("MERCATOR_DATA") {
|
||||||
Ok(val) => data = val,
|
Ok(val) => val,
|
||||||
Err(val) => {
|
Err(val) => {
|
||||||
error!("Could not fetch {} : `{}`", "MERCATOR_DATA", val);
|
error!("Could not fetch {} : `{}`", "MERCATOR_DATA", val);
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -123,9 +120,6 @@ fn main() {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// FIXME: Why do we have to go through a temporary variable?
|
|
||||||
let datasets = datasets.iter().map(String::as_str).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let db;
|
let db;
|
||||||
// Load a Database:
|
// Load a Database:
|
||||||
{
|
{
|
||||||
@@ -133,7 +127,7 @@ fn main() {
|
|||||||
// those is corrupted / incompatible.
|
// those is corrupted / incompatible.
|
||||||
info_time!("Loading database index");
|
info_time!("Loading database index");
|
||||||
|
|
||||||
db = DataBase::load(&datasets)
|
db = DataBase::load(&datasets.iter().map(String::as_str).collect::<Vec<_>>())
|
||||||
.unwrap_or_else(|e| panic!("Error while loading indices: {}", e));
|
.unwrap_or_else(|e| panic!("Error while loading indices: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,5 +135,6 @@ fn main() {
|
|||||||
&hostname,
|
&hostname,
|
||||||
port,
|
port,
|
||||||
Data::new(RwLock::new(SharedState::new(db))),
|
Data::new(RwLock::new(SharedState::new(db))),
|
||||||
);
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ use std::sync::RwLock;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::error_422;
|
use super::error_422;
|
||||||
|
use super::from_properties_by_spaces;
|
||||||
use super::ok_200;
|
use super::ok_200;
|
||||||
use super::to_spatial_objects;
|
|
||||||
use super::web;
|
use super::web;
|
||||||
use super::web::Data;
|
use super::web::Data;
|
||||||
use super::web::Json;
|
use super::web::Json;
|
||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
use super::HttpResponse;
|
use super::HttpResponse;
|
||||||
use super::SharedState;
|
use super::SharedState;
|
||||||
|
use mercator_db::CoreQueryParameters;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Query {
|
pub struct Query {
|
||||||
@@ -36,11 +37,11 @@ impl Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Also used for the root service.
|
// Also used for the root service.
|
||||||
pub fn health() -> HttpResponse {
|
pub async fn health() -> HttpResponse {
|
||||||
HttpResponse::Ok().finish()
|
HttpResponse::Ok().finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query((parameters, state): (Json<Query>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
async fn query((parameters, state): (Json<Query>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
||||||
trace!("POST '{:?}'", parameters);
|
trace!("POST '{:?}'", parameters);
|
||||||
let context = state
|
let context = state
|
||||||
.read()
|
.read()
|
||||||
@@ -50,25 +51,30 @@ fn query((parameters, state): (Json<Query>, Data<RwLock<SharedState>>)) -> Handl
|
|||||||
if query.is_empty() {
|
if query.is_empty() {
|
||||||
error_422(format!("Invalid query in '{:?}'", query))
|
error_422(format!("Invalid query in '{:?}'", query))
|
||||||
} else {
|
} else {
|
||||||
ok_200(
|
let parameters = CoreQueryParameters {
|
||||||
&context
|
db: context.db(),
|
||||||
|
output_space: None,
|
||||||
|
threshold_volume: parameters.volume(),
|
||||||
|
view_port: ¶meters.view_port,
|
||||||
|
resolution: parameters.resolution(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let results = context
|
||||||
.db()
|
.db()
|
||||||
.core_keys()
|
.core_keys()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|core| {
|
.filter_map(|core| {
|
||||||
match context.query(
|
match context.query(query) {
|
||||||
query,
|
Err(_) => None, // FIXME: Return errors here instead!!
|
||||||
core,
|
Ok(tree) => match context.execute(&tree, core, ¶meters) {
|
||||||
parameters.volume(),
|
Err(_) => None, // FIXME: Return errors here instead!!
|
||||||
¶meters.view_port,
|
Ok(objects) => Some(from_properties_by_spaces(objects).collect::<Vec<_>>()),
|
||||||
parameters.resolution(),
|
},
|
||||||
) {
|
|
||||||
Err(_) => vec![], // FIXME: Return errors here instead!!
|
|
||||||
Ok(objects) => to_spatial_objects(objects),
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.flatten()
|
||||||
)
|
.collect::<Vec<_>>();
|
||||||
|
ok_200(&results)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,30 +85,41 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod routing {
|
mod routing {
|
||||||
use super::super::tests_utils::*;
|
use crate::rest_api::tests_utils::*;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn health() {
|
async fn health() {
|
||||||
let ep = &get_path("/health");
|
let ep = &get_path("/health");
|
||||||
|
|
||||||
expect_200(Method::GET, ep);
|
expect_200(TestRequest::get(), ep).await;
|
||||||
|
|
||||||
expect_405(Method::POST, ep);
|
expect_405(TestRequest::post(), ep).await;
|
||||||
expect_405(Method::PUT, ep);
|
expect_405(TestRequest::put(), ep).await;
|
||||||
expect_405(Method::PATCH, ep);
|
expect_405(TestRequest::patch(), ep).await;
|
||||||
expect_405(Method::DELETE, ep);
|
expect_405(TestRequest::delete(), ep).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn query() {
|
async fn query() {
|
||||||
let ep = &get_path("/query");
|
let ep = &get_path("/query");
|
||||||
|
|
||||||
expect_200(Method::POST, ep);
|
expect_200(
|
||||||
expect_422(Method::POST, ep);
|
TestRequest::post()
|
||||||
|
.set_json(json!({"query": "json(.,inside(hyperrectangle{[0,0,0],[0,1,1]}))"})),
|
||||||
|
ep,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
expect_405(Method::GET, ep);
|
expect_422(TestRequest::post().set_json(json!({"query": "toto"})), ep).await;
|
||||||
expect_405(Method::PUT, ep);
|
expect_422(TestRequest::post().set_json(json!({"query": ""})), ep).await;
|
||||||
expect_405(Method::PATCH, ep);
|
expect_400(TestRequest::post().set_json(json!({"invalid": true})), ep).await;
|
||||||
expect_405(Method::DELETE, ep);
|
expect_400(TestRequest::post().set_json(json!({})), ep).await;
|
||||||
|
expect_400(TestRequest::post(), ep).await;
|
||||||
|
|
||||||
|
expect_405(TestRequest::get(), ep).await;
|
||||||
|
expect_405(TestRequest::put(), ep).await;
|
||||||
|
expect_405(TestRequest::patch(), ep).await;
|
||||||
|
expect_405(TestRequest::delete(), ep).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ use super::Core;
|
|||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
use super::SharedState;
|
use super::SharedState;
|
||||||
|
|
||||||
fn put(path: Path<String>) -> HandlerResult {
|
async fn put(path: Path<String>) -> HandlerResult {
|
||||||
trace!("PUT Triggered on {}", path);
|
trace!("PUT Triggered on {}", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get((core, state): (Path<String>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
async fn get((core, state): (Path<String>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
||||||
trace!("GET '{:?}'", core);
|
trace!("GET '{:?}'", core);
|
||||||
let core = core.to_string();
|
let core = core.to_string();
|
||||||
let context = state
|
let context = state
|
||||||
@@ -28,12 +28,12 @@ fn get((core, state): (Path<String>, Data<RwLock<SharedState>>)) -> HandlerResul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch(path: Path<String>) -> HandlerResult {
|
async fn patch(path: Path<String>) -> HandlerResult {
|
||||||
trace!("PATCH Triggered on {}", path);
|
trace!("PATCH Triggered on {}", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(path: Path<String>) -> HandlerResult {
|
async fn delete(path: Path<String>) -> HandlerResult {
|
||||||
trace!("DELETE Triggered on {}", path);
|
trace!("DELETE Triggered on {}", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
@@ -57,35 +57,35 @@ mod routing {
|
|||||||
|
|
||||||
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn put() {
|
async fn put() {
|
||||||
json::expect_200(Method::PUT, &get_core(INSTANCE_EXISTS), "".to_string());
|
json::expect_200(TestRequest::put(), &get_core(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_422(Method::PUT, &get_core(INSTANCE_EXISTS), "".to_string());
|
json::expect_422(TestRequest::put(), &get_core(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_200(Method::PUT, &get_core(INSTANCE_INVALID), "".to_string());
|
json::expect_200(TestRequest::put(), &get_core(INSTANCE_INVALID), "".to_string()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn patch() {
|
async fn patch() {
|
||||||
json::expect_200(Method::PATCH, &get_core(INSTANCE_EXISTS), "".to_string());
|
json::expect_200(TestRequest::patch(), &get_core(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_422(Method::PATCH, &get_core(INSTANCE_EXISTS), "".to_string());
|
json::expect_422(TestRequest::patch(), &get_core(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
expect_404(Method::PATCH, &get_core(INSTANCE_INVALID));
|
expect_404(TestRequest::patch(), &get_core(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn get() {
|
async fn get() {
|
||||||
expect_200(Method::GET, &get_core(INSTANCE_EXISTS));
|
expect_200(TestRequest::get(), &get_core(INSTANCE_EXISTS)).await;
|
||||||
expect_404(Method::GET, &get_core(INSTANCE_INVALID));
|
expect_404(TestRequest::get(), &get_core(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn delete() {
|
async fn delete() {
|
||||||
expect_200(Method::DELETE, &get_core(INSTANCE_EXISTS));
|
expect_200(TestRequest::delete(), &get_core(INSTANCE_EXISTS)).await;
|
||||||
expect_404(Method::DELETE, &get_core(INSTANCE_INVALID));
|
expect_404(TestRequest::delete(), &get_core(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn post() {
|
async fn post() {
|
||||||
expect_405(Method::POST, &get_core(INSTANCE_EXISTS));
|
expect_405(TestRequest::post(), &get_core(INSTANCE_EXISTS)).await;
|
||||||
expect_405(Method::POST, &get_core(INSTANCE_INVALID));
|
expect_405(TestRequest::post(), &get_core(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ use super::web;
|
|||||||
use super::web::Data;
|
use super::web::Data;
|
||||||
use super::web::Json;
|
use super::web::Json;
|
||||||
use super::Core;
|
use super::Core;
|
||||||
|
use super::CoreQueryParameters;
|
||||||
use super::Filters;
|
use super::Filters;
|
||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
use super::SharedState;
|
use super::SharedState;
|
||||||
|
|
||||||
fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
async fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
||||||
trace!("POST '{:?}'", parameters);
|
trace!("POST '{:?}'", parameters);
|
||||||
let context = state
|
let context = state
|
||||||
.read()
|
.read()
|
||||||
@@ -40,17 +41,23 @@ fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> Hand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(filter) => {
|
Some(filter) => {
|
||||||
|
let core_parameters = CoreQueryParameters {
|
||||||
|
db,
|
||||||
|
output_space: space.as_ref().map(String::as_str),
|
||||||
|
threshold_volume: parameters.volume(),
|
||||||
|
view_port: ¶meters.view_port,
|
||||||
|
resolution: parameters.resolution(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let tree = match context.filter(filter) {
|
||||||
|
Err(e) => return error_422(e),
|
||||||
|
Ok(tree) => tree,
|
||||||
|
};
|
||||||
|
|
||||||
// Retrieve the list of core ids.
|
// Retrieve the list of core ids.
|
||||||
let mut results = HashSet::new();
|
let mut results = HashSet::new();
|
||||||
for core in db.core_keys() {
|
for core in db.core_keys() {
|
||||||
match context.filter(
|
match context.execute(&tree, core, &core_parameters) {
|
||||||
filter,
|
|
||||||
core,
|
|
||||||
&space,
|
|
||||||
parameters.volume(),
|
|
||||||
¶meters.view_port,
|
|
||||||
parameters.resolution(),
|
|
||||||
) {
|
|
||||||
Err(e) => return error_422(e),
|
Err(e) => return error_422(e),
|
||||||
Ok(objects) => {
|
Ok(objects) => {
|
||||||
// If the list of SpaceObjects is not empty, add
|
// If the list of SpaceObjects is not empty, add
|
||||||
@@ -59,7 +66,7 @@ fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> Hand
|
|||||||
results.insert(core.to_string());
|
results.insert(core.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format the list or the whole core objects.
|
// Format the list or the whole core objects.
|
||||||
@@ -79,17 +86,17 @@ fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> Hand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put() -> HandlerResult {
|
async fn put() -> HandlerResult {
|
||||||
trace!("PUT Triggered!");
|
trace!("PUT Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch() -> HandlerResult {
|
async fn patch() -> HandlerResult {
|
||||||
trace!("PATCH Triggered!");
|
trace!("PATCH Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete() -> HandlerResult {
|
async fn delete() -> HandlerResult {
|
||||||
trace!("DELETE Triggered!");
|
trace!("DELETE Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
@@ -108,49 +115,47 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
mod routing {
|
mod routing {
|
||||||
use super::super::tests_utils::*;
|
use super::super::tests_utils::*;
|
||||||
|
|
||||||
const COLLECTION: &str = "/cores";
|
|
||||||
|
|
||||||
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn post() {
|
async fn post() {
|
||||||
expect_200(Method::POST, &get_core(""));
|
expect_200(TestRequest::post(), &get_core("")).await;
|
||||||
json::expect_200(Method::POST, &get_core(""), "".to_string());
|
json::expect_200(TestRequest::post(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::POST, &get_core(""), "".to_string());
|
json::expect_422(TestRequest::post(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::POST, &get_core(""));
|
expect_400(TestRequest::post(), &get_core("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn put() {
|
async fn put() {
|
||||||
json::expect_200(Method::PUT, &get_core(""), "".to_string());
|
json::expect_200(TestRequest::put(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::PUT, &get_core(""), "".to_string());
|
json::expect_422(TestRequest::put(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::PUT, &get_core(""));
|
expect_400(TestRequest::put(), &get_core("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn patch() {
|
async fn patch() {
|
||||||
json::expect_200(Method::PATCH, &get_core(""), "".to_string());
|
json::expect_200(TestRequest::patch(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::PATCH, &get_core(""), "".to_string());
|
json::expect_422(TestRequest::patch(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::PATCH, &get_core(""));
|
expect_400(TestRequest::patch(), &get_core("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn delete() {
|
async fn delete() {
|
||||||
json::expect_200(Method::DELETE, &get_core(""), "".to_string());
|
json::expect_200(TestRequest::delete(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::DELETE, &get_core(""), "".to_string());
|
json::expect_422(TestRequest::delete(), &get_core(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::DELETE, &get_core(""));
|
expect_400(TestRequest::delete(), &get_core("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn get() {
|
async fn get() {
|
||||||
expect_405(Method::GET, &get_core(""));
|
expect_405(TestRequest::get(), &get_core("")).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ where
|
|||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
match serde_json::to_string(data) {
|
match serde_json::to_string(data) {
|
||||||
Ok(response) => Ok(Either::A(
|
Ok(response) => Ok(Either::Left(
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.content_type("application/json")
|
.content_type("application/json")
|
||||||
.body(response),
|
.body(response),
|
||||||
@@ -30,7 +30,7 @@ pub fn error_422<S>(reason: S) -> HandlerResult
|
|||||||
where
|
where
|
||||||
S: Debug,
|
S: Debug,
|
||||||
{
|
{
|
||||||
Ok(Either::A(HttpResponse::UnprocessableEntity().body(
|
Ok(Either::Left(HttpResponse::UnprocessableEntity().body(
|
||||||
format!("422 - Unprocessable Entity:\n{:?}", reason),
|
format!("422 - Unprocessable Entity:\n{:?}", reason),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ where
|
|||||||
// error_400()
|
// error_400()
|
||||||
//}
|
//}
|
||||||
|
|
||||||
pub fn page_404() -> HandlerResult {
|
pub async fn page_404() -> HandlerResult {
|
||||||
trace!("404 Triggered!");
|
trace!("404 Triggered!");
|
||||||
error_404()
|
error_404()
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ pub fn page_404() -> HandlerResult {
|
|||||||
// error_405()
|
// error_405()
|
||||||
//}
|
//}
|
||||||
|
|
||||||
pub fn api(path: Path<String>) -> Result<NamedFile, Error> {
|
pub async fn api(path: Path<String>) -> Result<NamedFile, Error> {
|
||||||
trace!("api/{} Triggered!", path);
|
trace!("api/{} Triggered!", path);
|
||||||
|
|
||||||
match NamedFile::open(format!("static/api/{}", path).as_str()) {
|
match NamedFile::open(format!("static/api/{}", path).as_str()) {
|
||||||
@@ -71,7 +71,7 @@ pub fn api(path: Path<String>) -> Result<NamedFile, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn static_file(path: Path<String>) -> Result<NamedFile, Error> {
|
pub async fn static_file(path: Path<String>) -> Result<NamedFile, Error> {
|
||||||
trace!("static/{} Triggered!", path);
|
trace!("static/{} Triggered!", path);
|
||||||
|
|
||||||
match NamedFile::open(format!("static/{}", path).as_str()) {
|
match NamedFile::open(format!("static/{}", path).as_str()) {
|
||||||
@@ -85,10 +85,9 @@ pub fn static_file(path: Path<String>) -> Result<NamedFile, Error> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::super::tests_utils::*;
|
use super::super::tests_utils::*;
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn page_400() {
|
async fn page_400() {
|
||||||
// expect_400(Method::PATCH, get_core(INSTANCE_INVALID));
|
expect_400(TestRequest::patch(), &get_core(INVALID_CORE)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use actix_web::HttpResponse;
|
|||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
|
|
||||||
fn error(code: StatusCode) -> HandlerResult {
|
fn error(code: StatusCode) -> HandlerResult {
|
||||||
Ok(Either::A(HttpResponse::build(code).finish()))
|
Ok(Either::Left(HttpResponse::build(code).finish()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error_400() -> HandlerResult {
|
pub fn error_400() -> HandlerResult {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use super::HandlerResult;
|
|||||||
fn error(code: StatusCode) -> HandlerResult {
|
fn error(code: StatusCode) -> HandlerResult {
|
||||||
let path = format!("static/errors/{}.html", u16::from(code));
|
let path = format!("static/errors/{}.html", u16::from(code));
|
||||||
|
|
||||||
Ok(Either::B(NamedFile::open(path)?.set_status_code(code)))
|
Ok(Either::Right(NamedFile::open(path)?.set_status_code(code)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error_400() -> HandlerResult {
|
pub fn error_400() -> HandlerResult {
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ use actix_web::HttpResponse;
|
|||||||
use actix_web::HttpServer;
|
use actix_web::HttpServer;
|
||||||
use mercator_db::space::Shape;
|
use mercator_db::space::Shape;
|
||||||
use mercator_db::storage::model;
|
use mercator_db::storage::model;
|
||||||
use mercator_db::storage::model::v2::to_spatial_objects;
|
use mercator_db::storage::model::v2::from_properties_by_spaces;
|
||||||
|
use mercator_db::storage::model::v2::from_spaces_by_properties;
|
||||||
use mercator_db::CoreQueryParameters;
|
use mercator_db::CoreQueryParameters;
|
||||||
pub use mercator_db::DataBase;
|
pub use mercator_db::DataBase;
|
||||||
use mercator_db::Properties;
|
use mercator_db::Properties;
|
||||||
@@ -64,13 +65,10 @@ impl Filters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn ids_only(&self) -> bool {
|
pub fn ids_only(&self) -> bool {
|
||||||
match self.ids_only {
|
self.ids_only.unwrap_or(true)
|
||||||
None => true, // Defaults to true
|
|
||||||
Some(b) => b,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn space(&self, db: &mercator_db::DataBase) -> Result<&Option<String>, HandlerResult> {
|
pub fn space(&self, db: &DataBase) -> Result<&Option<String>, HandlerResult> {
|
||||||
if let Some(space_id) = &self.space {
|
if let Some(space_id) = &self.space {
|
||||||
if !db.space_keys().contains(&space_id.to_string()) {
|
if !db.space_keys().contains(&space_id.to_string()) {
|
||||||
return Err(error_422(format!(
|
return Err(error_422(format!(
|
||||||
@@ -87,10 +85,9 @@ impl Filters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn volume(&self) -> Option<f64> {
|
pub fn volume(&self) -> Option<f64> {
|
||||||
match &self.view_port {
|
self.view_port.as_ref().map(|(low, high)|
|
||||||
None => None,
|
Shape::BoundingBox(low.into(), high.into()).volume()
|
||||||
Some((low, high)) => Some(Shape::BoundingBox(low.into(), high.into()).volume()),
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +111,7 @@ impl From<&mercator_db::Core> for Core {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From: https://stackoverflow.com/a/52367953
|
// From: https://stackoverflow.com/a/52367953
|
||||||
fn into_static<S>(s: S) -> &'static str
|
pub fn into_static<S>(s: S) -> &'static str
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
@@ -142,10 +139,8 @@ fn config_v1(cfg: &mut web::ServiceConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(cfg: &mut web::ServiceConfig) {
|
pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
let prefix;
|
let prefix = match std::env::var("MERCATOR_BASE") {
|
||||||
|
Ok(val) => val,
|
||||||
match std::env::var("MERCATOR_BASE") {
|
|
||||||
Ok(val) => prefix = val,
|
|
||||||
Err(val) => {
|
Err(val) => {
|
||||||
error!("Could not fetch {} : `{}`", "MERCATOR_BASE", val);
|
error!("Could not fetch {} : `{}`", "MERCATOR_BASE", val);
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -160,7 +155,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
|||||||
|
|
||||||
pub fn get_cors() -> Cors {
|
pub fn get_cors() -> Cors {
|
||||||
// Setup CORS support.
|
// Setup CORS support.
|
||||||
let mut cors = Cors::new();
|
let mut cors = Cors::default();
|
||||||
|
|
||||||
match std::env::var("MERCATOR_ALLOWED_ORIGINS") {
|
match std::env::var("MERCATOR_ALLOWED_ORIGINS") {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
@@ -189,62 +184,42 @@ pub fn get_cors() -> Cors {
|
|||||||
macro_rules! get_app {
|
macro_rules! get_app {
|
||||||
($state:expr) => {
|
($state:expr) => {
|
||||||
App::new()
|
App::new()
|
||||||
.register_data($state.clone())
|
.app_data($state.clone())
|
||||||
.wrap(middleware::Logger::new(
|
.wrap(middleware::Logger::new(
|
||||||
r#"%a "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T[s] %D[ms]"#,
|
r#"%a "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T[s] %D[ms]"#,
|
||||||
))
|
))
|
||||||
.wrap(middleware::Compress::default())
|
.wrap(middleware::Compress::default())
|
||||||
.wrap(get_cors())
|
.wrap(get_cors())
|
||||||
.configure(config)
|
.configure(config)
|
||||||
.default_service(
|
.default_service(web::to(page_404))
|
||||||
web::resource("/")
|
|
||||||
// 404 for GET request
|
|
||||||
.route(web::to(page_404)),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(host: &str, port: u16, state: Data<RwLock<SharedState>>) {
|
pub async fn run(host: &str, port: u16, state: Data<RwLock<SharedState>>) -> std::io::Result<()> {
|
||||||
info!("Starting http server: {}:{}", host, port);
|
info!("Starting http server: {}:{}", host, port);
|
||||||
|
|
||||||
// Create & run the server.
|
// Create & run the server.
|
||||||
match HttpServer::new(move || get_app!(state))
|
HttpServer::new(move || get_app!(state))
|
||||||
.bind(format!("{}:{}", host, port))
|
.bind(format!("{}:{}", host, port))?
|
||||||
.unwrap_or_else(|e| panic!("Failed to bind to `{}:{}`: {}", host, port, e))
|
|
||||||
.run()
|
.run()
|
||||||
{
|
.await
|
||||||
Ok(_) => info!("Server Stopped!"),
|
|
||||||
Err(e) => error!("Error running the server: {}", e),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests_utils {
|
mod tests_utils {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
//use actix_server_config::ServerConfig;
|
|
||||||
//use actix_service::IntoNewService;
|
|
||||||
//use actix_service::NewService;
|
|
||||||
use actix_service::Service;
|
|
||||||
//use actix_web::dev::ServiceResponse;
|
|
||||||
use actix_web::test;
|
use actix_web::test;
|
||||||
//use actix_web::test::TestRequest;
|
pub use actix_web::test::TestRequest;
|
||||||
use mercator_db::DataBase;
|
|
||||||
|
|
||||||
pub const CORE_ID: &str = "10k";
|
pub const CORE_FILE: &str = "10k.index";
|
||||||
|
pub const CORE_ID: [&str; 1] = ["10k"];
|
||||||
|
|
||||||
pub const PREFIX: &str = "/spatial-search";
|
pub const PREFIX: &str = "/spatial-search-test";
|
||||||
pub const CORE: &str = "/10k";
|
pub const CORE: &str = "/10k";
|
||||||
|
pub const INVALID_CORE: &str = "/INVALID_CORE";
|
||||||
pub const SPACE: &str = "/std";
|
pub const SPACE: &str = "/std";
|
||||||
pub const SPATIAL_OBJECT: &str = "/oid0.44050628835072825";
|
pub const SPATIAL_OBJECT: &str = "/oid0.44050628835072825";
|
||||||
|
|
||||||
pub enum Method {
|
|
||||||
GET,
|
|
||||||
POST,
|
|
||||||
PUT,
|
|
||||||
PATCH,
|
|
||||||
DELETE,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_path(path: &str) -> String {
|
pub fn get_path(path: &str) -> String {
|
||||||
format!("{}{}", PREFIX, path)
|
format!("{}{}", PREFIX, path)
|
||||||
@@ -262,113 +237,113 @@ mod tests_utils {
|
|||||||
format!("{}{}{}", get_core(CORE), "/spatial_objects", name)
|
format!("{}{}{}", get_core(CORE), "/spatial_objects", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect(method: Method, path: &str, code: http::StatusCode) {
|
macro_rules! expect_code {
|
||||||
|
($request:expr, $path:expr, $code:expr) => {
|
||||||
|
{
|
||||||
std::env::set_var("MERCATOR_BASE", PREFIX);
|
std::env::set_var("MERCATOR_BASE", PREFIX);
|
||||||
|
let db = DataBase::load(&[CORE_FILE]).unwrap();
|
||||||
let mut app = test::init_service(get_app!(Data::new(RwLock::new(SharedState::new(
|
let app = test::init_service(
|
||||||
DataBase::load(CORE_ID).unwrap()
|
get_app!(Data::new(RwLock::new(SharedState::new(db))))).await;
|
||||||
)))));
|
let request = $request.uri(&$path).to_request();
|
||||||
|
let response = test::call_service(&app, request).await;
|
||||||
let request = match method {
|
assert_eq!(response.status(), $code);
|
||||||
Method::GET => test::TestRequest::get(),
|
// let json = test::read_body(response).await;
|
||||||
Method::POST => test::TestRequest::post(),
|
// println!("BODY: {:?}", json);
|
||||||
Method::PUT => test::TestRequest::put(),
|
}
|
||||||
Method::PATCH => test::TestRequest::patch(),
|
|
||||||
Method::DELETE => test::TestRequest::delete(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let request = request.uri(&path).to_request();
|
|
||||||
let response = test::block_on(app.call(request)).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(response.status(), code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_200(method: Method, path: &str) {
|
/// Checks status code OK
|
||||||
expect(method, path, http::StatusCode::OK);
|
pub async fn expect_200(method: TestRequest, path: &str) {
|
||||||
|
expect_code!(method, path, StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_400(method: Method, path: &str) {
|
/// Checks status code BAD_REQUEST
|
||||||
expect(method, path, http::StatusCode::BAD_REQUEST);
|
pub async fn expect_400(method: TestRequest, path: &str) {
|
||||||
|
expect_code!(method, path, StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_404(method: Method, path: &str) {
|
/// Checks status code NOT_FOUND
|
||||||
expect(method, path, http::StatusCode::NOT_FOUND);
|
pub async fn expect_404(method: TestRequest, path: &str) {
|
||||||
|
expect_code!(method, path, StatusCode::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_405(method: Method, path: &str) {
|
/// Checks status code METHOD_NOT_ALLOWED
|
||||||
expect(method, path, http::StatusCode::METHOD_NOT_ALLOWED);
|
pub async fn expect_405(method: TestRequest, path: &str) {
|
||||||
|
expect_code!(method, path, StatusCode::METHOD_NOT_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_422(method: Method, path: &str) {
|
/// Checks status code UNPROCESSABLE_ENTITY
|
||||||
expect(method, path, http::StatusCode::UNPROCESSABLE_ENTITY);
|
pub async fn expect_422(method: TestRequest, path: &str) {
|
||||||
|
expect_code!(method, path, StatusCode::UNPROCESSABLE_ENTITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod json {
|
pub mod json {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn expect_200(method: Method, path: &str, json: String) {
|
pub async fn expect_200(method: TestRequest, path: &str, _json: String) {
|
||||||
expect(method, path, http::StatusCode::OK);
|
expect_code!(method, path, StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_404(method: Method, path: &str, json: String) {
|
pub async fn expect_404(method: TestRequest, path: &str, _json: String) {
|
||||||
expect(method, path, http::StatusCode::NOT_FOUND);
|
expect_code!(method, path, StatusCode::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_422(method: Method, path: &str, json: String) {
|
pub async fn expect_422(method: TestRequest, path: &str, _json: String) {
|
||||||
expect(method, path, http::StatusCode::UNPROCESSABLE_ENTITY);
|
expect_code!(method, path, StatusCode::UNPROCESSABLE_ENTITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod routing {
|
mod routing {
|
||||||
|
use super::tests_utils::*;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
|
|
||||||
use super::tests_utils::*;
|
#[ignore] // Don't know how to make work the catch_unwind in an async context
|
||||||
|
#[actix_web::test]
|
||||||
#[test]
|
async fn default_no_path() {
|
||||||
fn default_no_path() {
|
|
||||||
// _FIXME: Currently the string is validated by the URI constructor which
|
// _FIXME: Currently the string is validated by the URI constructor which
|
||||||
// simply unwraps, thus we have to resort to this ugly workaround.
|
// simply unwraps, thus we have to resort to this ugly workaround.
|
||||||
// The goal is to catch if that behavior changes in the future.
|
// The goal is to catch if that behavior changes in the future.
|
||||||
let result = panic::catch_unwind(|| {
|
let result = panic::catch_unwind(|| {
|
||||||
expect_404(Method::GET, "");
|
//expect_404(TestRequest::get(), "").await;
|
||||||
});
|
});
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn default_slash() {
|
async fn default_slash() {
|
||||||
// We have to manually URL-encode spaces.
|
// We have to manually URL-encode spaces.
|
||||||
expect_404(Method::GET, "/");
|
expect_404(TestRequest::get(), "/").await;
|
||||||
expect_404(Method::GET, "//");
|
expect_404(TestRequest::get(), "//").await;
|
||||||
expect_404(Method::GET, "/%20/");
|
expect_404(TestRequest::get(), "/%20/").await;
|
||||||
expect_404(Method::GET, "/%20//");
|
expect_404(TestRequest::get(), "/%20//").await;
|
||||||
expect_404(Method::GET, "//%20");
|
expect_404(TestRequest::get(), "//%20").await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn default_invalid_prefix() {
|
async fn default_invalid_prefix() {
|
||||||
expect_404(Method::GET, "/test");
|
expect_404(TestRequest::get(), "/test").await;
|
||||||
expect_404(Method::GET, &format!("{}test", PREFIX));
|
expect_404(TestRequest::get(), &format!("{}test", PREFIX)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn default_prefix_no_slash() {
|
async fn default_prefix_no_slash() {
|
||||||
expect_404(Method::PUT, PREFIX);
|
expect_404(TestRequest::put(), PREFIX).await;
|
||||||
expect_404(Method::GET, PREFIX);
|
expect_404(TestRequest::get(), PREFIX).await;
|
||||||
expect_404(Method::POST, PREFIX);
|
expect_404(TestRequest::post(), PREFIX).await;
|
||||||
expect_404(Method::PATCH, PREFIX);
|
expect_404(TestRequest::patch(), PREFIX).await;
|
||||||
expect_404(Method::DELETE, PREFIX);
|
expect_404(TestRequest::delete(), PREFIX).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn default_prefix_final_slash() {
|
async fn default_prefix_final_slash() {
|
||||||
let path = &format!("{}/", PREFIX);
|
let path = &format!("{}/", PREFIX);
|
||||||
expect_404(Method::PUT, path);
|
expect_404(TestRequest::put(), path).await;
|
||||||
expect_404(Method::GET, path);
|
expect_404(TestRequest::get(), path).await;
|
||||||
expect_404(Method::POST, path);
|
expect_404(TestRequest::post(), path).await;
|
||||||
expect_404(Method::PATCH, path);
|
expect_404(TestRequest::patch(), path).await;
|
||||||
expect_404(Method::DELETE, path);
|
expect_404(TestRequest::delete(), path).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ use super::web::Path;
|
|||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
use super::SharedState;
|
use super::SharedState;
|
||||||
|
|
||||||
fn put(path: Path<String>) -> HandlerResult {
|
async fn put(path: Path<String>) -> HandlerResult {
|
||||||
trace!("POST '{:?}'", path);
|
trace!("POST '{:?}'", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get((path, state): (Path<String>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
async fn get((path, state): (Path<String>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
||||||
trace!("GET '{:?}'", path);
|
trace!("GET '{:?}'", path);
|
||||||
let name = path.to_string();
|
let name = path.to_string();
|
||||||
let context = state
|
let context = state
|
||||||
@@ -31,12 +31,12 @@ fn get((path, state): (Path<String>, Data<RwLock<SharedState>>)) -> HandlerResul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch(path: Path<String>) -> HandlerResult {
|
async fn patch(path: Path<String>) -> HandlerResult {
|
||||||
trace!("PATCH Triggered on {}", path);
|
trace!("PATCH Triggered on {}", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(path: Path<String>) -> HandlerResult {
|
async fn delete(path: Path<String>) -> HandlerResult {
|
||||||
trace!("DELETE Triggered on {}", path);
|
trace!("DELETE Triggered on {}", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
@@ -60,35 +60,35 @@ mod routing {
|
|||||||
|
|
||||||
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn put() {
|
async fn put() {
|
||||||
json::expect_200(Method::PUT, &get_space(INSTANCE_EXISTS), "".to_string());
|
json::expect_200(TestRequest::put(), &get_space(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_422(Method::PUT, &get_space(INSTANCE_EXISTS), "".to_string());
|
json::expect_422(TestRequest::put(), &get_space(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_200(Method::PUT, &get_space(INSTANCE_INVALID), "".to_string());
|
json::expect_200(TestRequest::put(), &get_space(INSTANCE_INVALID), "".to_string()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn patch() {
|
async fn patch() {
|
||||||
json::expect_200(Method::PATCH, &get_space(INSTANCE_EXISTS), "".to_string());
|
json::expect_200(TestRequest::patch(), &get_space(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_422(Method::PATCH, &get_space(INSTANCE_EXISTS), "".to_string());
|
json::expect_422(TestRequest::patch(), &get_space(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
expect_400(Method::PATCH, &get_space(INSTANCE_INVALID));
|
expect_400(TestRequest::patch(), &get_space(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn get() {
|
async fn get() {
|
||||||
expect_200(Method::GET, &get_space(INSTANCE_EXISTS));
|
expect_200(TestRequest::get(), &get_space(INSTANCE_EXISTS)).await;
|
||||||
expect_404(Method::GET, &get_space(INSTANCE_INVALID));
|
expect_404(TestRequest::get(), &get_space(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn delete() {
|
async fn delete() {
|
||||||
expect_200(Method::DELETE, &get_space(INSTANCE_EXISTS));
|
expect_200(TestRequest::delete(), &get_space(INSTANCE_EXISTS)).await;
|
||||||
expect_404(Method::DELETE, &get_space(INSTANCE_INVALID));
|
expect_404(TestRequest::delete(), &get_space(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn post() {
|
async fn post() {
|
||||||
expect_405(Method::POST, &get_space(INSTANCE_EXISTS));
|
expect_405(TestRequest::post(), &get_space(INSTANCE_EXISTS)).await;
|
||||||
expect_405(Method::POST, &get_space(INSTANCE_INVALID));
|
expect_405(TestRequest::post(), &get_space(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ use super::ok_200;
|
|||||||
use super::web;
|
use super::web;
|
||||||
use super::web::Data;
|
use super::web::Data;
|
||||||
use super::web::Json;
|
use super::web::Json;
|
||||||
|
use super::CoreQueryParameters;
|
||||||
use super::Filters;
|
use super::Filters;
|
||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
use super::SharedState;
|
use super::SharedState;
|
||||||
|
|
||||||
fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
async fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
||||||
trace!("POST '{:?}'", parameters);
|
trace!("POST '{:?}'", parameters);
|
||||||
let context = state
|
let context = state
|
||||||
.read()
|
.read()
|
||||||
@@ -43,15 +44,20 @@ fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> Hand
|
|||||||
// Retrieve the list of space ids.
|
// Retrieve the list of space ids.
|
||||||
let mut results = HashSet::new();
|
let mut results = HashSet::new();
|
||||||
|
|
||||||
|
let core_parameters = CoreQueryParameters {
|
||||||
|
db: context.db(),
|
||||||
|
output_space: space.as_ref().map(String::as_str),
|
||||||
|
threshold_volume: parameters.volume(),
|
||||||
|
view_port: ¶meters.view_port,
|
||||||
|
resolution: parameters.resolution(),
|
||||||
|
};
|
||||||
|
let tree = match context.filter(filter) {
|
||||||
|
Err(e) => return error_422(e),
|
||||||
|
Ok(bag) => bag,
|
||||||
|
};
|
||||||
|
|
||||||
for core in db.core_keys() {
|
for core in db.core_keys() {
|
||||||
match context.filter(
|
match context.execute(&tree, core, &core_parameters) {
|
||||||
filter,
|
|
||||||
core,
|
|
||||||
&space,
|
|
||||||
parameters.volume(),
|
|
||||||
¶meters.view_port,
|
|
||||||
parameters.resolution(),
|
|
||||||
) {
|
|
||||||
Err(e) => return error_422(e),
|
Err(e) => return error_422(e),
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
// We have a list of SpaceObjects, so extract
|
// We have a list of SpaceObjects, so extract
|
||||||
@@ -70,7 +76,7 @@ fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> Hand
|
|||||||
ok_200(
|
ok_200(
|
||||||
&results
|
&results
|
||||||
.drain()
|
.drain()
|
||||||
.map(|id| match db.space(&id) {
|
.map(|id| match db.space(id) {
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
Ok(x) => Some(model::Space::from(x)),
|
Ok(x) => Some(model::Space::from(x)),
|
||||||
})
|
})
|
||||||
@@ -83,17 +89,17 @@ fn post((parameters, state): (Json<Filters>, Data<RwLock<SharedState>>)) -> Hand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put() -> HandlerResult {
|
async fn put() -> HandlerResult {
|
||||||
trace!("PUT Triggered!");
|
trace!("PUT Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch() -> HandlerResult {
|
async fn patch() -> HandlerResult {
|
||||||
trace!("PATCH Triggered!");
|
trace!("PATCH Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete() -> HandlerResult {
|
async fn delete() -> HandlerResult {
|
||||||
trace!("DELETE Triggered!");
|
trace!("DELETE Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
@@ -114,45 +120,45 @@ mod routing {
|
|||||||
|
|
||||||
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn post() {
|
async fn post() {
|
||||||
expect_200(Method::POST, &get_space(""));
|
expect_200(TestRequest::post(), &get_space("")).await;
|
||||||
json::expect_200(Method::POST, &get_space(""), "".to_string());
|
json::expect_200(TestRequest::post(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::POST, &get_space(""), "".to_string());
|
json::expect_422(TestRequest::post(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::POST, &get_space(""));
|
expect_400(TestRequest::post(), &get_space("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn put() {
|
async fn put() {
|
||||||
json::expect_200(Method::PUT, &get_space(""), "".to_string());
|
json::expect_200(TestRequest::put(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::PUT, &get_space(""), "".to_string());
|
json::expect_422(TestRequest::put(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::PUT, &get_space(""));
|
expect_400(TestRequest::put(), &get_space("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn patch() {
|
async fn patch() {
|
||||||
json::expect_200(Method::PATCH, &get_space(""), "".to_string());
|
json::expect_200(TestRequest::patch(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::PATCH, &get_space(""), "".to_string());
|
json::expect_422(TestRequest::patch(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::PATCH, &get_space(""));
|
expect_400(TestRequest::patch(), &get_space("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn delete() {
|
async fn delete() {
|
||||||
json::expect_200(Method::DELETE, &get_space(""), "".to_string());
|
json::expect_200(TestRequest::delete(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::DELETE, &get_space(""), "".to_string());
|
json::expect_422(TestRequest::delete(), &get_space(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::DELETE, &get_space(""));
|
expect_400(TestRequest::delete(), &get_space("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn get() {
|
async fn get() {
|
||||||
expect_405(Method::GET, &get_space(""));
|
expect_405(TestRequest::get(), &get_space("")).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use std::sync::RwLock;
|
|||||||
|
|
||||||
use super::error_400;
|
use super::error_400;
|
||||||
use super::error_404;
|
use super::error_404;
|
||||||
|
use super::from_properties_by_spaces;
|
||||||
use super::ok_200;
|
use super::ok_200;
|
||||||
use super::to_spatial_objects;
|
|
||||||
use super::web;
|
use super::web;
|
||||||
use super::web::Data;
|
use super::web::Data;
|
||||||
use super::web::Path;
|
use super::web::Path;
|
||||||
@@ -11,17 +11,16 @@ use super::CoreQueryParameters;
|
|||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
use super::Properties;
|
use super::Properties;
|
||||||
use super::SharedState;
|
use super::SharedState;
|
||||||
|
use mercator_db::{IterObjects, IterObjectsBySpaces};
|
||||||
|
|
||||||
fn put(path: Path<String>) -> HandlerResult {
|
async fn put(path: Path<String>) -> HandlerResult {
|
||||||
trace!("PUT '{:?}'", path);
|
trace!("PUT '{:?}'", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get((path, state): (Path<(String, String)>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
async fn get((path, state): (Path<(String, String)>, Data<RwLock<SharedState>>)) -> HandlerResult {
|
||||||
trace!("GET '{:?}'", path);
|
trace!("GET '{:?}'", path);
|
||||||
let (core, id) = path.into_inner();
|
let (core, id) = path.into_inner();
|
||||||
let core = core;
|
|
||||||
let id = id;
|
|
||||||
let context = state
|
let context = state
|
||||||
.read()
|
.read()
|
||||||
.unwrap_or_else(|e| panic!("Can't acquire read lock of the database: {}", e));
|
.unwrap_or_else(|e| panic!("Can't acquire read lock of the database: {}", e));
|
||||||
@@ -39,20 +38,18 @@ fn get((path, state): (Path<(String, String)>, Data<RwLock<SharedState>>)) -> Ha
|
|||||||
|
|
||||||
match db.core(&core) {
|
match db.core(&core) {
|
||||||
Ok(core) => match core.get_by_id(¶meters, &id) {
|
Ok(core) => match core.get_by_id(¶meters, &id) {
|
||||||
Ok(objects) => {
|
Ok(positions_by_spaces) => {
|
||||||
let value = Properties::Feature(id);
|
let value = Properties::Feature(id);
|
||||||
let tmp = objects
|
let tmp: IterObjectsBySpaces = positions_by_spaces
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(space, positions)| {
|
.map(|(space, positions)| {
|
||||||
let shapes = positions
|
let objects: IterObjects =
|
||||||
.into_iter()
|
Box::new(positions.map(|position| (position, &value)));
|
||||||
.map(|position| (position, &value))
|
(space, objects)
|
||||||
.collect();
|
|
||||||
(space, shapes)
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let results = to_spatial_objects(tmp);
|
let results = from_properties_by_spaces(tmp).collect::<Vec<_>>();
|
||||||
|
|
||||||
if results.is_empty() {
|
if results.is_empty() {
|
||||||
error_404()
|
error_404()
|
||||||
@@ -66,12 +63,12 @@ fn get((path, state): (Path<(String, String)>, Data<RwLock<SharedState>>)) -> Ha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch(path: Path<String>) -> HandlerResult {
|
async fn patch(path: Path<String>) -> HandlerResult {
|
||||||
trace!("PATCH Triggered on {}", path);
|
trace!("PATCH Triggered on {}", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(path: Path<String>) -> HandlerResult {
|
async fn delete(path: Path<String>) -> HandlerResult {
|
||||||
trace!("DELETE Triggered on {}", path);
|
trace!("DELETE Triggered on {}", path);
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
@@ -95,35 +92,35 @@ mod routing {
|
|||||||
|
|
||||||
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn put() {
|
async fn put() {
|
||||||
json::expect_200(Method::PUT, &get_objects(INSTANCE_EXISTS), "".to_string());
|
json::expect_200(TestRequest::put(), &get_objects(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_422(Method::PUT, &get_objects(INSTANCE_EXISTS), "".to_string());
|
json::expect_422(TestRequest::put(), &get_objects(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_200(Method::PUT, &get_objects(INSTANCE_INVALID), "".to_string());
|
json::expect_200(TestRequest::put(), &get_objects(INSTANCE_INVALID), "".to_string()).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn patch() {
|
async fn patch() {
|
||||||
json::expect_200(Method::PATCH, &get_objects(INSTANCE_EXISTS), "".to_string());
|
json::expect_200(TestRequest::patch(), &get_objects(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
json::expect_422(Method::PATCH, &get_objects(INSTANCE_EXISTS), "".to_string());
|
json::expect_422(TestRequest::patch(), &get_objects(INSTANCE_EXISTS), "".to_string()).await;
|
||||||
expect_400(Method::PATCH, &get_objects(INSTANCE_INVALID));
|
expect_400(TestRequest::patch(), &get_objects(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn get() {
|
async fn get() {
|
||||||
expect_200(Method::GET, &get_objects(INSTANCE_EXISTS));
|
expect_200(TestRequest::get(), &get_objects(INSTANCE_EXISTS)).await;
|
||||||
expect_404(Method::GET, &get_objects(INSTANCE_INVALID));
|
expect_404(TestRequest::get(), &get_objects(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn delete() {
|
async fn delete() {
|
||||||
expect_200(Method::DELETE, &get_objects(INSTANCE_EXISTS));
|
expect_200(TestRequest::delete(), &get_objects(INSTANCE_EXISTS)).await;
|
||||||
expect_404(Method::DELETE, &get_objects(INSTANCE_INVALID));
|
expect_404(TestRequest::delete(), &get_objects(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn post() {
|
async fn post() {
|
||||||
expect_405(Method::POST, &get_objects(INSTANCE_EXISTS));
|
expect_405(TestRequest::post(), &get_objects(INSTANCE_EXISTS)).await;
|
||||||
expect_405(Method::POST, &get_objects(INSTANCE_INVALID));
|
expect_405(TestRequest::post(), &get_objects(INSTANCE_INVALID)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use super::error_400;
|
use super::error_400;
|
||||||
use super::error_404;
|
use super::error_404;
|
||||||
use super::error_422;
|
use super::error_422;
|
||||||
|
use super::from_properties_by_spaces;
|
||||||
|
use super::from_spaces_by_properties;
|
||||||
use super::ok_200;
|
use super::ok_200;
|
||||||
use super::to_spatial_objects;
|
|
||||||
use super::web;
|
use super::web;
|
||||||
use super::web::Data;
|
use super::web::Data;
|
||||||
use super::web::Json;
|
use super::web::Json;
|
||||||
@@ -16,7 +16,7 @@ use super::Filters;
|
|||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
use super::SharedState;
|
use super::SharedState;
|
||||||
|
|
||||||
fn post(
|
async fn post(
|
||||||
(core_id, parameters, state): (Path<String>, Json<Filters>, Data<RwLock<SharedState>>),
|
(core_id, parameters, state): (Path<String>, Json<Filters>, Data<RwLock<SharedState>>),
|
||||||
) -> HandlerResult {
|
) -> HandlerResult {
|
||||||
trace!("POST '{:?}', {:?}", parameters, core_id);
|
trace!("POST '{:?}', {:?}", parameters, core_id);
|
||||||
@@ -32,13 +32,15 @@ fn post(
|
|||||||
Err(e) => e,
|
Err(e) => e,
|
||||||
Ok(space) => match parameters.filters() {
|
Ok(space) => match parameters.filters() {
|
||||||
None => {
|
None => {
|
||||||
let mut results = HashMap::new();
|
|
||||||
for property in core.keys().iter() {
|
|
||||||
results.insert(property.id(), property);
|
|
||||||
}
|
|
||||||
|
|
||||||
if parameters.ids_only() {
|
if parameters.ids_only() {
|
||||||
ok_200(&results.drain().map(|(k, _)| k).collect::<Vec<_>>())
|
// keys() contains unique values only.
|
||||||
|
let ids = core
|
||||||
|
.keys()
|
||||||
|
.iter()
|
||||||
|
.map(|properties| properties.id())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
ok_200(&ids)
|
||||||
} else {
|
} else {
|
||||||
let core_parameters = CoreQueryParameters {
|
let core_parameters = CoreQueryParameters {
|
||||||
db,
|
db,
|
||||||
@@ -48,40 +50,33 @@ fn post(
|
|||||||
resolution: parameters.resolution(),
|
resolution: parameters.resolution(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut objects = vec![];
|
let objects_by_spaces =
|
||||||
for (id, properties) in results.drain() {
|
Box::new(core.keys().iter().filter_map(|property| {
|
||||||
match core.get_by_id(&core_parameters, id) {
|
match core.get_by_id(&core_parameters, property.id()) {
|
||||||
Err(_) => (), // FIXME: Return error ?
|
Err(_) => None, // FIXME: Return error ?
|
||||||
Ok(r) => {
|
Ok(positions_by_spaces) => {
|
||||||
let mut tmp = r
|
Some((property, positions_by_spaces))
|
||||||
.into_iter()
|
|
||||||
.map(|(space, positions)| {
|
|
||||||
let shapes = positions
|
|
||||||
.into_iter()
|
|
||||||
.map(|position| (position, properties))
|
|
||||||
.collect();
|
|
||||||
(space, shapes)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
objects.append(&mut tmp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
|
ok_200(&from_spaces_by_properties(objects_by_spaces).collect::<Vec<_>>())
|
||||||
let objects = to_spatial_objects(objects);
|
|
||||||
|
|
||||||
ok_200(&objects)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(filter) => {
|
Some(filter) => {
|
||||||
match context.filter(
|
let core_parameters = CoreQueryParameters {
|
||||||
filter,
|
db,
|
||||||
&core_id,
|
output_space: space.as_ref().map(String::as_str),
|
||||||
space,
|
threshold_volume: parameters.volume(),
|
||||||
parameters.volume(),
|
view_port: ¶meters.view_port,
|
||||||
¶meters.view_port,
|
resolution: parameters.resolution(),
|
||||||
parameters.resolution(),
|
};
|
||||||
) {
|
|
||||||
|
let tree = match context.filter(filter) {
|
||||||
|
Err(e) => return error_422(e),
|
||||||
|
Ok(bag) => bag,
|
||||||
|
};
|
||||||
|
|
||||||
|
let r = match context.execute(&tree, &core_id, &core_parameters) {
|
||||||
Err(e) => error_422(e),
|
Err(e) => error_422(e),
|
||||||
Ok(objects) => {
|
Ok(objects) => {
|
||||||
if parameters.ids_only() {
|
if parameters.ids_only() {
|
||||||
@@ -94,29 +89,29 @@ fn post(
|
|||||||
|
|
||||||
ok_200(&uniques.drain().collect::<Vec<_>>())
|
ok_200(&uniques.drain().collect::<Vec<_>>())
|
||||||
} else {
|
} else {
|
||||||
let objects = to_spatial_objects(objects);
|
ok_200(&from_properties_by_spaces(objects).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ok_200(&objects)
|
r
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put() -> HandlerResult {
|
async fn put() -> HandlerResult {
|
||||||
trace!("PUT Triggered!");
|
trace!("PUT Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch() -> HandlerResult {
|
async fn patch() -> HandlerResult {
|
||||||
trace!("PATCH Triggered!");
|
trace!("PATCH Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete() -> HandlerResult {
|
async fn delete() -> HandlerResult {
|
||||||
trace!("DELETE Triggered!");
|
trace!("DELETE Triggered!");
|
||||||
error_400()
|
error_400()
|
||||||
}
|
}
|
||||||
@@ -137,45 +132,45 @@ mod routing {
|
|||||||
|
|
||||||
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
// FIXME: Add Body to request to see difference between (in)valid bodied requests
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn post() {
|
async fn post() {
|
||||||
expect_200(Method::POST, &get_objects(""));
|
expect_200(TestRequest::post(), &get_objects("")).await;
|
||||||
json::expect_200(Method::POST, &get_objects(""), "".to_string());
|
json::expect_200(TestRequest::post(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::POST, &get_objects(""), "".to_string());
|
json::expect_422(TestRequest::post(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::POST, &get_objects(""));
|
expect_400(TestRequest::post(), &get_objects("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn put() {
|
async fn put() {
|
||||||
json::expect_200(Method::PUT, &get_objects(""), "".to_string());
|
json::expect_200(TestRequest::put(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::PUT, &get_objects(""), "".to_string());
|
json::expect_422(TestRequest::put(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::PUT, &get_objects(""));
|
expect_400(TestRequest::put(), &get_objects("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn patch() {
|
async fn patch() {
|
||||||
json::expect_200(Method::PATCH, &get_objects(""), "".to_string());
|
json::expect_200(TestRequest::patch(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::PATCH, &get_objects(""), "".to_string());
|
json::expect_422(TestRequest::patch(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::PATCH, &get_objects(""));
|
expect_400(TestRequest::patch(), &get_objects("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn delete() {
|
async fn delete() {
|
||||||
json::expect_200(Method::DELETE, &get_objects(""), "".to_string());
|
json::expect_200(TestRequest::delete(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
json::expect_422(Method::DELETE, &get_objects(""), "".to_string());
|
json::expect_422(TestRequest::delete(), &get_objects(""), "".to_string()).await;
|
||||||
|
|
||||||
expect_400(Method::DELETE, &get_objects(""));
|
expect_400(TestRequest::delete(), &get_objects("")).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[actix_web::test]
|
||||||
fn get() {
|
async fn get() {
|
||||||
expect_405(Method::GET, &get_objects(""));
|
expect_405(TestRequest::get(), &get_objects("")).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use mercator_db::CoreQueryParameters;
|
use mercator_db::CoreQueryParameters;
|
||||||
use mercator_db::DataBase;
|
use mercator_db::DataBase;
|
||||||
|
use mercator_parser::Bag;
|
||||||
use mercator_parser::Executor;
|
use mercator_parser::Executor;
|
||||||
use mercator_parser::FiltersParser;
|
use mercator_parser::FiltersParser;
|
||||||
|
use mercator_parser::Projection;
|
||||||
use mercator_parser::QueryParser;
|
use mercator_parser::QueryParser;
|
||||||
use mercator_parser::Validator;
|
use mercator_parser::Validator;
|
||||||
|
|
||||||
@@ -32,24 +34,35 @@ impl SharedState {
|
|||||||
&self.query_parser
|
&self.query_parser
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter<'q>(
|
pub fn execute<'e, T>(
|
||||||
&'q self,
|
&'e self,
|
||||||
filter: &'q str,
|
tree: &'e T, //&'e Bag,
|
||||||
core: &'q str,
|
core: &'e str,
|
||||||
output_space: &'q Option<String>,
|
parameters: &'e CoreQueryParameters<'e>,
|
||||||
volume: Option<f64>,
|
) -> mercator_db::ResultSet<'e>
|
||||||
view_port: &'q Option<(Vec<f64>, Vec<f64>)>,
|
where
|
||||||
resolution: &'q Option<Vec<u32>>,
|
T: Executor<'e, ResultSet = mercator_db::ResultSet<'e>>,
|
||||||
) -> mercator_db::ResultSet<'q> {
|
{
|
||||||
|
// Execute filter.
|
||||||
|
let execution = {
|
||||||
|
info_time!("Execution");
|
||||||
|
// _FIXME: Output space is defined as part of the projection
|
||||||
|
// and is ignored by projections operators.
|
||||||
|
tree.execute(core, parameters)
|
||||||
|
};
|
||||||
|
|
||||||
|
match execution {
|
||||||
|
Err(e) => {
|
||||||
|
debug!("Execution failed: \n{:?}", e);
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
results @ Ok(_) => results,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter<'q>(&'q self, filter: &'q str) -> Result<Bag, String> {
|
||||||
let parser = self.filter_parser();
|
let parser = self.filter_parser();
|
||||||
let parse;
|
let parse;
|
||||||
let parameters = CoreQueryParameters {
|
|
||||||
db: self.db(),
|
|
||||||
output_space: output_space.as_ref().map(String::as_str),
|
|
||||||
threshold_volume: volume,
|
|
||||||
view_port,
|
|
||||||
resolution,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse Input
|
// Parse Input
|
||||||
{
|
{
|
||||||
@@ -63,52 +76,20 @@ impl SharedState {
|
|||||||
Err(format!("{}", e))
|
Err(format!("{}", e))
|
||||||
}
|
}
|
||||||
Ok(tree) => {
|
Ok(tree) => {
|
||||||
let validation;
|
|
||||||
let execution;
|
|
||||||
|
|
||||||
// Check type coherence & validate tree
|
// Check type coherence & validate tree
|
||||||
{
|
{
|
||||||
debug_time!("Type check");
|
debug_time!("Type check");
|
||||||
validation = tree.validate();
|
let _ = tree.validate()?;
|
||||||
}
|
|
||||||
if validation.is_err() {
|
|
||||||
debug!("Type check failed");
|
|
||||||
return Err("Type check failed".to_string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute filter.
|
Ok(tree)
|
||||||
{
|
|
||||||
info_time!("Execution");
|
|
||||||
execution = tree.execute(core, ¶meters);
|
|
||||||
}
|
|
||||||
match execution {
|
|
||||||
Err(e) => {
|
|
||||||
debug!("Parsing failed: \n{:?}", e);
|
|
||||||
Err(e)
|
|
||||||
}
|
|
||||||
results @ Ok(_) => results,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query<'q>(
|
pub fn query(&self, query: &str) -> Result<Projection, String> {
|
||||||
&'q self,
|
|
||||||
query: &str,
|
|
||||||
core: &str,
|
|
||||||
volume: Option<f64>,
|
|
||||||
view_port: &'q Option<(Vec<f64>, Vec<f64>)>,
|
|
||||||
resolution: &'q Option<Vec<u32>>,
|
|
||||||
) -> mercator_db::ResultSet<'q> {
|
|
||||||
let parser = self.query_parser();
|
let parser = self.query_parser();
|
||||||
let parse;
|
let parse;
|
||||||
let parameters = CoreQueryParameters {
|
|
||||||
db: self.db(),
|
|
||||||
output_space: None,
|
|
||||||
threshold_volume: volume,
|
|
||||||
view_port,
|
|
||||||
resolution,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse Input
|
// Parse Input
|
||||||
{
|
{
|
||||||
@@ -120,35 +101,15 @@ impl SharedState {
|
|||||||
debug!("Parsing failed: \n{:?}", e);
|
debug!("Parsing failed: \n{:?}", e);
|
||||||
Err(e.to_string())
|
Err(e.to_string())
|
||||||
}
|
}
|
||||||
Ok(None) => Ok(vec![]),
|
Ok(None) => Err("Query is empty!".to_string()),
|
||||||
Ok(Some(tree)) => {
|
Ok(Some(tree)) => {
|
||||||
let validation;
|
|
||||||
let execution;
|
|
||||||
|
|
||||||
// Check type coherence & validate tree
|
// Check type coherence & validate tree
|
||||||
{
|
{
|
||||||
debug_time!("Type check");
|
debug_time!("Type check");
|
||||||
validation = tree.validate();
|
let _ = tree.validate()?;
|
||||||
}
|
|
||||||
if validation.is_err() {
|
|
||||||
debug!("Type check failed");
|
|
||||||
return Err("Type check failed".to_string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute filter.
|
Ok(tree)
|
||||||
{
|
|
||||||
info_time!("Execution");
|
|
||||||
// _FIXME: Output space is defined as part of the projection
|
|
||||||
// and is ignored by projections operators.
|
|
||||||
execution = tree.execute(core, ¶meters);
|
|
||||||
}
|
|
||||||
match execution {
|
|
||||||
Err(e) => {
|
|
||||||
debug!("Parsing failed: \n{:?}", e);
|
|
||||||
Err(e)
|
|
||||||
}
|
|
||||||
results @ Ok(_) => results,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user