Fork of https://github.com/oxigraph/oxigraph.git for the purpose of NextGraph project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
oxigraph/spargebra/src/update.rs

322 lines
10 KiB

use crate::algebra::*;
use crate::parser::{parse_update, ParseError};
use crate::term::*;
use oxiri::Iri;
use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;
/// A parsed [SPARQL update](https://www.w3.org/TR/sparql11-update/)
///
/// ```
/// use spargebra::Update;
///
/// let update_str = "CLEAR ALL ;";
/// let update = Update::parse(update_str, None)?;
/// assert_eq!(update.to_string().trim(), update_str);
/// # Result::Ok::<_, spargebra::ParseError>(())
/// ```
#[derive(Eq, PartialEq, Clone, Hash)]
pub struct Update {
/// The update base IRI
pub base_iri: Option<Iri<String>>,
/// The [update operations](https://www.w3.org/TR/sparql11-update/#formalModelGraphUpdate)
pub operations: Vec<GraphUpdateOperation>,
}
impl Update {
/// Parses a SPARQL update with an optional base IRI to resolve relative IRIs in the query
pub fn parse(update: &str, base_iri: Option<&str>) -> Result<Self, ParseError> {
parse_update(update, base_iri)
}
}
impl fmt::Debug for Update {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(base_iri) = &self.base_iri {
write!(f, "(base <{}> ", base_iri)?;
}
write!(f, "(update")?;
for op in &self.operations {
write!(f, " {:?}", op)?;
}
write!(f, ")")?;
if self.base_iri.is_some() {
write!(f, ")")?;
}
Ok(())
}
}
impl fmt::Display for Update {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(base_iri) = &self.base_iri {
writeln!(f, "BASE <{}>", base_iri)?;
}
for update in &self.operations {
writeln!(f, "{} ;", update)?;
}
Ok(())
}
}
impl FromStr for Update {
type Err = ParseError;
fn from_str(update: &str) -> Result<Self, ParseError> {
Self::parse(update, None)
}
}
impl<'a> TryFrom<&'a str> for Update {
type Error = ParseError;
fn try_from(update: &str) -> Result<Self, ParseError> {
Self::from_str(update)
}
}
impl<'a> TryFrom<&'a String> for Update {
type Error = ParseError;
fn try_from(update: &String) -> Result<Self, ParseError> {
Self::from_str(update)
}
}
/// The [graph update operations](https://www.w3.org/TR/sparql11-update/#formalModelGraphUpdate)
#[derive(Eq, PartialEq, Clone, Hash)]
pub enum GraphUpdateOperation {
/// [insert data](https://www.w3.org/TR/sparql11-update/#defn_insertDataOperation)
InsertData { data: Vec<Quad> },
/// [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<GroundQuadPattern>,
insert: Vec<QuadPattern>,
using: Option<QueryDataset>,
pattern: Box<GraphPattern>,
},
/// [load](https://www.w3.org/TR/sparql11-update/#defn_loadOperation)
Load {
silent: bool,
from: NamedNode,
to: GraphName,
},
/// [clear](https://www.w3.org/TR/sparql11-update/#defn_clearOperation)
Clear { silent: bool, graph: GraphTarget },
/// [create](https://www.w3.org/TR/sparql11-update/#defn_createOperation)
Create { silent: bool, graph: NamedNode },
/// [drop](https://www.w3.org/TR/sparql11-update/#defn_dropOperation)
Drop { silent: bool, graph: GraphTarget },
}
impl fmt::Debug for GraphUpdateOperation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GraphUpdateOperation::InsertData { data } => {
write!(f, "(insertData (")?;
for (i, t) in data.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
write!(f, "{:?}", t)?;
}
write!(f, "))")
}
GraphUpdateOperation::DeleteData { data } => {
write!(f, "(deleteData (")?;
for (i, t) in data.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
write!(f, "{:?}", t)?;
}
write!(f, "))")
}
GraphUpdateOperation::DeleteInsert {
delete,
insert,
using,
pattern,
} => {
write!(f, "(modify")?;
if let Some(using) = using {
write!(f, " (using {:?}", using)?;
}
write!(f, " {:?}", pattern)?;
if using.is_some() {
write!(f, ")")?;
}
if !delete.is_empty() {
write!(f, " (delete (")?;
for (i, t) in delete.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
write!(f, "{:?}", t)?;
}
write!(f, "))")?;
}
if !insert.is_empty() {
write!(f, " (insert (")?;
for (i, t) in insert.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
write!(f, "{:?}", t)?;
}
write!(f, "))")?;
}
write!(f, ")")
}
GraphUpdateOperation::Load { silent, from, to } => {
write!(f, "(load")?;
if *silent {
write!(f, " silent")?;
}
write!(f, " {:?} {:?}", from, to)
}
GraphUpdateOperation::Clear { silent, graph } => {
write!(f, "(clear")?;
if *silent {
write!(f, " silent")?;
}
write!(f, " {:?})", graph)
}
GraphUpdateOperation::Create { silent, graph } => {
write!(f, "(create")?;
if *silent {
write!(f, " silent")?;
}
write!(f, " {:?})", graph)
}
GraphUpdateOperation::Drop { silent, graph } => {
write!(f, "(drop")?;
if *silent {
write!(f, " silent")?;
}
write!(f, " {:?})", graph)
}
}
}
}
impl fmt::Display for GraphUpdateOperation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GraphUpdateOperation::InsertData { data } => {
writeln!(f, "INSERT DATA {{")?;
write_quads(data, f)?;
write!(f, "}}")
}
GraphUpdateOperation::DeleteData { data } => {
writeln!(f, "DELETE DATA {{")?;
write_ground_quads(data, f)?;
write!(f, "}}")
}
GraphUpdateOperation::DeleteInsert {
delete,
insert,
using,
pattern,
} => {
if !delete.is_empty() {
writeln!(f, "DELETE {{")?;
for quad in delete {
writeln!(f, "\t{} .", quad)?;
}
writeln!(f, "}}")?;
}
if !insert.is_empty() {
writeln!(f, "INSERT {{")?;
for quad in insert {
writeln!(f, "\t{} .", quad)?;
}
writeln!(f, "}}")?;
}
if let Some(using) = using {
for g in &using.default {
writeln!(f, "USING {}", g)?;
}
if let Some(named) = &using.named {
for g in named {
writeln!(f, "USING NAMED {}", g)?;
}
}
}
write!(
f,
"WHERE {{ {} }}",
SparqlGraphRootPattern {
pattern,
dataset: None
}
)
}
GraphUpdateOperation::Load { silent, from, to } => {
write!(f, "LOAD ")?;
if *silent {
write!(f, "SILENT ")?;
}
write!(f, "{}", from)?;
if to != &GraphName::DefaultGraph {
write!(f, " INTO GRAPH {}", to)?;
}
Ok(())
}
GraphUpdateOperation::Clear { silent, graph } => {
write!(f, "CLEAR ")?;
if *silent {
write!(f, "SILENT ")?;
}
write!(f, "{}", graph)
}
GraphUpdateOperation::Create { silent, graph } => {
write!(f, "CREATE ")?;
if *silent {
write!(f, "SILENT ")?;
}
write!(f, "GRAPH {}", graph)
}
GraphUpdateOperation::Drop { silent, graph } => {
write!(f, "DROP ")?;
if *silent {
write!(f, "SILENT ")?;
}
write!(f, "{}", graph)
}
}
}
}
fn write_quads(quads: &[Quad], 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(())
}
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(())
}