Makes SPARQL algebra more strict

Removes some invalid but encodable states
pull/171/head
Tpt 4 years ago
parent aa7a23b94d
commit e6e83ff369
  1. 38
      lib/src/sparql/plan_builder.rs
  2. 234
      lib/src/sparql/update.rs
  3. 8
      lib/src/store.rs
  4. 76
      spargebra/src/algebra.rs
  5. 164
      spargebra/src/parser.rs
  6. 205
      spargebra/src/term.rs
  7. 41
      spargebra/src/update.rs

@ -775,7 +775,8 @@ impl<'a> PlanBuilder<'a> {
TermOrVariable::Variable(variable) => {
PatternValue::Variable(variable_key(variables, variable))
}
TermOrVariable::Term(Term::BlankNode(bnode)) => {
TermOrVariable::NamedNode(node) => PatternValue::Constant(self.build_named_node(node)?),
TermOrVariable::BlankNode(bnode) => {
PatternValue::Variable(variable_key(
variables,
&Variable {
@ -784,7 +785,9 @@ impl<'a> PlanBuilder<'a> {
))
//TODO: very bad hack to convert bnode to variable
}
TermOrVariable::Term(term) => PatternValue::Constant(self.build_term(term)?),
TermOrVariable::Literal(literal) => {
PatternValue::Constant(self.build_literal(literal)?)
}
})
}
@ -806,7 +809,7 @@ impl<'a> PlanBuilder<'a> {
fn encode_bindings(
&mut self,
table_variables: &[Variable],
rows: &[Vec<Option<NamedNodeOrLiteral>>],
rows: &[Vec<Option<GroundTerm>>],
variables: &mut Vec<Variable>,
) -> Result<Vec<EncodedTuple>, EvaluationError> {
let bindings_variables_keys = table_variables
@ -821,8 +824,8 @@ impl<'a> PlanBuilder<'a> {
result.set(
bindings_variables_keys[key],
match term {
NamedNodeOrLiteral::NamedNode(node) => self.build_named_node(node),
NamedNodeOrLiteral::Literal(literal) => self.build_literal(literal),
GroundTerm::NamedNode(node) => self.build_named_node(node),
GroundTerm::Literal(literal) => self.build_literal(literal),
}?,
);
}
@ -926,10 +929,15 @@ impl<'a> PlanBuilder<'a> {
TermOrVariable::Variable(variable) => {
TripleTemplateValue::Variable(variable_key(variables, variable))
}
TermOrVariable::Term(Term::BlankNode(bnode)) => {
TermOrVariable::NamedNode(node) => {
TripleTemplateValue::Constant(self.build_named_node(node)?)
}
TermOrVariable::BlankNode(bnode) => {
TripleTemplateValue::BlankNode(bnode_key(bnodes, bnode))
}
TermOrVariable::Term(term) => TripleTemplateValue::Constant(self.build_term(term)?),
TermOrVariable::Literal(literal) => {
TripleTemplateValue::Constant(self.build_literal(literal)?)
}
})
}
@ -1064,14 +1072,6 @@ impl<'a> PlanBuilder<'a> {
),
})
}
fn build_term(&mut self, term: &Term) -> Result<EncodedTerm, EvaluationError> {
match term {
Term::NamedNode(node) => self.build_named_node(node),
Term::BlankNode(_) => Err(EvaluationError::msg("Unexpected blank node")),
Term::Literal(literal) => self.build_literal(literal),
}
}
}
fn variable_key(variables: &mut Vec<Variable>, variable: &Variable) -> usize {
@ -1130,7 +1130,7 @@ fn count_pattern_binds(
if !assigned_variables.contains(v) {
count -= 4;
}
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.subject {
} else if let TermOrVariable::BlankNode(bnode) = &pattern.subject {
if !assigned_blank_nodes.contains(bnode) {
count -= 4;
}
@ -1148,7 +1148,7 @@ fn count_pattern_binds(
if !assigned_variables.contains(v) {
count -= 4;
}
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.object {
} else if let TermOrVariable::BlankNode(bnode) = &pattern.object {
if !assigned_blank_nodes.contains(bnode) {
count -= 4;
}
@ -1165,7 +1165,7 @@ fn add_pattern_variables<'a>(
) {
if let TermOrVariable::Variable(v) = &pattern.subject {
variables.insert(v);
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.subject {
} else if let TermOrVariable::BlankNode(bnode) = &pattern.subject {
blank_nodes.insert(bnode);
}
if let NamedNodeOrVariable::Variable(v) = &pattern.predicate {
@ -1173,7 +1173,7 @@ fn add_pattern_variables<'a>(
}
if let TermOrVariable::Variable(v) = &pattern.object {
variables.insert(v);
} else if let TermOrVariable::Term(Term::BlankNode(bnode)) = &pattern.object {
} else if let TermOrVariable::BlankNode(bnode) = &pattern.object {
blank_nodes.insert(bnode);
}
}

@ -16,10 +16,11 @@ use crate::storage::Storage;
use http::header::{ACCEPT, CONTENT_TYPE, USER_AGENT};
use http::{Method, Request, StatusCode};
use oxiri::Iri;
use spargebra::algebra::{GraphPattern, GraphTarget, QuadPattern};
use spargebra::algebra::{GraphPattern, GraphTarget, GroundQuadPattern, QuadPattern};
use spargebra::term::{
BlankNode, GraphName, Literal, NamedNode, NamedNodeOrVariable, NamedOrBlankNode, Quad, Term,
TermOrVariable, Variable,
BlankNode, GraphName, GraphNameOrVariable, GroundQuad, GroundTerm, GroundTermOrVariable,
Literal, NamedNode, NamedNodeOrVariable, NamedOrBlankNode, Quad, Term, TermOrVariable,
Variable,
};
use spargebra::GraphUpdateOperation;
use std::collections::HashMap;
@ -99,9 +100,9 @@ impl<'a> SimpleUpdateEvaluator<'a> {
Ok(())
}
fn eval_delete_data(&mut self, data: &[Quad]) -> Result<(), EvaluationError> {
fn eval_delete_data(&mut self, data: &[GroundQuad]) -> Result<(), EvaluationError> {
for quad in data {
let quad = self.encode_quad_for_deletion(quad)?;
let quad = self.encode_quad_for_deletion(quad);
self.storage.remove(&quad)?;
}
Ok(())
@ -109,7 +110,7 @@ impl<'a> SimpleUpdateEvaluator<'a> {
fn eval_delete_insert(
&mut self,
delete: &[QuadPattern],
delete: &[GroundQuadPattern],
insert: &[QuadPattern],
using: &QueryDataset,
algebra: &GraphPattern,
@ -146,8 +147,7 @@ impl<'a> SimpleUpdateEvaluator<'a> {
.collect::<Result<Vec<_>, EvaluationError>>()?;
for quad in delete {
if let Some(quad) =
self.encode_quad_pattern_for_deletion(quad, &variables, &tuple)?
if let Some(quad) = self.encode_quad_pattern_for_deletion(quad, &variables, &tuple)
{
self.storage.remove(&quad)?;
}
@ -164,11 +164,7 @@ impl<'a> SimpleUpdateEvaluator<'a> {
Ok(())
}
fn eval_load(
&mut self,
from: &NamedNode,
to: &Option<NamedNode>,
) -> Result<(), EvaluationError> {
fn eval_load(&mut self, from: &NamedNode, to: &GraphName) -> Result<(), EvaluationError> {
let request = Request::builder()
.method(Method::GET)
.uri(&from.iri)
@ -201,10 +197,9 @@ impl<'a> SimpleUpdateEvaluator<'a> {
from, content_type
))
})?;
let to_graph_name = if let Some(graph_name) = to {
NamedNodeRef::new_unchecked(&graph_name.iri).into()
} else {
GraphNameRef::DefaultGraph
let to_graph_name = match to {
GraphName::NamedNode(graph_name) => NamedNodeRef::new_unchecked(&graph_name.iri).into(),
GraphName::DefaultGraph => GraphNameRef::DefaultGraph,
};
load_graph(
self.storage,
@ -365,16 +360,12 @@ impl<'a> SimpleUpdateEvaluator<'a> {
} else {
return Ok(None);
},
graph_name: if let Some(graph_name) = &quad.graph_name {
if let Some(graph_name) =
self.encode_named_node_or_var_for_insertion(graph_name, variables, values)?
graph_name: if let Some(graph_name) =
self.encode_graph_name_or_var_for_insertion(&quad.graph_name, variables, values)?
{
graph_name
} else {
return Ok(None);
}
} else {
EncodedTerm::DefaultGraph
},
}))
}
@ -388,27 +379,14 @@ impl<'a> SimpleUpdateEvaluator<'a> {
validate: impl FnOnce(&EncodedTerm) -> bool,
) -> Result<Option<EncodedTerm>, EvaluationError> {
Ok(match term {
TermOrVariable::Term(term) => Some(match term {
Term::NamedNode(term) => self.encode_named_node_for_insertion(term)?,
Term::BlankNode(bnode) => self
.storage
TermOrVariable::NamedNode(term) => Some(self.encode_named_node_for_insertion(term)?),
TermOrVariable::BlankNode(bnode) => Some(
self.storage
.encode_blank_node(bnodes.entry(bnode.clone()).or_default().as_ref())?,
Term::Literal(term) => self.encode_literal_for_insertion(term)?,
}),
),
TermOrVariable::Literal(term) => Some(self.encode_literal_for_insertion(term)?),
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
}
self.lookup_variable(v, variables, values).filter(validate)
}
})
}
@ -423,22 +401,46 @@ impl<'a> SimpleUpdateEvaluator<'a> {
NamedNodeOrVariable::NamedNode(term) => {
Some(self.encode_named_node_for_insertion(term)?)
}
NamedNodeOrVariable::Variable(v) => {
NamedNodeOrVariable::Variable(v) => self
.lookup_variable(v, variables, values)
.filter(|value| value.is_named_node()),
})
}
fn encode_graph_name_or_var_for_insertion(
&mut self,
term: &GraphNameOrVariable,
variables: &[Variable],
values: &[Option<EncodedTerm>],
) -> Result<Option<EncodedTerm>, EvaluationError> {
Ok(match term {
GraphNameOrVariable::NamedNode(term) => {
Some(self.encode_named_node_for_insertion(term)?)
}
GraphNameOrVariable::DefaultGraph => Some(EncodedTerm::DefaultGraph),
GraphNameOrVariable::Variable(v) => self
.lookup_variable(v, variables, values)
.filter(|value| value.is_named_node()),
})
}
fn lookup_variable(
&self,
v: &Variable,
variables: &[Variable],
values: &[Option<EncodedTerm>],
) -> Option<EncodedTerm> {
{
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_named_node_for_insertion(
@ -465,105 +467,56 @@ impl<'a> SimpleUpdateEvaluator<'a> {
})?)
}
fn encode_quad_for_deletion(&mut self, quad: &Quad) -> Result<EncodedQuad, EvaluationError> {
Ok(EncodedQuad {
subject: match &quad.subject {
NamedOrBlankNode::NamedNode(subject) => {
self.encode_named_node_for_deletion(subject)
}
NamedOrBlankNode::BlankNode(_) => {
return Err(EvaluationError::msg(
"Blank nodes are not allowed in DELETE DATA",
))
}
},
fn encode_quad_for_deletion(&mut self, quad: &GroundQuad) -> EncodedQuad {
EncodedQuad {
subject: self.encode_named_node_for_deletion(&quad.subject),
predicate: self.encode_named_node_for_deletion(&quad.predicate),
object: match &quad.object {
Term::NamedNode(object) => self.encode_named_node_for_deletion(object),
Term::BlankNode(_) => {
return Err(EvaluationError::msg(
"Blank nodes are not allowed in DELETE DATA",
))
}
Term::Literal(object) => self.encode_literal_for_deletion(object),
GroundTerm::NamedNode(object) => self.encode_named_node_for_deletion(object),
GroundTerm::Literal(object) => self.encode_literal_for_deletion(object),
},
graph_name: match &quad.graph_name {
GraphName::NamedNode(graph_name) => self.encode_named_node_for_deletion(graph_name),
GraphName::DefaultGraph => EncodedTerm::DefaultGraph,
},
})
}
}
fn encode_quad_pattern_for_deletion(
&self,
quad: &QuadPattern,
quad: &GroundQuadPattern,
variables: &[Variable],
values: &[Option<EncodedTerm>],
) -> Result<Option<EncodedQuad>, EvaluationError> {
Ok(Some(EncodedQuad {
subject: if let Some(subject) =
self.encode_term_or_var_for_deletion(&quad.subject, variables, values)?
{
subject
} else {
return Ok(None);
},
predicate: if let Some(predicate) =
self.encode_named_node_or_var_for_deletion(&quad.predicate, variables, values)
{
predicate
} else {
return Ok(None);
},
object: if let Some(object) =
self.encode_term_or_var_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_or_var_for_deletion(graph_name, variables, values)
{
graph_name
} else {
return Ok(None);
}
} else {
EncodedTerm::DefaultGraph
},
}))
) -> Option<EncodedQuad> {
Some(EncodedQuad {
subject: self.encode_term_or_var_for_deletion(&quad.subject, variables, values)?,
predicate: self.encode_named_node_or_var_for_deletion(
&quad.predicate,
variables,
values,
)?,
object: self.encode_term_or_var_for_deletion(&quad.object, variables, values)?,
graph_name: self.encode_graph_name_or_var_for_deletion(
&quad.graph_name,
variables,
values,
)?,
})
}
fn encode_term_or_var_for_deletion(
&self,
term: &TermOrVariable,
term: &GroundTermOrVariable,
variables: &[Variable],
values: &[Option<EncodedTerm>],
) -> Result<Option<EncodedTerm>, EvaluationError> {
Ok(match term {
TermOrVariable::Term(term) => match term {
Term::NamedNode(term) => Some(self.encode_named_node_for_deletion(term)),
Term::BlankNode(_) => {
return Err(EvaluationError::msg(
"Blank nodes are not allowed in DELETE patterns",
))
}
Term::Literal(term) => Some(self.encode_literal_for_deletion(term)),
},
TermOrVariable::Variable(v) => {
if let Some(Some(term)) = variables
.iter()
.position(|v2| v == v2)
.and_then(|i| values.get(i))
{
Some(*term)
} else {
None
) -> Option<EncodedTerm> {
match term {
GroundTermOrVariable::NamedNode(term) => {
Some(self.encode_named_node_for_deletion(term))
}
GroundTermOrVariable::Literal(term) => Some(self.encode_literal_for_deletion(term)),
GroundTermOrVariable::Variable(v) => self.lookup_variable(v, variables, values),
}
})
}
fn encode_named_node_or_var_for_deletion(
@ -574,21 +527,24 @@ impl<'a> SimpleUpdateEvaluator<'a> {
) -> Option<EncodedTerm> {
match term {
NamedNodeOrVariable::NamedNode(term) => Some(self.encode_named_node_for_deletion(term)),
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
NamedNodeOrVariable::Variable(v) => self
.lookup_variable(v, variables, values)
.filter(|v| v.is_named_node()),
}
}
fn encode_graph_name_or_var_for_deletion(
&self,
graph_name: &GraphNameOrVariable,
variables: &[Variable],
values: &[Option<EncodedTerm>],
) -> Option<EncodedTerm> {
match graph_name {
GraphNameOrVariable::NamedNode(term) => Some(self.encode_named_node_for_deletion(term)),
GraphNameOrVariable::DefaultGraph => Some(EncodedTerm::DefaultGraph),
GraphNameOrVariable::Variable(v) => self
.lookup_variable(v, variables, values)
.filter(|v| v.is_named_node()),
}
}

@ -171,10 +171,10 @@ impl Store {
) -> QuadIter {
QuadIter {
iter: self.storage.quads_for_pattern(
subject.map(|s| get_encoded_named_or_blank_node(s)),
predicate.map(|p| get_encoded_named_node(p)),
object.map(|o| get_encoded_term(o)),
graph_name.map(|g| get_encoded_graph_name(g)),
subject.map(get_encoded_named_or_blank_node),
predicate.map(get_encoded_named_node),
object.map(get_encoded_term),
graph_name.map(get_encoded_graph_name),
),
storage: self.storage.clone(),
}

@ -55,7 +55,7 @@ pub struct QuadPattern {
pub subject: TermOrVariable,
pub predicate: NamedNodeOrVariable,
pub object: TermOrVariable,
pub graph_name: Option<NamedNodeOrVariable>,
pub graph_name: GraphNameOrVariable,
}
impl QuadPattern {
@ -63,31 +63,58 @@ impl QuadPattern {
subject: impl Into<TermOrVariable>,
predicate: impl Into<NamedNodeOrVariable>,
object: impl Into<TermOrVariable>,
graph_name: Option<NamedNodeOrVariable>,
graph_name: impl Into<GraphNameOrVariable>,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
graph_name,
graph_name: graph_name.into(),
}
}
}
impl fmt::Display for QuadPattern {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(graph_name) = &self.graph_name {
if self.graph_name == GraphNameOrVariable::DefaultGraph {
write!(
f,
"(graph {} (triple {} {} {}))",
graph_name, self.subject, self.predicate, self.object
"(triple {} {} {})",
self.subject, self.predicate, self.object
)
} else {
write!(
f,
"(graph {} (triple {} {} {}))",
self.graph_name, self.subject, self.predicate, self.object
)
}
}
}
/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph without blank nodes
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct GroundQuadPattern {
pub subject: GroundTermOrVariable,
pub predicate: NamedNodeOrVariable,
pub object: GroundTermOrVariable,
pub graph_name: GraphNameOrVariable,
}
impl fmt::Display for GroundQuadPattern {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.graph_name == GraphNameOrVariable::DefaultGraph {
write!(
f,
"(triple {} {} {})",
self.subject, self.predicate, self.object
)
} else {
write!(
f,
"(graph {} (triple {} {} {}))",
self.graph_name, self.subject, self.predicate, self.object
)
}
}
}
@ -96,18 +123,38 @@ pub(crate) struct SparqlQuadPattern<'a>(pub(crate) &'a QuadPattern);
impl<'a> fmt::Display for SparqlQuadPattern<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(graph_name) = &self.0.graph_name {
if self.0.graph_name == GraphNameOrVariable::DefaultGraph {
write!(
f,
"GRAPH {} {{ {} {} {} }}",
graph_name, self.0.subject, self.0.predicate, self.0.object
"{} {} {} .",
self.0.subject, self.0.predicate, self.0.object
)
} else {
write!(
f,
"GRAPH {} {{ {} {} {} }}",
self.0.graph_name, self.0.subject, self.0.predicate, self.0.object
)
}
}
}
pub(crate) struct SparqlGroundQuadPattern<'a>(pub(crate) &'a GroundQuadPattern);
impl<'a> fmt::Display for SparqlGroundQuadPattern<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0.graph_name == GraphNameOrVariable::DefaultGraph {
write!(
f,
"{} {} {} .",
self.0.subject, self.0.predicate, self.0.object
)
} else {
write!(
f,
"GRAPH {} {{ {} {} {} }}",
self.0.graph_name, self.0.subject, self.0.predicate, self.0.object
)
}
}
}
@ -566,7 +613,7 @@ pub enum GraphPattern {
/// A table used to provide inline values
Table {
variables: Vec<Variable>,
rows: Vec<Vec<Option<NamedNodeOrLiteral>>>,
rows: Vec<Vec<Option<GroundTerm>>>,
},
/// [OrderBy](https://www.w3.org/TR/sparql11-query/#defn_algOrdered)
OrderBy {
@ -1329,3 +1376,12 @@ impl From<NamedNode> for GraphTarget {
Self::NamedNode(node)
}
}
impl From<GraphName> for GraphTarget {
fn from(graph_name: GraphName) -> Self {
match graph_name {
GraphName::NamedNode(node) => Self::NamedNode(node),
GraphName::DefaultGraph => Self::DefaultGraph,
}
}
}

@ -454,7 +454,10 @@ fn build_select(
m
}
fn copy_graph(from: Option<NamedNode>, to: Option<NamedNodeOrVariable>) -> GraphUpdateOperation {
fn copy_graph(
from: impl Into<GraphName>,
to: impl Into<GraphNameOrVariable>,
) -> GraphUpdateOperation {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(
Variable { name: "s".into() },
Variable { name: "p".into() },
@ -469,13 +472,12 @@ fn copy_graph(from: Option<NamedNode>, to: Option<NamedNodeOrVariable>) -> Graph
to,
)],
using: None,
pattern: Box::new(if let Some(from) = from {
GraphPattern::Graph {
pattern: Box::new(match from.into() {
GraphName::NamedNode(from) => GraphPattern::Graph {
graph_name: from.into(),
inner: Box::new(bgp),
}
} else {
bgp
},
GraphName::DefaultGraph => bgp,
}),
}
}
@ -968,7 +970,7 @@ parser! {
//[31]
rule Load() -> Vec<GraphUpdateOperation> = i("LOAD") _ silent:Update1_silent() _ from:iri() _ to:Load_to()? {
vec![GraphUpdateOperation::Load { silent, from, to }]
vec![GraphUpdateOperation::Load { silent, from, to: to.map_or(GraphName::DefaultGraph, GraphName::NamedNode) }]
}
rule Load_to() -> NamedNode = i("INTO") _ g: GraphRef() { g }
@ -994,7 +996,7 @@ parser! {
Vec::new() // identity case
} else {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(Variable { name: "s".into() }, Variable { name: "p".into() }, Variable { name: "o".into() })]);
vec![copy_graph(from, to.map(NamedNodeOrVariable::NamedNode))]
vec![copy_graph(from, to)]
}
}
@ -1005,7 +1007,7 @@ parser! {
Vec::new() // identity case
} else {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(Variable { name: "s".into() }, Variable { name: "p".into() }, Variable { name: "o".into() })]);
vec![GraphUpdateOperation::Drop { silent: true, graph: to.clone().map_or(GraphTarget::DefaultGraph, GraphTarget::NamedNode) }, copy_graph(from.clone(), to.map(NamedNodeOrVariable::NamedNode)), GraphUpdateOperation::Drop { silent, graph: from.map_or(GraphTarget::DefaultGraph, GraphTarget::NamedNode) }]
vec![GraphUpdateOperation::Drop { silent: true, graph: to.clone().into() }, copy_graph(from.clone(), to), GraphUpdateOperation::Drop { silent, graph: from.into() }]
}
}
@ -1016,7 +1018,7 @@ parser! {
Vec::new() // identity case
} else {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(Variable { name: "s".into() }, Variable { name: "p".into() }, Variable{ name: "o".into() })]);
vec![GraphUpdateOperation::Drop { silent: true, graph: to.clone().map_or(GraphTarget::DefaultGraph, GraphTarget::NamedNode) }, copy_graph(from, to.map(NamedNodeOrVariable::NamedNode))]
vec![GraphUpdateOperation::Drop { silent: true, graph: to.clone().into() }, copy_graph(from, to)]
}
}
@ -1026,35 +1028,43 @@ parser! {
}
//[39]
rule DeleteData() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("DATA") _ data:QuadData() {?
if data.iter().any(|quad| matches!(quad.subject, NamedOrBlankNode::BlankNode(_)) || matches!(quad.object, Term::BlankNode(_))) {
Err("Blank nodes are not allowed in DELETE DATA")
} else {
Ok(vec![GraphUpdateOperation::DeleteData { data }])
}
rule DeleteData() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("DATA") _ data:GroundQuadData() {
vec![GraphUpdateOperation::DeleteData { data }]
}
//[40]
rule DeleteWhere() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("WHERE") _ d:QuadPattern() {?
if d.iter().any(|quad| matches!(quad.subject, TermOrVariable::Term(Term::BlankNode(_))) || matches!(quad.object, TermOrVariable::Term(Term::BlankNode(_)))) {
Err("Blank nodes are not allowed in DELETE WHERE")
} else {
let pattern = d.iter().map(|q| {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())]);
if let Some(graph_name) = &q.graph_name {
GraphPattern::Graph { graph_name: graph_name.clone(), inner: Box::new(bgp) }
} else {
bgp
match &q.graph_name {
GraphNameOrVariable::NamedNode(graph_name) => GraphPattern::Graph { graph_name: graph_name.clone().into(), inner: Box::new(bgp) },
GraphNameOrVariable::DefaultGraph => bgp,
GraphNameOrVariable::Variable(graph_name) => GraphPattern::Graph { graph_name: graph_name.clone().into(), inner: Box::new(bgp) },
}
}).fold(GraphPattern::Bgp(Vec::new()), new_join);
let delete = d.into_iter().map(|q| Ok(GroundQuadPattern {
subject: match q.subject {
TermOrVariable::NamedNode(subject) => subject.into(),
TermOrVariable::BlankNode(_) => return Err("Blank nodes are not allowed in DELETE WHERE"),
TermOrVariable::Literal(subject) => subject.into(),
TermOrVariable::Variable(subject) => subject.into(),
},
predicate: q.predicate,
object: match q.object {
TermOrVariable::NamedNode(object) => object.into(),
TermOrVariable::BlankNode(_) => return Err("Blank nodes are not allowed in DELETE WHERE"),
TermOrVariable::Literal(object) => object.into(),
TermOrVariable::Variable(object) => object.into(),
},
graph_name: q.graph_name
})).collect::<Result<Vec<_>,_>>()?;
Ok(vec![GraphUpdateOperation::DeleteInsert {
delete: d,
delete,
insert: Vec::new(),
using: None,
pattern: Box::new(pattern)
}])
}
}
//[41]
rule Modify() -> Vec<GraphUpdateOperation> = with:Modify_with()? _ Modify_clear() c:Modify_clauses() _ u:(UsingClause() ** (_)) _ i("WHERE") _ pattern:GroupGraphPattern() {
@ -1081,13 +1091,23 @@ parser! {
if let Some(with) = with {
// We inject WITH everywhere
delete = delete.into_iter().map(|q| if q.graph_name.is_none() {
QuadPattern::new(q.subject, q.predicate, q.object, Some(with.clone().into()))
delete = delete.into_iter().map(|q| if q.graph_name == GraphNameOrVariable::DefaultGraph {
GroundQuadPattern {
subject: q.subject,
predicate: q.predicate,
object: q.object,
graph_name: with.clone().into()
}
} else {
q
}).collect();
insert = insert.into_iter().map(|q| if q.graph_name.is_none() {
QuadPattern::new(q.subject, q.predicate, q.object, Some(with.clone().into()))
insert = insert.into_iter().map(|q| if q.graph_name == GraphNameOrVariable::DefaultGraph {
QuadPattern {
subject: q.subject,
predicate: q.predicate,
object: q.object,
graph_name: with.clone().into()
}
} else {
q
}).collect();
@ -1104,7 +1124,7 @@ parser! {
}]
}
rule Modify_with() -> NamedNode = i("WITH") _ i:iri() _ { i }
rule Modify_clauses() -> (Option<Vec<QuadPattern>>, Option<Vec<QuadPattern>>) = d:DeleteClause() _ i:InsertClause()? {
rule Modify_clauses() -> (Option<Vec<GroundQuadPattern>>, Option<Vec<QuadPattern>>) = d:DeleteClause() _ i:InsertClause()? {
(Some(d), i)
} / i:InsertClause() {
(None, Some(i))
@ -1115,12 +1135,23 @@ parser! {
}
//[42]
rule DeleteClause() -> Vec<QuadPattern> = i("DELETE") _ q:QuadPattern() {?
if q.iter().any(|quad| matches!(quad.subject, TermOrVariable::Term(Term::BlankNode(_))) || matches!(quad.object, TermOrVariable::Term(Term::BlankNode(_)))) {
Err("Blank nodes are not allowed in DELETE")
} else {
Ok(q)
}
rule DeleteClause() -> Vec<GroundQuadPattern> = i("DELETE") _ q:QuadPattern() {?
q.into_iter().map(|q| Ok(GroundQuadPattern {
subject: match q.subject {
TermOrVariable::NamedNode(subject) => subject.into(),
TermOrVariable::BlankNode(_) => return Err("Blank nodes are not allowed in DELETE WHERE"),
TermOrVariable::Literal(subject) => subject.into(),
TermOrVariable::Variable(subject) => subject.into(),
},
predicate: q.predicate,
object: match q.object {
TermOrVariable::NamedNode(object) => object.into(),
TermOrVariable::BlankNode(_) => return Err("Blank nodes are not allowed in DELETE WHERE"),
TermOrVariable::Literal(object) => object.into(),
TermOrVariable::Variable(object) => object.into(),
},
graph_name: q.graph_name
})).collect::<Result<Vec<_>,_>>()
}
//[43]
@ -1136,10 +1167,10 @@ parser! {
}
//[45]
rule GraphOrDefault() -> Option<NamedNode> = i("DEFAULT") {
None
rule GraphOrDefault() -> GraphName = i("DEFAULT") {
GraphName::DefaultGraph
} / (i("GRAPH") _)? g:iri() {
Some(g)
GraphName::NamedNode(g)
}
//[46]
@ -1158,24 +1189,49 @@ parser! {
rule QuadData() -> Vec<Quad> = "{" _ q:Quads() _ "}" {?
q.into_iter().map(|q| Ok(Quad {
subject: match q.subject {
TermOrVariable::Term(Term::NamedNode(t)) => t.into(),
TermOrVariable::Term(Term::BlankNode(t)) => t.into(),
_ => return Err(())
TermOrVariable::NamedNode(t) => t.into(),
TermOrVariable::BlankNode(t) => t.into(),
TermOrVariable::Literal(_) | TermOrVariable::Variable(_) => return Err(())
},
predicate: if let NamedNodeOrVariable::NamedNode(t) = q.predicate {
t
} else {
return Err(())
},
object: if let TermOrVariable::Term(t) = q.object {
object: match q.object {
TermOrVariable::NamedNode(t) => t.into(),
TermOrVariable::BlankNode(t) => t.into(),
TermOrVariable::Literal(t) => t.into(),
TermOrVariable::Variable(_) => return Err(())
},
graph_name: match q.graph_name {
GraphNameOrVariable::NamedNode(t) => t.into(),
GraphNameOrVariable::DefaultGraph => GraphName::DefaultGraph,
GraphNameOrVariable::Variable(_) => return Err(())
}
})).collect::<Result<Vec<_>, ()>>().map_err(|_| "Variables are not allowed in INSERT DATA and DELETE DATA")
}
rule GroundQuadData() -> Vec<GroundQuad> = "{" _ q:Quads() _ "}" {?
q.into_iter().map(|q| Ok(GroundQuad {
subject: if let TermOrVariable::NamedNode(t) = q.subject {
t
} else {
return Err(())
},
predicate: if let NamedNodeOrVariable::NamedNode(t) = q.predicate {
t
} else {
return Err(())
},
object: match q.object {
TermOrVariable::NamedNode(t) => t.into(),
TermOrVariable::Literal(t) => t.into(),
TermOrVariable::BlankNode(_) | TermOrVariable::Variable(_) => return Err(())
},
graph_name: match q.graph_name {
Some(NamedNodeOrVariable::NamedNode(t)) => t.into(),
None => GraphName::DefaultGraph,
_ => return Err(())
GraphNameOrVariable::NamedNode(t) => t.into(),
GraphNameOrVariable::DefaultGraph => GraphName::DefaultGraph,
GraphNameOrVariable::Variable(_) => return Err(())
}
})).collect::<Result<Vec<_>, ()>>().map_err(|_| "Variables are not allowed in INSERT DATA and DELETE DATA")
}
@ -1185,13 +1241,13 @@ parser! {
q.into_iter().flatten().collect()
}
rule Quads_TriplesTemplate() -> Vec<QuadPattern> = t:TriplesTemplate() {
t.into_iter().map(|t| QuadPattern::new(t.subject, t.predicate, t.object, None)).collect()
t.into_iter().map(|t| QuadPattern::new(t.subject, t.predicate, t.object, GraphNameOrVariable::DefaultGraph)).collect()
} //TODO: return iter?
rule Quads_QuadsNotTriples() -> Vec<QuadPattern> = q:QuadsNotTriples() _ "."? { q }
//[51]
rule QuadsNotTriples() -> Vec<QuadPattern> = i("GRAPH") _ g:VarOrIri() _ "{" _ t:TriplesTemplate()? _ "}" {
t.unwrap_or_else(Vec::new).into_iter().map(|t| QuadPattern::new(t.subject, t.predicate, t.object, Some(g.clone()))).collect()
t.unwrap_or_else(Vec::new).into_iter().map(|t| QuadPattern::new(t.subject, t.predicate, t.object, g.clone())).collect()
}
//[52]
@ -1305,21 +1361,21 @@ parser! {
}
//[63]
rule InlineDataOneVar() -> (Vec<Variable>, Vec<Vec<Option<NamedNodeOrLiteral>>>) = var:Var() _ "{" _ d:InlineDataOneVar_value()* "}" {
rule InlineDataOneVar() -> (Vec<Variable>, Vec<Vec<Option<GroundTerm>>>) = var:Var() _ "{" _ d:InlineDataOneVar_value()* "}" {
(vec![var], d)
}
rule InlineDataOneVar_value() -> Vec<Option<NamedNodeOrLiteral>> = t:DataBlockValue() _ { vec![t] }
rule InlineDataOneVar_value() -> Vec<Option<GroundTerm>> = t:DataBlockValue() _ { vec![t] }
//[64]
rule InlineDataFull() -> (Vec<Variable>, Vec<Vec<Option<NamedNodeOrLiteral>>>) = "(" _ vars:InlineDataFull_var()* _ ")" _ "{" _ val:InlineDataFull_values()* "}" {
rule InlineDataFull() -> (Vec<Variable>, Vec<Vec<Option<GroundTerm>>>) = "(" _ vars:InlineDataFull_var()* _ ")" _ "{" _ val:InlineDataFull_values()* "}" {
(vars, val)
}
rule InlineDataFull_var() -> Variable = v:Var() _ { v }
rule InlineDataFull_values() -> Vec<Option<NamedNodeOrLiteral>> = "(" _ v:InlineDataFull_value()* _ ")" _ { v }
rule InlineDataFull_value() -> Option<NamedNodeOrLiteral> = v:DataBlockValue() _ { v }
rule InlineDataFull_values() -> Vec<Option<GroundTerm>> = "(" _ v:InlineDataFull_value()* _ ")" _ { v }
rule InlineDataFull_value() -> Option<GroundTerm> = v:DataBlockValue() _ { v }
//[65]
rule DataBlockValue() -> Option<NamedNodeOrLiteral> =
rule DataBlockValue() -> Option<GroundTerm> =
i:iri() { Some(i.into()) } /
l:RDFLiteral() { Some(l.into()) } /
l:NumericLiteral() { Some(l.into()) } /

@ -163,14 +163,14 @@ impl fmt::Display for NamedOrBlankNode {
impl From<NamedNode> for NamedOrBlankNode {
#[inline]
fn from(node: NamedNode) -> Self {
NamedOrBlankNode::NamedNode(node)
Self::NamedNode(node)
}
}
impl From<BlankNode> for NamedOrBlankNode {
#[inline]
fn from(node: BlankNode) -> Self {
NamedOrBlankNode::BlankNode(node)
Self::BlankNode(node)
}
}
@ -178,32 +178,32 @@ impl From<BlankNode> for NamedOrBlankNode {
///
/// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum NamedNodeOrLiteral {
pub enum GroundTerm {
NamedNode(NamedNode),
Literal(Literal),
}
impl fmt::Display for NamedNodeOrLiteral {
impl fmt::Display for GroundTerm {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NamedNodeOrLiteral::NamedNode(node) => node.fmt(f),
NamedNodeOrLiteral::Literal(literal) => literal.fmt(f),
GroundTerm::NamedNode(node) => node.fmt(f),
GroundTerm::Literal(literal) => literal.fmt(f),
}
}
}
impl From<NamedNode> for NamedNodeOrLiteral {
impl From<NamedNode> for GroundTerm {
#[inline]
fn from(node: NamedNode) -> Self {
NamedNodeOrLiteral::NamedNode(node)
Self::NamedNode(node)
}
}
impl From<Literal> for NamedNodeOrLiteral {
impl From<Literal> for GroundTerm {
#[inline]
fn from(literal: Literal) -> Self {
NamedNodeOrLiteral::Literal(literal)
Self::Literal(literal)
}
}
@ -233,21 +233,21 @@ impl fmt::Display for Term {
impl From<NamedNode> for Term {
#[inline]
fn from(node: NamedNode) -> Self {
Term::NamedNode(node)
Self::NamedNode(node)
}
}
impl From<BlankNode> for Term {
#[inline]
fn from(node: BlankNode) -> Self {
Term::BlankNode(node)
Self::BlankNode(node)
}
}
impl From<Literal> for Term {
#[inline]
fn from(literal: Literal) -> Self {
Term::Literal(literal)
Self::Literal(literal)
}
}
@ -255,8 +255,8 @@ impl From<NamedOrBlankNode> for Term {
#[inline]
fn from(resource: NamedOrBlankNode) -> Self {
match resource {
NamedOrBlankNode::NamedNode(node) => Term::NamedNode(node),
NamedOrBlankNode::BlankNode(node) => Term::BlankNode(node),
NamedOrBlankNode::NamedNode(node) => Self::NamedNode(node),
NamedOrBlankNode::BlankNode(node) => Self::BlankNode(node),
}
}
}
@ -282,7 +282,7 @@ impl fmt::Display for GraphName {
impl From<NamedNode> for GraphName {
#[inline]
fn from(node: NamedNode) -> Self {
GraphName::NamedNode(node)
Self::NamedNode(node)
}
}
@ -327,6 +327,47 @@ impl fmt::Display for Quad {
}
}
/// A [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in a [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) without blank nodes.
///
/// The default string formatter is returning a N-Quads representation.
///
/// ```
/// use spargebra::term::NamedNode;
/// use spargebra::term::GroundQuad;
///
/// assert_eq!(
/// "<http://example.com/foo> <http://schema.org/sameAs> <http://example.com/foo> <http://example.com/> .",
/// GroundQuad {
/// subject: NamedNode { iri: "http://example.com/foo".into() }.into(),
/// predicate: NamedNode { iri: "http://schema.org/sameAs".into() },
/// object: NamedNode { iri: "http://example.com/foo".into() }.into(),
/// graph_name: NamedNode { iri: "http://example.com/".into() }.into(),
/// }.to_string()
/// )
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct GroundQuad {
pub subject: NamedNode,
pub predicate: NamedNode,
pub object: GroundTerm,
pub graph_name: GraphName,
}
impl fmt::Display for GroundQuad {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.graph_name == GraphName::DefaultGraph {
write!(f, "{} {} {} .", self.subject, self.predicate, self.object)
} else {
write!(
f,
"{} {} {} {} .",
self.subject, self.predicate, self.object, self.graph_name
)
}
}
}
/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum NamedNodeOrVariable {
@ -345,27 +386,85 @@ impl fmt::Display for NamedNodeOrVariable {
impl From<NamedNode> for NamedNodeOrVariable {
fn from(node: NamedNode) -> Self {
NamedNodeOrVariable::NamedNode(node)
Self::NamedNode(node)
}
}
impl From<Variable> for NamedNodeOrVariable {
fn from(var: Variable) -> Self {
NamedNodeOrVariable::Variable(var)
Self::Variable(var)
}
}
/// The union of [terms](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GroundTermOrVariable {
NamedNode(NamedNode),
Literal(Literal),
Variable(Variable),
}
impl fmt::Display for GroundTermOrVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GroundTermOrVariable::NamedNode(term) => term.fmt(f),
GroundTermOrVariable::Literal(term) => term.fmt(f),
GroundTermOrVariable::Variable(var) => var.fmt(f),
}
}
}
impl From<NamedNode> for GroundTermOrVariable {
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<Literal> for GroundTermOrVariable {
fn from(literal: Literal) -> Self {
Self::Literal(literal)
}
}
impl From<Variable> for GroundTermOrVariable {
fn from(var: Variable) -> Self {
Self::Variable(var)
}
}
impl From<GroundTerm> for GroundTermOrVariable {
fn from(term: GroundTerm) -> Self {
match term {
GroundTerm::NamedNode(node) => Self::NamedNode(node),
GroundTerm::Literal(literal) => Self::Literal(literal),
}
}
}
impl From<NamedNodeOrVariable> for GroundTermOrVariable {
fn from(element: NamedNodeOrVariable) -> Self {
match element {
NamedNodeOrVariable::NamedNode(node) => Self::NamedNode(node),
NamedNodeOrVariable::Variable(var) => Self::Variable(var),
}
}
}
/// The union of [terms](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum TermOrVariable {
Term(Term),
NamedNode(NamedNode),
BlankNode(BlankNode),
Literal(Literal),
Variable(Variable),
}
impl fmt::Display for TermOrVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TermOrVariable::Term(term) => term.fmt(f),
TermOrVariable::NamedNode(term) => term.fmt(f),
TermOrVariable::BlankNode(term) => term.fmt(f),
TermOrVariable::Literal(term) => term.fmt(f),
TermOrVariable::Variable(var) => var.fmt(f),
}
}
@ -373,39 +472,91 @@ impl fmt::Display for TermOrVariable {
impl From<NamedNode> for TermOrVariable {
fn from(node: NamedNode) -> Self {
TermOrVariable::Term(node.into())
Self::NamedNode(node)
}
}
impl From<BlankNode> for TermOrVariable {
fn from(node: BlankNode) -> Self {
TermOrVariable::Term(node.into())
Self::BlankNode(node)
}
}
impl From<Literal> for TermOrVariable {
fn from(literal: Literal) -> Self {
TermOrVariable::Term(literal.into())
Self::Literal(literal)
}
}
impl From<Variable> for TermOrVariable {
fn from(var: Variable) -> Self {
TermOrVariable::Variable(var)
Self::Variable(var)
}
}
impl From<Term> for TermOrVariable {
fn from(term: Term) -> Self {
TermOrVariable::Term(term)
match term {
Term::NamedNode(node) => Self::NamedNode(node),
Term::BlankNode(node) => Self::BlankNode(node),
Term::Literal(literal) => Self::Literal(literal),
}
}
}
impl From<NamedNodeOrVariable> for TermOrVariable {
fn from(element: NamedNodeOrVariable) -> Self {
match element {
NamedNodeOrVariable::NamedNode(node) => TermOrVariable::Term(node.into()),
NamedNodeOrVariable::Variable(var) => TermOrVariable::Variable(var),
NamedNodeOrVariable::NamedNode(node) => Self::NamedNode(node),
NamedNodeOrVariable::Variable(var) => Self::Variable(var),
}
}
}
/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [default graph name](https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GraphNameOrVariable {
NamedNode(NamedNode),
DefaultGraph,
Variable(Variable),
}
impl fmt::Display for GraphNameOrVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GraphNameOrVariable::NamedNode(node) => node.fmt(f),
GraphNameOrVariable::DefaultGraph => f.write_str("DEFAULT"),
GraphNameOrVariable::Variable(var) => var.fmt(f),
}
}
}
impl From<NamedNode> for GraphNameOrVariable {
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<Variable> for GraphNameOrVariable {
fn from(var: Variable) -> Self {
Self::Variable(var)
}
}
impl From<GraphName> for GraphNameOrVariable {
fn from(graph_name: GraphName) -> Self {
match graph_name {
GraphName::NamedNode(node) => Self::NamedNode(node),
GraphName::DefaultGraph => Self::DefaultGraph,
}
}
}
impl From<NamedNodeOrVariable> for GraphNameOrVariable {
fn from(graph_name: NamedNodeOrVariable) -> Self {
match graph_name {
NamedNodeOrVariable::NamedNode(node) => Self::NamedNode(node),
NamedNodeOrVariable::Variable(var) => Self::Variable(var),
}
}
}

@ -70,28 +70,28 @@ impl<'a> TryFrom<&'a String> for Update {
/// The [graph update operations](https://www.w3.org/TR/sparql11-update/#formalModelGraphUpdate)
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GraphUpdateOperation {
/// [insert data](https://www.w3.org/TR/sparql11-update/#def_insertdataoperation)
/// [insert data](https://www.w3.org/TR/sparql11-update/#defn_insertDataOperation)
InsertData { data: Vec<Quad> },
/// [delete data](https://www.w3.org/TR/sparql11-update/#def_deletedataoperation)
DeleteData { data: Vec<Quad> },
/// [delete insert](https://www.w3.org/TR/sparql11-update/#def_deleteinsertoperation)
/// [delete data](https://www.w3.org/TR/sparql11-update/#defn_deleteDataOperation)
DeleteData { data: Vec<GroundQuad> },
/// [delete insert](https://www.w3.org/TR/sparql11-update/#defn_deleteInsertOperation)
DeleteInsert {
delete: Vec<QuadPattern>,
delete: Vec<GroundQuadPattern>,
insert: Vec<QuadPattern>,
using: Option<QueryDataset>,
pattern: Box<GraphPattern>,
},
/// [load](https://www.w3.org/TR/sparql11-update/#def_loadoperation)
/// [load](https://www.w3.org/TR/sparql11-update/#defn_loadOperation)
Load {
silent: bool,
from: NamedNode,
to: Option<NamedNode>,
to: GraphName,
},
/// [clear](https://www.w3.org/TR/sparql11-update/#def_clearoperation)
/// [clear](https://www.w3.org/TR/sparql11-update/#defn_clearOperation)
Clear { silent: bool, graph: GraphTarget },
/// [create](https://www.w3.org/TR/sparql11-update/#def_createoperation)
/// [create](https://www.w3.org/TR/sparql11-update/#defn_createOperation)
Create { silent: bool, graph: NamedNode },
/// [drop](https://www.w3.org/TR/sparql11-update/#def_dropoperation)
/// [drop](https://www.w3.org/TR/sparql11-update/#defn_dropOperation)
Drop { silent: bool, graph: GraphTarget },
}
@ -105,7 +105,7 @@ impl fmt::Display for GraphUpdateOperation {
}
GraphUpdateOperation::DeleteData { data } => {
writeln!(f, "DELETE DATA {{")?;
write_quads(data, f)?;
write_ground_quads(data, f)?;
write!(f, "}}")
}
GraphUpdateOperation::DeleteInsert {
@ -117,7 +117,7 @@ impl fmt::Display for GraphUpdateOperation {
if !delete.is_empty() {
writeln!(f, "DELETE {{")?;
for quad in delete {
writeln!(f, "\t{}", SparqlQuadPattern(quad))?;
writeln!(f, "\t{}", SparqlGroundQuadPattern(quad))?;
}
writeln!(f, "}}")?;
}
@ -153,7 +153,7 @@ impl fmt::Display for GraphUpdateOperation {
write!(f, "SILENT ")?;
}
write!(f, "{}", from)?;
if let Some(to) = to {
if to != &GraphName::DefaultGraph {
write!(f, " INTO GRAPH {}", to)?;
}
Ok(())
@ -197,3 +197,18 @@ fn write_quads(quads: &[Quad], f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
Ok(())
}
fn write_ground_quads(quads: &[GroundQuad], f: &mut fmt::Formatter<'_>) -> fmt::Result {
for quad in quads {
if quad.graph_name == GraphName::DefaultGraph {
writeln!(f, "\t{} {} {} .", quad.subject, quad.predicate, quad.object)?;
} else {
writeln!(
f,
"\tGRAPH {} {{ {} {} {} }}",
quad.graph_name, quad.subject, quad.predicate, quad.object
)?;
}
}
Ok(())
}

Loading…
Cancel
Save