use iron::prelude::*;
use iron::status;
use indradb::{EdgeDirection, EdgeKey, EdgeQuery, Error, Transaction, Type, VertexQuery};
use common::ProxyTransaction;
use serde_json::value::Value as JsonValue;
use serde_json;
use serde::ser::Serialize;
use uuid::Uuid;
use script;
use super::util::*;
use iron::typemap::TypeMap;
use iron::headers::{ContentType, Encoding, Headers, TransferEncoding};
use std::thread::spawn;
pub fn script(req: &mut Request) -> IronResult<Response> {
let name: String = get_url_param(req, "name")?;
let payload = read_json(&mut req.body)?.unwrap_or_else(|| JsonValue::Null);
let (path, contents) = get_script_file(name)?;
match script::execute(&contents, &path, payload) {
Ok(value) => Ok(to_response(status::Ok, &value)),
Err(err) => {
let error_message = format!("Script failed: {:?}", err);
Err(create_iron_error(
status::InternalServerError,
error_message,
))
}
}
}
pub fn mapreduce(req: &mut Request) -> IronResult<Response> {
let name: String = get_url_param(req, "name")?;
let payload = read_json(&mut req.body)?.unwrap_or_else(|| JsonValue::Null);
let (path, contents) = get_script_file(name)?;
let mut hs = Headers::new();
hs.set(ContentType(get_json_mime()));
hs.set(TransferEncoding(vec![Encoding::Chunked]));
let (sender, receiver) = script::bounded(1);
spawn(move || {
script::execute_mapreduce(contents, path, payload, sender);
});
Ok(Response {
status: Some(status::Ok),
headers: hs,
extensions: TypeMap::new(),
body: Some(Box::new(receiver)),
})
}
pub fn transaction(req: &mut Request) -> IronResult<Response> {
let trans = get_transaction()?;
let mut jsonable_res: Vec<JsonValue> = Vec::new();
let body: Vec<JsonValue> = read_json(&mut req.body)?.unwrap_or_else(Vec::new);
for (idx, item) in body.into_iter().enumerate() {
if let JsonValue::Object(obj) = item {
let action = get_json_obj_value::<String>(&obj, "action").map_err(|err| {
let message = format!("Item #{}: {}", idx, err);
create_iron_error(status::BadRequest, message)
})?;
let result: Result<JsonValue, IronError> = match &action[..] {
"create_vertex" => create_vertex(&trans, &obj),
"get_vertices" => get_vertices(&trans, &obj),
"delete_vertices" => delete_vertices(&trans, &obj),
"get_vertex_count" => get_vertex_count(&trans, &obj),
"create_edge" => create_edge(&trans, &obj),
"get_edges" => get_edges(&trans, &obj),
"delete_edges" => delete_edges(&trans, &obj),
"get_edge_count" => get_edge_count(&trans, &obj),
"get_global_metadata" => get_global_metadata(&trans, &obj),
"set_global_metadata" => set_global_metadata(&trans, &obj),
"delete_global_metadata" => delete_global_metadata(&trans, &obj),
"get_vertex_metadata" => get_vertex_metadata(&trans, &obj),
"set_vertex_metadata" => set_vertex_metadata(&trans, &obj),
"delete_vertex_metadata" => delete_vertex_metadata(&trans, &obj),
"get_edge_metadata" => get_edge_metadata(&trans, &obj),
"set_edge_metadata" => set_edge_metadata(&trans, &obj),
"delete_edge_metadata" => delete_edge_metadata(&trans, &obj),
_ => Err(create_iron_error(
status::BadRequest,
"Unknown action".to_string(),
)),
};
match result {
Err(err) => {
let message = format!("Item #{}: {}", idx, err);
return Err(create_iron_error(status::BadRequest, message));
}
Ok(value) => {
jsonable_res.push(value);
}
}
} else {
return Err(create_iron_error(
status::BadRequest,
format!("Item #{}: Invalid type", idx),
));
}
}
Ok(to_response(status::Ok, &jsonable_res))
}
fn create_vertex(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let t = get_json_obj_value::<Type>(item, "type")?;
execute_item(trans.create_vertex(&t))
}
fn get_vertices(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<VertexQuery>(item, "query")?;
execute_item(trans.get_vertices(&q))
}
fn delete_vertices(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<VertexQuery>(item, "query")?;
execute_item(trans.delete_vertices(&q))
}
fn get_vertex_count(
trans: &ProxyTransaction,
_: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
execute_item(trans.get_vertex_count())
}
fn create_edge(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let key = get_json_obj_value::<EdgeKey>(item, "key")?;
execute_item(trans.create_edge(&key))
}
fn get_edges(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<EdgeQuery>(item, "query")?;
execute_item(trans.get_edges(&q))
}
fn delete_edges(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<EdgeQuery>(item, "query")?;
execute_item(trans.delete_edges(&q))
}
fn get_edge_count(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let id = get_json_obj_value::<Uuid>(item, "id")?;
let type_filter = get_json_obj_value::<Option<Type>>(item, "type_filter")?;
let direction = get_json_obj_value::<EdgeDirection>(item, "direction")?;
execute_item(trans.get_edge_count(id, type_filter.as_ref(), direction))
}
fn get_global_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let name = get_json_obj_value::<String>(item, "name")?;
execute_item(trans.get_global_metadata(&name))
}
fn set_global_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let name = get_json_obj_value::<String>(item, "name")?;
let value = get_json_obj_value::<JsonValue>(item, "value")?;
execute_item(trans.set_global_metadata(&name, &value))
}
fn delete_global_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let name = get_json_obj_value::<String>(item, "name")?;
execute_item(trans.delete_global_metadata(&name))
}
fn get_vertex_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<VertexQuery>(item, "query")?;
let name = get_json_obj_value::<String>(item, "name")?;
execute_item(trans.get_vertex_metadata(&q, &name))
}
fn set_vertex_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<VertexQuery>(item, "query")?;
let name = get_json_obj_value::<String>(item, "name")?;
let value = get_json_obj_value::<JsonValue>(item, "value")?;
execute_item(trans.set_vertex_metadata(&q, &name, &value))
}
fn delete_vertex_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<VertexQuery>(item, "query")?;
let name = get_json_obj_value::<String>(item, "name")?;
execute_item(trans.delete_vertex_metadata(&q, &name))
}
fn get_edge_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<EdgeQuery>(item, "query")?;
let name = get_json_obj_value::<String>(item, "name")?;
execute_item(trans.get_edge_metadata(&q, &name))
}
fn set_edge_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<EdgeQuery>(item, "query")?;
let name = get_json_obj_value::<String>(item, "name")?;
let value = get_json_obj_value::<JsonValue>(item, "value")?;
execute_item(trans.set_edge_metadata(&q, &name, &value))
}
fn delete_edge_metadata(
trans: &ProxyTransaction,
item: &serde_json::Map<String, JsonValue>,
) -> Result<JsonValue, IronError> {
let q = get_json_obj_value::<EdgeQuery>(item, "query")?;
let name = get_json_obj_value::<String>(item, "name")?;
execute_item(trans.delete_edge_metadata(&q, &name))
}
fn execute_item<T: Serialize>(result: Result<T, Error>) -> Result<JsonValue, IronError> {
let value =
result.map_err(|err| create_iron_error(status::InternalServerError, format!("{}", err)))?;
Ok(serde_json::to_value(value).map_err(|err| {
create_iron_error(
status::InternalServerError,
format!("Could not serialize results: {}", err),
)
})?)
}