Adds basic SPARQL UPDATE support to the server

pull/51/head
Tpt 5 years ago
parent b7041819a6
commit 6ed2f0117d
  1. 110
      server/src/main.rs
  2. 28
      server/templates/query.html

@ -22,7 +22,9 @@ use http_types::{
}; };
use oxigraph::io::{DatasetFormat, GraphFormat}; use oxigraph::io::{DatasetFormat, GraphFormat};
use oxigraph::model::{GraphName, NamedNode}; use oxigraph::model::{GraphName, NamedNode};
use oxigraph::sparql::{Query, QueryOptions, QueryResults, QueryResultsFormat, ServiceHandler}; use oxigraph::sparql::{
Query, QueryOptions, QueryResults, QueryResultsFormat, ServiceHandler, Update,
};
use oxigraph::RocksDbStore; use oxigraph::RocksDbStore;
use std::fmt; use std::fmt;
use std::io::{BufReader, Cursor}; use std::io::{BufReader, Cursor};
@ -135,7 +137,37 @@ async fn handle_request(request: Request, store: RocksDbStore) -> Result<Respons
} else { } else {
simple_response( simple_response(
StatusCode::UnsupportedMediaType, StatusCode::UnsupportedMediaType,
format!("No supported Content-Type given: {}", content_type), format!("Not supported Content-Type given: {}", content_type),
)
}
} else {
simple_response(StatusCode::BadRequest, "No Content-Type given")
}
}
("/update", Method::Post) => {
if let Some(content_type) = request.content_type() {
if content_type.essence() == "application/sparql-update" {
let mut buffer = String::new();
let mut request = request;
request
.take_body()
.take(MAX_SPARQL_BODY_SIZE)
.read_to_string(&mut buffer)
.await?;
evaluate_sparql_update(store, buffer, Vec::new(), Vec::new()).await?
} else if content_type.essence() == "application/x-www-form-urlencoded" {
let mut buffer = Vec::new();
let mut request = request;
request
.take_body()
.take(MAX_SPARQL_BODY_SIZE)
.read_to_end(&mut buffer)
.await?;
evaluate_urlencoded_sparql_update(store, buffer).await?
} else {
simple_response(
StatusCode::UnsupportedMediaType,
format!("Not supported Content-Type given: {}", content_type),
) )
} }
} else { } else {
@ -252,6 +284,60 @@ async fn evaluate_sparql_query(
.await .await
} }
async fn evaluate_urlencoded_sparql_update(
store: RocksDbStore,
encoded: Vec<u8>,
) -> Result<Response> {
let mut update = None;
let mut default_graph_uris = Vec::new();
let mut named_graph_uris = Vec::new();
for (k, v) in form_urlencoded::parse(&encoded) {
match k.as_ref() {
"update" => update = Some(v.into_owned()),
"using-graph-uri" => default_graph_uris.push(v.into_owned()),
"using-named-graph-uri" => named_graph_uris.push(v.into_owned()),
_ => {
return Ok(simple_response(
StatusCode::BadRequest,
format!("Unexpected parameter: {}", k),
))
}
}
}
if let Some(update) = update {
evaluate_sparql_update(store, update, default_graph_uris, named_graph_uris).await
} else {
Ok(simple_response(
StatusCode::BadRequest,
"You should set the 'update' parameter",
))
}
}
async fn evaluate_sparql_update(
store: RocksDbStore,
update: String,
default_graph_uris: Vec<String>,
named_graph_uris: Vec<String>,
) -> Result<Response> {
if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() {
return Ok(simple_response(
StatusCode::BadRequest,
"using-graph-uri and using-named-graph-uri parameters are not supported yet",
));
}
spawn_blocking(move || {
let update = Update::parse(&update, None).map_err(|e| {
let mut e = Error::from(e);
e.set_status(StatusCode::BadRequest);
e
})?;
store.update(update)?;
Ok(Response::new(StatusCode::NoContent))
})
.await
}
async fn http_server< async fn http_server<
F: Clone + Send + Sync + 'static + Fn(Request) -> Fut, F: Clone + Send + Sync + 'static + Fn(Request) -> Fut,
Fut: Send + Future<Output = Result<Response>>, Fut: Send + Future<Output = Result<Response>>,
@ -522,6 +608,26 @@ mod tests {
exec(request, StatusCode::Ok) exec(request, StatusCode::Ok)
} }
#[test]
fn post_update() {
let mut request =
Request::new(Method::Post, Url::parse("http://localhost/update").unwrap());
request.insert_header("Content-Type", "application/sparql-update");
request.set_body(
"INSERT DATA { <http://example.com> <http://example.com> <http://example.com> }",
);
exec(request, StatusCode::NoContent)
}
#[test]
fn post_bad_update() {
let mut request =
Request::new(Method::Post, Url::parse("http://localhost/update").unwrap());
request.insert_header("Content-Type", "application/sparql-update");
request.set_body("INSERT");
exec(request, StatusCode::BadRequest)
}
fn exec(request: Request, expected_status: StatusCode) { fn exec(request: Request, expected_status: StatusCode) {
let mut path = temp_dir(); let mut path = temp_dir();
path.push("temp-oxigraph-server-test"); path.push("temp-oxigraph-server-test");

@ -3,25 +3,23 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Oxigraph server</title> <title>Oxigraph server</title>
<link rel="stylesheet" href="//tools-static.wmflabs.org/cdnjs/ajax/libs/yasqe/2.11.22/yasqe.min.css"/> <link href="https://unpkg.com/@triply/yasgui@4/build/yasgui.min.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="//tools-static.wmflabs.org/cdnjs/ajax/libs/yasr/2.12.19/yasr.min.css"/> <script src="https://unpkg.com/@triply/yasgui@4/build/yasgui.min.js"></script>
</head> </head>
<body> <body>
<div id="yasqe"></div> <div id="yasgui"></div>
<div id="yasr"></div>
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/yasr/2.12.19/yasr.bundled.min.js"></script>
<script src="//tools-static.wmflabs.org/cdnjs/ajax/libs/yasqe/2.11.22/yasqe.bundled.min.js"></script>
<script> <script>
var yasqe = YASQE(document.getElementById("yasqe"), { new Yasgui(document.getElementById("yasgui"), {
sparql: { requestConfig: { endpoint: window.location.protocol + '//' + window.location.host + "/query" },
showQueryButton: true, endpointCatalogueOptions: {
endpoint: "/query" getData: function () {
return [
{ endpoint: window.location.protocol + '//' + window.location.host + "/query" },
{ endpoint: window.location.protocol + '//' + window.location.host + "/update" },
];
},
keys: [],
} }
}); });
var yasr = YASR(document.getElementById("yasr"), {
getUsedPrefixes: yasqe.getPrefixesFromQuery,
useGoogleCharts: false
});
yasqe.options.sparql.callbacks.complete = yasr.setResponse;
</script> </script>
</body> </body>

Loading…
Cancel
Save