parent
b762991917
commit
bf3d205cf7
@ -0,0 +1,403 @@ |
|||||||
|
use crate::sparql::algebra::{ |
||||||
|
DatasetSpec, GraphPattern, GraphTarget, GraphUpdateOperation, NamedNodeOrVariable, QuadPattern, |
||||||
|
TermOrVariable, |
||||||
|
}; |
||||||
|
use crate::sparql::dataset::{DatasetStrId, DatasetView}; |
||||||
|
use crate::sparql::eval::SimpleEvaluator; |
||||||
|
use crate::sparql::plan::EncodedTuple; |
||||||
|
use crate::sparql::plan_builder::PlanBuilder; |
||||||
|
use crate::sparql::{EvaluationError, ServiceHandler, Variable}; |
||||||
|
use crate::store::numeric_encoder::{ |
||||||
|
EncodedQuad, EncodedTerm, ReadEncoder, StrContainer, StrLookup, WriteEncoder, |
||||||
|
}; |
||||||
|
use crate::store::{ReadableEncodedStore, WritableEncodedStore}; |
||||||
|
use oxiri::Iri; |
||||||
|
use std::rc::Rc; |
||||||
|
|
||||||
|
pub(crate) struct SimpleUpdateEvaluator<'a, R, W> { |
||||||
|
read: R, |
||||||
|
write: &'a mut W, |
||||||
|
base_iri: Option<Rc<Iri<String>>>, |
||||||
|
service_handler: Rc<dyn ServiceHandler<Error = EvaluationError>>, |
||||||
|
} |
||||||
|
|
||||||
|
impl< |
||||||
|
'a, |
||||||
|
R: ReadableEncodedStore + Clone + 'static, |
||||||
|
W: StrContainer<StrId = R::StrId> + WritableEncodedStore<StrId = R::StrId> + 'a, |
||||||
|
> SimpleUpdateEvaluator<'a, R, W> |
||||||
|
{ |
||||||
|
pub fn new( |
||||||
|
read: R, |
||||||
|
write: &'a mut W, |
||||||
|
base_iri: Option<Rc<Iri<String>>>, |
||||||
|
service_handler: Rc<dyn ServiceHandler<Error = EvaluationError>>, |
||||||
|
) -> Self { |
||||||
|
Self { |
||||||
|
read, |
||||||
|
write, |
||||||
|
base_iri, |
||||||
|
service_handler, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn eval_all(&mut self, updates: &[GraphUpdateOperation]) -> Result<(), EvaluationError> { |
||||||
|
for update in updates { |
||||||
|
self.eval(update)?; |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
fn eval(&mut self, update: &GraphUpdateOperation) -> Result<(), EvaluationError> { |
||||||
|
match update { |
||||||
|
GraphUpdateOperation::InsertData { data } => self.eval_insert_data(data), |
||||||
|
GraphUpdateOperation::DeleteData { data } => self.eval_delete_data(data), |
||||||
|
GraphUpdateOperation::DeleteInsert { |
||||||
|
delete, |
||||||
|
insert, |
||||||
|
using, |
||||||
|
algebra, |
||||||
|
} => self.eval_delete_insert(delete, insert, using, algebra), |
||||||
|
GraphUpdateOperation::Load { .. } => Err(EvaluationError::msg( |
||||||
|
"SPARQL UPDATE LOAD operation is not implemented yet", |
||||||
|
)), |
||||||
|
GraphUpdateOperation::Clear { graph, .. } => self.eval_clear(graph), |
||||||
|
GraphUpdateOperation::Create { .. } => Ok(()), |
||||||
|
GraphUpdateOperation::Drop { graph, .. } => self.eval_clear(graph), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_insert_data(&mut self, data: &[QuadPattern]) -> Result<(), EvaluationError> { |
||||||
|
for quad in data { |
||||||
|
if let Some(quad) = self.encode_quad_for_insertion(quad, &[], &[])? { |
||||||
|
self.write.insert_encoded(&quad).map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_delete_data(&mut self, data: &[QuadPattern]) -> Result<(), EvaluationError> { |
||||||
|
for quad in data { |
||||||
|
if let Some(quad) = self.encode_quad_for_deletion(quad, &[], &[])? { |
||||||
|
self.write.remove_encoded(&quad).map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_delete_insert( |
||||||
|
&mut self, |
||||||
|
delete: &[QuadPattern], |
||||||
|
insert: &[QuadPattern], |
||||||
|
using: &DatasetSpec, |
||||||
|
algebra: &GraphPattern, |
||||||
|
) -> Result<(), EvaluationError> { |
||||||
|
let dataset = Rc::new(DatasetView::new(self.read.clone(), false, &[], &[], using)?); |
||||||
|
let (plan, variables) = PlanBuilder::build(dataset.as_ref(), algebra)?; |
||||||
|
let evaluator = SimpleEvaluator::<DatasetView<R>>::new( |
||||||
|
dataset.clone(), |
||||||
|
self.base_iri.clone(), |
||||||
|
self.service_handler.clone(), |
||||||
|
); |
||||||
|
for tuple in evaluator.eval_plan(&plan, EncodedTuple::with_capacity(variables.len())) { |
||||||
|
// We map the tuple to only get store strings
|
||||||
|
let tuple = tuple? |
||||||
|
.into_iter() |
||||||
|
.map(|t| { |
||||||
|
Ok(if let Some(t) = t { |
||||||
|
Some( |
||||||
|
t.try_map_id(|id| { |
||||||
|
if let DatasetStrId::Store(s) = id { |
||||||
|
Ok(s) |
||||||
|
} else { |
||||||
|
self.write |
||||||
|
.insert_str( |
||||||
|
&dataset |
||||||
|
.get_str(id) |
||||||
|
.map_err(to_eval_error)? |
||||||
|
.ok_or_else(|| { |
||||||
|
EvaluationError::msg( |
||||||
|
"String not stored in the string store", |
||||||
|
) |
||||||
|
}) |
||||||
|
.map_err(to_eval_error)?, |
||||||
|
) |
||||||
|
.map_err(to_eval_error) |
||||||
|
} |
||||||
|
}) |
||||||
|
.map_err(to_eval_error)?, |
||||||
|
) |
||||||
|
} else { |
||||||
|
None |
||||||
|
}) |
||||||
|
}) |
||||||
|
.collect::<Result<Vec<_>, EvaluationError>>()?; |
||||||
|
|
||||||
|
for quad in delete { |
||||||
|
if let Some(quad) = self.encode_quad_for_deletion(quad, &variables, &tuple)? { |
||||||
|
self.write.remove_encoded(&quad).map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} |
||||||
|
for quad in insert { |
||||||
|
if let Some(quad) = self.encode_quad_for_insertion(quad, &variables, &tuple)? { |
||||||
|
self.write.insert_encoded(&quad).map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
fn eval_clear(&mut self, graph: &GraphTarget) -> Result<(), EvaluationError> { |
||||||
|
match graph { |
||||||
|
GraphTarget::NamedNode(graph) => { |
||||||
|
if let Some(graph) = self |
||||||
|
.read |
||||||
|
.get_encoded_named_node(graph.into()) |
||||||
|
.map_err(to_eval_error)? |
||||||
|
{ |
||||||
|
for quad in self |
||||||
|
.read |
||||||
|
.encoded_quads_for_pattern(None, None, None, Some(graph)) |
||||||
|
{ |
||||||
|
self.write |
||||||
|
.remove_encoded(&quad.map_err(to_eval_error)?) |
||||||
|
.map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} else { |
||||||
|
//we do not track created graph so it's fine
|
||||||
|
} |
||||||
|
} |
||||||
|
GraphTarget::DefaultGraph => { |
||||||
|
for quad in self.read.encoded_quads_for_pattern( |
||||||
|
None, |
||||||
|
None, |
||||||
|
None, |
||||||
|
Some(EncodedTerm::DefaultGraph), |
||||||
|
) { |
||||||
|
self.write |
||||||
|
.remove_encoded(&quad.map_err(to_eval_error)?) |
||||||
|
.map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} |
||||||
|
GraphTarget::NamedGraphs => { |
||||||
|
for quad in self.read.encoded_quads_for_pattern(None, None, None, None) { |
||||||
|
let quad = quad.map_err(to_eval_error)?; |
||||||
|
if !quad.graph_name.is_default_graph() { |
||||||
|
self.write.remove_encoded(&quad).map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
GraphTarget::AllGraphs => { |
||||||
|
for quad in self.read.encoded_quads_for_pattern(None, None, None, None) { |
||||||
|
self.write |
||||||
|
.remove_encoded(&quad.map_err(to_eval_error)?) |
||||||
|
.map_err(to_eval_error)?; |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
Ok(()) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_quad_for_insertion( |
||||||
|
&mut self, |
||||||
|
quad: &QuadPattern, |
||||||
|
variables: &[Variable], |
||||||
|
values: &[Option<EncodedTerm<R::StrId>>], |
||||||
|
) -> Result<Option<EncodedQuad<R::StrId>>, EvaluationError> { |
||||||
|
Ok(Some(EncodedQuad { |
||||||
|
subject: if let Some(subject) = |
||||||
|
self.encode_term_for_insertion(&quad.subject, variables, values, |t| { |
||||||
|
t.is_named_node() || t.is_blank_node() |
||||||
|
})? { |
||||||
|
subject |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
}, |
||||||
|
predicate: if let Some(predicate) = |
||||||
|
self.encode_named_node_for_insertion(&quad.predicate, variables, values)? |
||||||
|
{ |
||||||
|
predicate |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
}, |
||||||
|
object: if let Some(object) = |
||||||
|
self.encode_term_for_insertion(&quad.object, variables, values, |t| { |
||||||
|
!t.is_default_graph() |
||||||
|
})? { |
||||||
|
object |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
}, |
||||||
|
graph_name: if let Some(graph_name) = &quad.graph_name { |
||||||
|
if let Some(graph_name) = |
||||||
|
self.encode_named_node_for_insertion(graph_name, variables, values)? |
||||||
|
{ |
||||||
|
graph_name |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
} |
||||||
|
} else { |
||||||
|
EncodedTerm::DefaultGraph |
||||||
|
}, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_term_for_insertion( |
||||||
|
&mut self, |
||||||
|
term: &TermOrVariable, |
||||||
|
variables: &[Variable], |
||||||
|
values: &[Option<EncodedTerm<R::StrId>>], |
||||||
|
validate: impl FnOnce(&EncodedTerm<R::StrId>) -> bool, |
||||||
|
) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> { |
||||||
|
Ok(match term { |
||||||
|
TermOrVariable::Term(term) => { |
||||||
|
Some(self.write.encode_term(term.into()).map_err(to_eval_error)?) |
||||||
|
} |
||||||
|
TermOrVariable::Variable(v) => { |
||||||
|
if let Some(Some(term)) = variables |
||||||
|
.iter() |
||||||
|
.position(|v2| v == v2) |
||||||
|
.and_then(|i| values.get(i)) |
||||||
|
{ |
||||||
|
if validate(term) { |
||||||
|
Some(*term) |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_named_node_for_insertion( |
||||||
|
&mut self, |
||||||
|
term: &NamedNodeOrVariable, |
||||||
|
variables: &[Variable], |
||||||
|
values: &[Option<EncodedTerm<R::StrId>>], |
||||||
|
) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> { |
||||||
|
Ok(match term { |
||||||
|
NamedNodeOrVariable::NamedNode(term) => Some( |
||||||
|
self.write |
||||||
|
.encode_named_node(term.into()) |
||||||
|
.map_err(to_eval_error)?, |
||||||
|
), |
||||||
|
NamedNodeOrVariable::Variable(v) => { |
||||||
|
if let Some(Some(term)) = variables |
||||||
|
.iter() |
||||||
|
.position(|v2| v == v2) |
||||||
|
.and_then(|i| values.get(i)) |
||||||
|
{ |
||||||
|
if term.is_named_node() { |
||||||
|
Some(*term) |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_quad_for_deletion( |
||||||
|
&self, |
||||||
|
quad: &QuadPattern, |
||||||
|
variables: &[Variable], |
||||||
|
values: &[Option<EncodedTerm<R::StrId>>], |
||||||
|
) -> Result<Option<EncodedQuad<R::StrId>>, EvaluationError> { |
||||||
|
Ok(Some(EncodedQuad { |
||||||
|
subject: if let Some(subject) = |
||||||
|
self.encode_term_for_deletion(&quad.subject, variables, values)? |
||||||
|
{ |
||||||
|
subject |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
}, |
||||||
|
predicate: if let Some(predicate) = |
||||||
|
self.encode_named_node_for_deletion(&quad.predicate, variables, values)? |
||||||
|
{ |
||||||
|
predicate |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
}, |
||||||
|
object: if let Some(object) = |
||||||
|
self.encode_term_for_deletion(&quad.object, variables, values)? |
||||||
|
{ |
||||||
|
object |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
}, |
||||||
|
graph_name: if let Some(graph_name) = &quad.graph_name { |
||||||
|
if let Some(graph_name) = |
||||||
|
self.encode_named_node_for_deletion(graph_name, variables, values)? |
||||||
|
{ |
||||||
|
graph_name |
||||||
|
} else { |
||||||
|
return Ok(None); |
||||||
|
} |
||||||
|
} else { |
||||||
|
EncodedTerm::DefaultGraph |
||||||
|
}, |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_term_for_deletion( |
||||||
|
&self, |
||||||
|
term: &TermOrVariable, |
||||||
|
variables: &[Variable], |
||||||
|
values: &[Option<EncodedTerm<R::StrId>>], |
||||||
|
) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> { |
||||||
|
Ok(match term { |
||||||
|
TermOrVariable::Term(term) => self |
||||||
|
.read |
||||||
|
.get_encoded_term(term.into()) |
||||||
|
.map_err(to_eval_error)?, |
||||||
|
TermOrVariable::Variable(v) => { |
||||||
|
if let Some(Some(term)) = variables |
||||||
|
.iter() |
||||||
|
.position(|v2| v == v2) |
||||||
|
.and_then(|i| values.get(i)) |
||||||
|
{ |
||||||
|
Some(*term) |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fn encode_named_node_for_deletion( |
||||||
|
&self, |
||||||
|
term: &NamedNodeOrVariable, |
||||||
|
variables: &[Variable], |
||||||
|
values: &[Option<EncodedTerm<R::StrId>>], |
||||||
|
) -> Result<Option<EncodedTerm<R::StrId>>, EvaluationError> { |
||||||
|
Ok(match term { |
||||||
|
NamedNodeOrVariable::NamedNode(term) => self |
||||||
|
.read |
||||||
|
.get_encoded_named_node(term.into()) |
||||||
|
.map_err(to_eval_error)?, |
||||||
|
NamedNodeOrVariable::Variable(v) => { |
||||||
|
if let Some(Some(term)) = variables |
||||||
|
.iter() |
||||||
|
.position(|v2| v == v2) |
||||||
|
.and_then(|i| values.get(i)) |
||||||
|
{ |
||||||
|
if term.is_named_node() { |
||||||
|
Some(*term) |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} else { |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn to_eval_error(e: impl Into<EvaluationError>) -> EvaluationError { |
||||||
|
e.into() |
||||||
|
} |
Loading…
Reference in new issue