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) => { TermOrVariable::Variable(variable) => {
PatternValue::Variable(variable_key(variables, 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( PatternValue::Variable(variable_key(
variables, variables,
&Variable { &Variable {
@ -784,7 +785,9 @@ impl<'a> PlanBuilder<'a> {
)) ))
//TODO: very bad hack to convert bnode to variable //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( fn encode_bindings(
&mut self, &mut self,
table_variables: &[Variable], table_variables: &[Variable],
rows: &[Vec<Option<NamedNodeOrLiteral>>], rows: &[Vec<Option<GroundTerm>>],
variables: &mut Vec<Variable>, variables: &mut Vec<Variable>,
) -> Result<Vec<EncodedTuple>, EvaluationError> { ) -> Result<Vec<EncodedTuple>, EvaluationError> {
let bindings_variables_keys = table_variables let bindings_variables_keys = table_variables
@ -821,8 +824,8 @@ impl<'a> PlanBuilder<'a> {
result.set( result.set(
bindings_variables_keys[key], bindings_variables_keys[key],
match term { match term {
NamedNodeOrLiteral::NamedNode(node) => self.build_named_node(node), GroundTerm::NamedNode(node) => self.build_named_node(node),
NamedNodeOrLiteral::Literal(literal) => self.build_literal(literal), GroundTerm::Literal(literal) => self.build_literal(literal),
}?, }?,
); );
} }
@ -926,10 +929,15 @@ impl<'a> PlanBuilder<'a> {
TermOrVariable::Variable(variable) => { TermOrVariable::Variable(variable) => {
TripleTemplateValue::Variable(variable_key(variables, 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)) 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 { fn variable_key(variables: &mut Vec<Variable>, variable: &Variable) -> usize {
@ -1130,7 +1130,7 @@ fn count_pattern_binds(
if !assigned_variables.contains(v) { if !assigned_variables.contains(v) {
count -= 4; 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) { if !assigned_blank_nodes.contains(bnode) {
count -= 4; count -= 4;
} }
@ -1148,7 +1148,7 @@ fn count_pattern_binds(
if !assigned_variables.contains(v) { if !assigned_variables.contains(v) {
count -= 4; 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) { if !assigned_blank_nodes.contains(bnode) {
count -= 4; count -= 4;
} }
@ -1165,7 +1165,7 @@ fn add_pattern_variables<'a>(
) { ) {
if let TermOrVariable::Variable(v) = &pattern.subject { if let TermOrVariable::Variable(v) = &pattern.subject {
variables.insert(v); 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); blank_nodes.insert(bnode);
} }
if let NamedNodeOrVariable::Variable(v) = &pattern.predicate { if let NamedNodeOrVariable::Variable(v) = &pattern.predicate {
@ -1173,7 +1173,7 @@ fn add_pattern_variables<'a>(
} }
if let TermOrVariable::Variable(v) = &pattern.object { if let TermOrVariable::Variable(v) = &pattern.object {
variables.insert(v); 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); blank_nodes.insert(bnode);
} }
} }

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

@ -55,7 +55,7 @@ pub struct QuadPattern {
pub subject: TermOrVariable, pub subject: TermOrVariable,
pub predicate: NamedNodeOrVariable, pub predicate: NamedNodeOrVariable,
pub object: TermOrVariable, pub object: TermOrVariable,
pub graph_name: Option<NamedNodeOrVariable>, pub graph_name: GraphNameOrVariable,
} }
impl QuadPattern { impl QuadPattern {
@ -63,31 +63,58 @@ impl QuadPattern {
subject: impl Into<TermOrVariable>, subject: impl Into<TermOrVariable>,
predicate: impl Into<NamedNodeOrVariable>, predicate: impl Into<NamedNodeOrVariable>,
object: impl Into<TermOrVariable>, object: impl Into<TermOrVariable>,
graph_name: Option<NamedNodeOrVariable>, graph_name: impl Into<GraphNameOrVariable>,
) -> Self { ) -> Self {
Self { Self {
subject: subject.into(), subject: subject.into(),
predicate: predicate.into(), predicate: predicate.into(),
object: object.into(), object: object.into(),
graph_name, graph_name: graph_name.into(),
} }
} }
} }
impl fmt::Display for QuadPattern { impl fmt::Display for QuadPattern {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(graph_name) = &self.graph_name { if self.graph_name == GraphNameOrVariable::DefaultGraph {
write!( write!(
f, f,
"(graph {} (triple {} {} {}))", "(triple {} {} {})",
graph_name, self.subject, self.predicate, self.object self.subject, self.predicate, self.object
) )
} else { } 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!( write!(
f, f,
"(triple {} {} {})", "(triple {} {} {})",
self.subject, self.predicate, self.object 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> { impl<'a> fmt::Display for SparqlQuadPattern<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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!( write!(
f, f,
"GRAPH {} {{ {} {} {} }}", "{} {} {} .",
graph_name, self.0.subject, self.0.predicate, self.0.object self.0.subject, self.0.predicate, self.0.object
) )
} else { } 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!( write!(
f, f,
"{} {} {} .", "{} {} {} .",
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
)
} }
} }
} }
@ -566,7 +613,7 @@ pub enum GraphPattern {
/// A table used to provide inline values /// A table used to provide inline values
Table { Table {
variables: Vec<Variable>, variables: Vec<Variable>,
rows: Vec<Vec<Option<NamedNodeOrLiteral>>>, rows: Vec<Vec<Option<GroundTerm>>>,
}, },
/// [OrderBy](https://www.w3.org/TR/sparql11-query/#defn_algOrdered) /// [OrderBy](https://www.w3.org/TR/sparql11-query/#defn_algOrdered)
OrderBy { OrderBy {
@ -1329,3 +1376,12 @@ impl From<NamedNode> for GraphTarget {
Self::NamedNode(node) 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 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( let bgp = GraphPattern::Bgp(vec![TriplePattern::new(
Variable { name: "s".into() }, Variable { name: "s".into() },
Variable { name: "p".into() }, Variable { name: "p".into() },
@ -469,13 +472,12 @@ fn copy_graph(from: Option<NamedNode>, to: Option<NamedNodeOrVariable>) -> Graph
to, to,
)], )],
using: None, using: None,
pattern: Box::new(if let Some(from) = from { pattern: Box::new(match from.into() {
GraphPattern::Graph { GraphName::NamedNode(from) => GraphPattern::Graph {
graph_name: from.into(), graph_name: from.into(),
inner: Box::new(bgp), inner: Box::new(bgp),
} },
} else { GraphName::DefaultGraph => bgp,
bgp
}), }),
} }
} }
@ -968,7 +970,7 @@ parser! {
//[31] //[31]
rule Load() -> Vec<GraphUpdateOperation> = i("LOAD") _ silent:Update1_silent() _ from:iri() _ to:Load_to()? { 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 } rule Load_to() -> NamedNode = i("INTO") _ g: GraphRef() { g }
@ -994,7 +996,7 @@ parser! {
Vec::new() // identity case Vec::new() // identity case
} else { } else {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(Variable { name: "s".into() }, Variable { name: "p".into() }, Variable { name: "o".into() })]); 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 Vec::new() // identity case
} else { } else {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(Variable { name: "s".into() }, Variable { name: "p".into() }, Variable { name: "o".into() })]); 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 Vec::new() // identity case
} else { } else {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(Variable { name: "s".into() }, Variable { name: "p".into() }, Variable{ name: "o".into() })]); 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] //[39]
rule DeleteData() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("DATA") _ data:QuadData() {? rule DeleteData() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("DATA") _ data:GroundQuadData() {
if data.iter().any(|quad| matches!(quad.subject, NamedOrBlankNode::BlankNode(_)) || matches!(quad.object, Term::BlankNode(_))) { vec![GraphUpdateOperation::DeleteData { data }]
Err("Blank nodes are not allowed in DELETE DATA")
} else {
Ok(vec![GraphUpdateOperation::DeleteData { data }])
}
} }
//[40] //[40]
rule DeleteWhere() -> Vec<GraphUpdateOperation> = i("DELETE") _ i("WHERE") _ d:QuadPattern() {? 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 pattern = d.iter().map(|q| {
let bgp = GraphPattern::Bgp(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())]); let bgp = GraphPattern::Bgp(vec![TriplePattern::new(q.subject.clone(), q.predicate.clone(), q.object.clone())]);
if let Some(graph_name) = &q.graph_name { match &q.graph_name {
GraphPattern::Graph { graph_name: graph_name.clone(), inner: Box::new(bgp) } GraphNameOrVariable::NamedNode(graph_name) => GraphPattern::Graph { graph_name: graph_name.clone().into(), inner: Box::new(bgp) },
} else { GraphNameOrVariable::DefaultGraph => bgp,
bgp GraphNameOrVariable::Variable(graph_name) => GraphPattern::Graph { graph_name: graph_name.clone().into(), inner: Box::new(bgp) },
} }
}).fold(GraphPattern::Bgp(Vec::new()), new_join); }).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 { Ok(vec![GraphUpdateOperation::DeleteInsert {
delete: d, delete,
insert: Vec::new(), insert: Vec::new(),
using: None, using: None,
pattern: Box::new(pattern) pattern: Box::new(pattern)
}]) }])
} }
}
//[41] //[41]
rule Modify() -> Vec<GraphUpdateOperation> = with:Modify_with()? _ Modify_clear() c:Modify_clauses() _ u:(UsingClause() ** (_)) _ i("WHERE") _ pattern:GroupGraphPattern() { 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 { if let Some(with) = with {
// We inject WITH everywhere // We inject WITH everywhere
delete = delete.into_iter().map(|q| if q.graph_name.is_none() { delete = delete.into_iter().map(|q| if q.graph_name == GraphNameOrVariable::DefaultGraph {
QuadPattern::new(q.subject, q.predicate, q.object, Some(with.clone().into())) GroundQuadPattern {
subject: q.subject,
predicate: q.predicate,
object: q.object,
graph_name: with.clone().into()
}
} else { } else {
q q
}).collect(); }).collect();
insert = insert.into_iter().map(|q| if q.graph_name.is_none() { insert = insert.into_iter().map(|q| if q.graph_name == GraphNameOrVariable::DefaultGraph {
QuadPattern::new(q.subject, q.predicate, q.object, Some(with.clone().into())) QuadPattern {
subject: q.subject,
predicate: q.predicate,
object: q.object,
graph_name: with.clone().into()
}
} else { } else {
q q
}).collect(); }).collect();
@ -1104,7 +1124,7 @@ parser! {
}] }]
} }
rule Modify_with() -> NamedNode = i("WITH") _ i:iri() _ { i } 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) (Some(d), i)
} / i:InsertClause() { } / i:InsertClause() {
(None, Some(i)) (None, Some(i))
@ -1115,12 +1135,23 @@ parser! {
} }
//[42] //[42]
rule DeleteClause() -> Vec<QuadPattern> = i("DELETE") _ q:QuadPattern() {? rule DeleteClause() -> Vec<GroundQuadPattern> = i("DELETE") _ q:QuadPattern() {?
if q.iter().any(|quad| matches!(quad.subject, TermOrVariable::Term(Term::BlankNode(_))) || matches!(quad.object, TermOrVariable::Term(Term::BlankNode(_)))) { q.into_iter().map(|q| Ok(GroundQuadPattern {
Err("Blank nodes are not allowed in DELETE") subject: match q.subject {
} else { TermOrVariable::NamedNode(subject) => subject.into(),
Ok(q) 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] //[43]
@ -1136,10 +1167,10 @@ parser! {
} }
//[45] //[45]
rule GraphOrDefault() -> Option<NamedNode> = i("DEFAULT") { rule GraphOrDefault() -> GraphName = i("DEFAULT") {
None GraphName::DefaultGraph
} / (i("GRAPH") _)? g:iri() { } / (i("GRAPH") _)? g:iri() {
Some(g) GraphName::NamedNode(g)
} }
//[46] //[46]
@ -1158,24 +1189,49 @@ parser! {
rule QuadData() -> Vec<Quad> = "{" _ q:Quads() _ "}" {? rule QuadData() -> Vec<Quad> = "{" _ q:Quads() _ "}" {?
q.into_iter().map(|q| Ok(Quad { q.into_iter().map(|q| Ok(Quad {
subject: match q.subject { subject: match q.subject {
TermOrVariable::Term(Term::NamedNode(t)) => t.into(), TermOrVariable::NamedNode(t) => t.into(),
TermOrVariable::Term(Term::BlankNode(t)) => t.into(), TermOrVariable::BlankNode(t) => t.into(),
_ => return Err(()) TermOrVariable::Literal(_) | TermOrVariable::Variable(_) => return Err(())
}, },
predicate: if let NamedNodeOrVariable::NamedNode(t) = q.predicate { predicate: if let NamedNodeOrVariable::NamedNode(t) = q.predicate {
t t
} else { } else {
return Err(()) 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 t
} else { } else {
return Err(()) 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 { graph_name: match q.graph_name {
Some(NamedNodeOrVariable::NamedNode(t)) => t.into(), GraphNameOrVariable::NamedNode(t) => t.into(),
None => GraphName::DefaultGraph, GraphNameOrVariable::DefaultGraph => GraphName::DefaultGraph,
_ => return Err(()) GraphNameOrVariable::Variable(_) => return Err(())
} }
})).collect::<Result<Vec<_>, ()>>().map_err(|_| "Variables are not allowed in INSERT DATA and DELETE DATA") })).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() q.into_iter().flatten().collect()
} }
rule Quads_TriplesTemplate() -> Vec<QuadPattern> = t:TriplesTemplate() { 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? } //TODO: return iter?
rule Quads_QuadsNotTriples() -> Vec<QuadPattern> = q:QuadsNotTriples() _ "."? { q } rule Quads_QuadsNotTriples() -> Vec<QuadPattern> = q:QuadsNotTriples() _ "."? { q }
//[51] //[51]
rule QuadsNotTriples() -> Vec<QuadPattern> = i("GRAPH") _ g:VarOrIri() _ "{" _ t:TriplesTemplate()? _ "}" { 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] //[52]
@ -1305,21 +1361,21 @@ parser! {
} }
//[63] //[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) (vec![var], d)
} }
rule InlineDataOneVar_value() -> Vec<Option<NamedNodeOrLiteral>> = t:DataBlockValue() _ { vec![t] } rule InlineDataOneVar_value() -> Vec<Option<GroundTerm>> = t:DataBlockValue() _ { vec![t] }
//[64] //[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) (vars, val)
} }
rule InlineDataFull_var() -> Variable = v:Var() _ { v } rule InlineDataFull_var() -> Variable = v:Var() _ { v }
rule InlineDataFull_values() -> Vec<Option<NamedNodeOrLiteral>> = "(" _ v:InlineDataFull_value()* _ ")" _ { v } rule InlineDataFull_values() -> Vec<Option<GroundTerm>> = "(" _ v:InlineDataFull_value()* _ ")" _ { v }
rule InlineDataFull_value() -> Option<NamedNodeOrLiteral> = v:DataBlockValue() _ { v } rule InlineDataFull_value() -> Option<GroundTerm> = v:DataBlockValue() _ { v }
//[65] //[65]
rule DataBlockValue() -> Option<NamedNodeOrLiteral> = rule DataBlockValue() -> Option<GroundTerm> =
i:iri() { Some(i.into()) } / i:iri() { Some(i.into()) } /
l:RDFLiteral() { Some(l.into()) } / l:RDFLiteral() { Some(l.into()) } /
l:NumericLiteral() { Some(l.into()) } / l:NumericLiteral() { Some(l.into()) } /

@ -163,14 +163,14 @@ impl fmt::Display for NamedOrBlankNode {
impl From<NamedNode> for NamedOrBlankNode { impl From<NamedNode> for NamedOrBlankNode {
#[inline] #[inline]
fn from(node: NamedNode) -> Self { fn from(node: NamedNode) -> Self {
NamedOrBlankNode::NamedNode(node) Self::NamedNode(node)
} }
} }
impl From<BlankNode> for NamedOrBlankNode { impl From<BlankNode> for NamedOrBlankNode {
#[inline] #[inline]
fn from(node: BlankNode) -> Self { 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. /// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
#[derive(Eq, PartialEq, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum NamedNodeOrLiteral { pub enum GroundTerm {
NamedNode(NamedNode), NamedNode(NamedNode),
Literal(Literal), Literal(Literal),
} }
impl fmt::Display for NamedNodeOrLiteral { impl fmt::Display for GroundTerm {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
NamedNodeOrLiteral::NamedNode(node) => node.fmt(f), GroundTerm::NamedNode(node) => node.fmt(f),
NamedNodeOrLiteral::Literal(literal) => literal.fmt(f), GroundTerm::Literal(literal) => literal.fmt(f),
} }
} }
} }
impl From<NamedNode> for NamedNodeOrLiteral { impl From<NamedNode> for GroundTerm {
#[inline] #[inline]
fn from(node: NamedNode) -> Self { fn from(node: NamedNode) -> Self {
NamedNodeOrLiteral::NamedNode(node) Self::NamedNode(node)
} }
} }
impl From<Literal> for NamedNodeOrLiteral { impl From<Literal> for GroundTerm {
#[inline] #[inline]
fn from(literal: Literal) -> Self { 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 { impl From<NamedNode> for Term {
#[inline] #[inline]
fn from(node: NamedNode) -> Self { fn from(node: NamedNode) -> Self {
Term::NamedNode(node) Self::NamedNode(node)
} }
} }
impl From<BlankNode> for Term { impl From<BlankNode> for Term {
#[inline] #[inline]
fn from(node: BlankNode) -> Self { fn from(node: BlankNode) -> Self {
Term::BlankNode(node) Self::BlankNode(node)
} }
} }
impl From<Literal> for Term { impl From<Literal> for Term {
#[inline] #[inline]
fn from(literal: Literal) -> Self { fn from(literal: Literal) -> Self {
Term::Literal(literal) Self::Literal(literal)
} }
} }
@ -255,8 +255,8 @@ impl From<NamedOrBlankNode> for Term {
#[inline] #[inline]
fn from(resource: NamedOrBlankNode) -> Self { fn from(resource: NamedOrBlankNode) -> Self {
match resource { match resource {
NamedOrBlankNode::NamedNode(node) => Term::NamedNode(node), NamedOrBlankNode::NamedNode(node) => Self::NamedNode(node),
NamedOrBlankNode::BlankNode(node) => Term::BlankNode(node), NamedOrBlankNode::BlankNode(node) => Self::BlankNode(node),
} }
} }
} }
@ -282,7 +282,7 @@ impl fmt::Display for GraphName {
impl From<NamedNode> for GraphName { impl From<NamedNode> for GraphName {
#[inline] #[inline]
fn from(node: NamedNode) -> Self { 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). /// 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)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum NamedNodeOrVariable { pub enum NamedNodeOrVariable {
@ -345,27 +386,85 @@ impl fmt::Display for NamedNodeOrVariable {
impl From<NamedNode> for NamedNodeOrVariable { impl From<NamedNode> for NamedNodeOrVariable {
fn from(node: NamedNode) -> Self { fn from(node: NamedNode) -> Self {
NamedNodeOrVariable::NamedNode(node) Self::NamedNode(node)
} }
} }
impl From<Variable> for NamedNodeOrVariable { impl From<Variable> for NamedNodeOrVariable {
fn from(var: Variable) -> Self { 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). /// 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)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum TermOrVariable { pub enum TermOrVariable {
Term(Term), NamedNode(NamedNode),
BlankNode(BlankNode),
Literal(Literal),
Variable(Variable), Variable(Variable),
} }
impl fmt::Display for TermOrVariable { impl fmt::Display for TermOrVariable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { 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), TermOrVariable::Variable(var) => var.fmt(f),
} }
} }
@ -373,39 +472,91 @@ impl fmt::Display for TermOrVariable {
impl From<NamedNode> for TermOrVariable { impl From<NamedNode> for TermOrVariable {
fn from(node: NamedNode) -> Self { fn from(node: NamedNode) -> Self {
TermOrVariable::Term(node.into()) Self::NamedNode(node)
} }
} }
impl From<BlankNode> for TermOrVariable { impl From<BlankNode> for TermOrVariable {
fn from(node: BlankNode) -> Self { fn from(node: BlankNode) -> Self {
TermOrVariable::Term(node.into()) Self::BlankNode(node)
} }
} }
impl From<Literal> for TermOrVariable { impl From<Literal> for TermOrVariable {
fn from(literal: Literal) -> Self { fn from(literal: Literal) -> Self {
TermOrVariable::Term(literal.into()) Self::Literal(literal)
} }
} }
impl From<Variable> for TermOrVariable { impl From<Variable> for TermOrVariable {
fn from(var: Variable) -> Self { fn from(var: Variable) -> Self {
TermOrVariable::Variable(var) Self::Variable(var)
} }
} }
impl From<Term> for TermOrVariable { impl From<Term> for TermOrVariable {
fn from(term: Term) -> Self { 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 { impl From<NamedNodeOrVariable> for TermOrVariable {
fn from(element: NamedNodeOrVariable) -> Self { fn from(element: NamedNodeOrVariable) -> Self {
match element { match element {
NamedNodeOrVariable::NamedNode(node) => TermOrVariable::Term(node.into()), NamedNodeOrVariable::NamedNode(node) => Self::NamedNode(node),
NamedNodeOrVariable::Variable(var) => TermOrVariable::Variable(var), 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) /// The [graph update operations](https://www.w3.org/TR/sparql11-update/#formalModelGraphUpdate)
#[derive(Eq, PartialEq, Debug, Clone, Hash)] #[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GraphUpdateOperation { 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> }, InsertData { data: Vec<Quad> },
/// [delete data](https://www.w3.org/TR/sparql11-update/#def_deletedataoperation) /// [delete data](https://www.w3.org/TR/sparql11-update/#defn_deleteDataOperation)
DeleteData { data: Vec<Quad> }, DeleteData { data: Vec<GroundQuad> },
/// [delete insert](https://www.w3.org/TR/sparql11-update/#def_deleteinsertoperation) /// [delete insert](https://www.w3.org/TR/sparql11-update/#defn_deleteInsertOperation)
DeleteInsert { DeleteInsert {
delete: Vec<QuadPattern>, delete: Vec<GroundQuadPattern>,
insert: Vec<QuadPattern>, insert: Vec<QuadPattern>,
using: Option<QueryDataset>, using: Option<QueryDataset>,
pattern: Box<GraphPattern>, pattern: Box<GraphPattern>,
}, },
/// [load](https://www.w3.org/TR/sparql11-update/#def_loadoperation) /// [load](https://www.w3.org/TR/sparql11-update/#defn_loadOperation)
Load { Load {
silent: bool, silent: bool,
from: NamedNode, 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 }, 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 }, 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 }, Drop { silent: bool, graph: GraphTarget },
} }
@ -105,7 +105,7 @@ impl fmt::Display for GraphUpdateOperation {
} }
GraphUpdateOperation::DeleteData { data } => { GraphUpdateOperation::DeleteData { data } => {
writeln!(f, "DELETE DATA {{")?; writeln!(f, "DELETE DATA {{")?;
write_quads(data, f)?; write_ground_quads(data, f)?;
write!(f, "}}") write!(f, "}}")
} }
GraphUpdateOperation::DeleteInsert { GraphUpdateOperation::DeleteInsert {
@ -117,7 +117,7 @@ impl fmt::Display for GraphUpdateOperation {
if !delete.is_empty() { if !delete.is_empty() {
writeln!(f, "DELETE {{")?; writeln!(f, "DELETE {{")?;
for quad in delete { for quad in delete {
writeln!(f, "\t{}", SparqlQuadPattern(quad))?; writeln!(f, "\t{}", SparqlGroundQuadPattern(quad))?;
} }
writeln!(f, "}}")?; writeln!(f, "}}")?;
} }
@ -153,7 +153,7 @@ impl fmt::Display for GraphUpdateOperation {
write!(f, "SILENT ")?; write!(f, "SILENT ")?;
} }
write!(f, "{}", from)?; write!(f, "{}", from)?;
if let Some(to) = to { if to != &GraphName::DefaultGraph {
write!(f, " INTO GRAPH {}", to)?; write!(f, " INTO GRAPH {}", to)?;
} }
Ok(()) Ok(())
@ -197,3 +197,18 @@ fn write_quads(quads: &[Quad], f: &mut fmt::Formatter<'_>) -> fmt::Result {
} }
Ok(()) 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