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.
1406 lines
45 KiB
1406 lines
45 KiB
//! [SPARQL 1.1 Query Algebra](https://www.w3.org/TR/sparql11-query/#sparqlQuery) AST
|
|
|
|
use crate::model::*;
|
|
use crate::sparql::model::*;
|
|
use oxiri::Iri;
|
|
use rio_api::model as rio;
|
|
use std::collections::BTreeSet;
|
|
use std::fmt;
|
|
use std::ops::Add;
|
|
use std::rc::Rc;
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum NamedNodeOrVariable {
|
|
NamedNode(NamedNode),
|
|
Variable(Variable),
|
|
}
|
|
|
|
impl fmt::Display for NamedNodeOrVariable {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
NamedNodeOrVariable::NamedNode(node) => node.fmt(f),
|
|
NamedNodeOrVariable::Variable(var) => var.fmt(f),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<NamedNode> for NamedNodeOrVariable {
|
|
fn from(node: NamedNode) -> Self {
|
|
NamedNodeOrVariable::NamedNode(node)
|
|
}
|
|
}
|
|
|
|
impl From<Variable> for NamedNodeOrVariable {
|
|
fn from(var: Variable) -> Self {
|
|
NamedNodeOrVariable::Variable(var)
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum TermOrVariable {
|
|
Term(Term),
|
|
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::Variable(var) => var.fmt(f),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<NamedNode> for TermOrVariable {
|
|
fn from(node: NamedNode) -> Self {
|
|
TermOrVariable::Term(node.into())
|
|
}
|
|
}
|
|
|
|
impl From<BlankNode> for TermOrVariable {
|
|
fn from(node: BlankNode) -> Self {
|
|
TermOrVariable::Term(node.into())
|
|
}
|
|
}
|
|
|
|
impl From<Literal> for TermOrVariable {
|
|
fn from(literal: Literal) -> Self {
|
|
TermOrVariable::Term(literal.into())
|
|
}
|
|
}
|
|
|
|
impl From<Variable> for TermOrVariable {
|
|
fn from(var: Variable) -> Self {
|
|
TermOrVariable::Variable(var)
|
|
}
|
|
}
|
|
|
|
impl From<Term> for TermOrVariable {
|
|
fn from(term: Term) -> Self {
|
|
TermOrVariable::Term(term)
|
|
}
|
|
}
|
|
|
|
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),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub struct StaticBindings {
|
|
variables: Vec<Variable>,
|
|
values: Vec<Vec<Option<Term>>>,
|
|
}
|
|
|
|
impl StaticBindings {
|
|
pub fn new(variables: Vec<Variable>, values: Vec<Vec<Option<Term>>>) -> Self {
|
|
Self { variables, values }
|
|
}
|
|
|
|
pub fn variables(&self) -> &[Variable] {
|
|
&*self.variables
|
|
}
|
|
|
|
pub fn variables_iter(&self) -> impl Iterator<Item = &Variable> {
|
|
self.variables.iter()
|
|
}
|
|
|
|
pub fn values_iter(&self) -> impl Iterator<Item = &Vec<Option<Term>>> {
|
|
self.values.iter()
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
self.values.is_empty()
|
|
}
|
|
}
|
|
|
|
impl Default for StaticBindings {
|
|
fn default() -> Self {
|
|
Self {
|
|
variables: Vec::default(),
|
|
values: Vec::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub struct TriplePattern {
|
|
pub subject: TermOrVariable,
|
|
pub predicate: NamedNodeOrVariable,
|
|
pub object: TermOrVariable,
|
|
}
|
|
|
|
impl TriplePattern {
|
|
pub fn new(
|
|
subject: impl Into<TermOrVariable>,
|
|
predicate: impl Into<NamedNodeOrVariable>,
|
|
object: impl Into<TermOrVariable>,
|
|
) -> Self {
|
|
Self {
|
|
subject: subject.into(),
|
|
predicate: predicate.into(),
|
|
object: object.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for TriplePattern {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{} {} {}", self.subject, self.predicate, self.object)
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum PropertyPath {
|
|
PredicatePath(NamedNode),
|
|
InversePath(Box<PropertyPath>),
|
|
SequencePath(Box<PropertyPath>, Box<PropertyPath>),
|
|
AlternativePath(Box<PropertyPath>, Box<PropertyPath>),
|
|
ZeroOrMorePath(Box<PropertyPath>),
|
|
OneOrMorePath(Box<PropertyPath>),
|
|
ZeroOrOnePath(Box<PropertyPath>),
|
|
NegatedPropertySet(Vec<NamedNode>),
|
|
}
|
|
|
|
impl fmt::Display for PropertyPath {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
PropertyPath::PredicatePath(p) => write!(f, "link({})", p),
|
|
PropertyPath::InversePath(p) => write!(f, "inv({})", p),
|
|
PropertyPath::AlternativePath(a, b) => write!(f, "alt({}, {})", a, b),
|
|
PropertyPath::SequencePath(a, b) => write!(f, "seq({}, {})", a, b),
|
|
PropertyPath::ZeroOrMorePath(p) => write!(f, "ZeroOrMorePath({})", p),
|
|
PropertyPath::OneOrMorePath(p) => write!(f, "OneOrMorePath({})", p),
|
|
PropertyPath::ZeroOrOnePath(p) => write!(f, "ZeroOrOnePath({})", p),
|
|
PropertyPath::NegatedPropertySet(p) => write!(
|
|
f,
|
|
"NPS({{ {} }})",
|
|
p.iter()
|
|
.map(|v| v.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(" ")
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SparqlPropertyPath<'a>(&'a PropertyPath);
|
|
|
|
impl<'a> fmt::Display for SparqlPropertyPath<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self.0 {
|
|
PropertyPath::PredicatePath(p) => write!(f, "{}", p),
|
|
PropertyPath::InversePath(p) => write!(f, "^{}", SparqlPropertyPath(&*p)),
|
|
PropertyPath::SequencePath(a, b) => write!(
|
|
f,
|
|
"({} / {})",
|
|
SparqlPropertyPath(&*a),
|
|
SparqlPropertyPath(&*b)
|
|
),
|
|
PropertyPath::AlternativePath(a, b) => write!(
|
|
f,
|
|
"({} | {})",
|
|
SparqlPropertyPath(&*a),
|
|
SparqlPropertyPath(&*b)
|
|
),
|
|
PropertyPath::ZeroOrMorePath(p) => write!(f, "{}*", SparqlPropertyPath(&*p)),
|
|
PropertyPath::OneOrMorePath(p) => write!(f, "{}+", SparqlPropertyPath(&*p)),
|
|
PropertyPath::ZeroOrOnePath(p) => write!(f, "{}?", SparqlPropertyPath(&*p)),
|
|
PropertyPath::NegatedPropertySet(p) => write!(
|
|
f,
|
|
"!({})",
|
|
p.iter()
|
|
.map(|v| v.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(" | ")
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<NamedNode> for PropertyPath {
|
|
fn from(p: NamedNode) -> Self {
|
|
PropertyPath::PredicatePath(p)
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub struct PathPattern {
|
|
pub subject: TermOrVariable,
|
|
pub path: PropertyPath,
|
|
pub object: TermOrVariable,
|
|
}
|
|
|
|
impl fmt::Display for PathPattern {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "Path({} {} {})", self.subject, self.path, self.object)
|
|
}
|
|
}
|
|
|
|
impl PathPattern {
|
|
pub fn new(
|
|
subject: impl Into<TermOrVariable>,
|
|
path: impl Into<PropertyPath>,
|
|
object: impl Into<TermOrVariable>,
|
|
) -> Self {
|
|
Self {
|
|
subject: subject.into(),
|
|
path: path.into(),
|
|
object: object.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SparqlPathPattern<'a>(&'a PathPattern);
|
|
|
|
impl<'a> fmt::Display for SparqlPathPattern<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(
|
|
f,
|
|
"{} {} {}",
|
|
self.0.subject,
|
|
SparqlPropertyPath(&self.0.path),
|
|
self.0.object
|
|
)
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum TripleOrPathPattern {
|
|
Triple(TriplePattern),
|
|
Path(PathPattern),
|
|
}
|
|
|
|
impl TripleOrPathPattern {
|
|
pub(crate) fn subject(&self) -> &TermOrVariable {
|
|
match self {
|
|
TripleOrPathPattern::Triple(t) => &t.subject,
|
|
TripleOrPathPattern::Path(t) => &t.subject,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn object(&self) -> &TermOrVariable {
|
|
match self {
|
|
TripleOrPathPattern::Triple(t) => &t.object,
|
|
TripleOrPathPattern::Path(t) => &t.object,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> fmt::Display for TripleOrPathPattern {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
TripleOrPathPattern::Triple(tp) => write!(f, "{}", tp),
|
|
TripleOrPathPattern::Path(ppp) => write!(f, "{}", ppp),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<TriplePattern> for TripleOrPathPattern {
|
|
fn from(tp: TriplePattern) -> Self {
|
|
TripleOrPathPattern::Triple(tp)
|
|
}
|
|
}
|
|
|
|
impl From<PathPattern> for TripleOrPathPattern {
|
|
fn from(ppp: PathPattern) -> Self {
|
|
TripleOrPathPattern::Path(ppp)
|
|
}
|
|
}
|
|
|
|
struct SparqlTripleOrPathPattern<'a>(&'a TripleOrPathPattern);
|
|
|
|
impl<'a> fmt::Display for SparqlTripleOrPathPattern<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self.0 {
|
|
TripleOrPathPattern::Triple(tp) => write!(f, "{}", tp),
|
|
TripleOrPathPattern::Path(ppp) => write!(f, "{}", SparqlPathPattern(ppp)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum Expression {
|
|
NamedNode(NamedNode),
|
|
Literal(Literal),
|
|
Variable(Variable),
|
|
Or(Box<Expression>, Box<Expression>),
|
|
And(Box<Expression>, Box<Expression>),
|
|
Equal(Box<Expression>, Box<Expression>),
|
|
NotEqual(Box<Expression>, Box<Expression>),
|
|
Greater(Box<Expression>, Box<Expression>),
|
|
GreaterOrEq(Box<Expression>, Box<Expression>),
|
|
Lower(Box<Expression>, Box<Expression>),
|
|
LowerOrEq(Box<Expression>, Box<Expression>),
|
|
In(Box<Expression>, Vec<Expression>),
|
|
NotIn(Box<Expression>, Vec<Expression>),
|
|
Add(Box<Expression>, Box<Expression>),
|
|
Sub(Box<Expression>, Box<Expression>),
|
|
Mul(Box<Expression>, Box<Expression>),
|
|
Div(Box<Expression>, Box<Expression>),
|
|
UnaryPlus(Box<Expression>),
|
|
UnaryMinus(Box<Expression>),
|
|
UnaryNot(Box<Expression>),
|
|
FunctionCall(Function, Vec<Expression>),
|
|
Exists(Box<GraphPattern>),
|
|
Bound(Variable),
|
|
}
|
|
|
|
impl fmt::Display for Expression {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Expression::NamedNode(node) => node.fmt(f),
|
|
Expression::Literal(l) => l.fmt(f),
|
|
Expression::Variable(var) => var.fmt(f),
|
|
Expression::Or(a, b) => write!(f, "({} || {})", a, b),
|
|
Expression::And(a, b) => write!(f, "({} && {})", a, b),
|
|
Expression::Equal(a, b) => write!(f, "({} = {})", a, b),
|
|
Expression::NotEqual(a, b) => write!(f, "({} != {})", a, b),
|
|
Expression::Greater(a, b) => write!(f, "({} > {})", a, b),
|
|
Expression::GreaterOrEq(a, b) => write!(f, "({} >= {})", a, b),
|
|
Expression::Lower(a, b) => write!(f, "({} < {})", a, b),
|
|
Expression::LowerOrEq(a, b) => write!(f, "({} <= {})", a, b),
|
|
Expression::In(a, b) => write!(
|
|
f,
|
|
"({} IN ({}))",
|
|
a,
|
|
b.iter()
|
|
.map(|v| v.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
Expression::NotIn(a, b) => write!(
|
|
f,
|
|
"({} NOT IN ({}))",
|
|
a,
|
|
b.iter()
|
|
.map(|v| v.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
Expression::Add(a, b) => write!(f, "{} + {}", a, b),
|
|
Expression::Sub(a, b) => write!(f, "{} - {}", a, b),
|
|
Expression::Mul(a, b) => write!(f, "{} * {}", a, b),
|
|
Expression::Div(a, b) => write!(f, "{} / {}", a, b),
|
|
Expression::UnaryPlus(e) => write!(f, "+{}", e),
|
|
Expression::UnaryMinus(e) => write!(f, "-{}", e),
|
|
Expression::UnaryNot(e) => write!(f, "!{}", e),
|
|
Expression::FunctionCall(function, parameters) => {
|
|
write!(f, "{}(", function)?;
|
|
let mut cont = false;
|
|
for p in parameters {
|
|
if cont {
|
|
write!(f, ", ")?;
|
|
}
|
|
p.fmt(f)?;
|
|
cont = true;
|
|
}
|
|
write!(f, ")")
|
|
}
|
|
Expression::Exists(p) => write!(f, "EXISTS {{ {} }}", p),
|
|
Expression::Bound(v) => write!(f, "BOUND({})", v),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<NamedNode> for Expression {
|
|
fn from(p: NamedNode) -> Self {
|
|
Expression::NamedNode(p)
|
|
}
|
|
}
|
|
|
|
impl From<Literal> for Expression {
|
|
fn from(p: Literal) -> Self {
|
|
Expression::Literal(p)
|
|
}
|
|
}
|
|
|
|
impl From<Variable> for Expression {
|
|
fn from(v: Variable) -> Self {
|
|
Expression::Variable(v)
|
|
}
|
|
}
|
|
|
|
struct SparqlExpression<'a>(&'a Expression);
|
|
|
|
impl<'a> fmt::Display for SparqlExpression<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self.0 {
|
|
Expression::NamedNode(node) => node.fmt(f),
|
|
Expression::Literal(l) => l.fmt(f),
|
|
Expression::Variable(var) => var.fmt(f),
|
|
Expression::Or(a, b) => write!(
|
|
f,
|
|
"({} || {})",
|
|
SparqlExpression(&*a),
|
|
SparqlExpression(&*b)
|
|
),
|
|
Expression::And(a, b) => write!(
|
|
f,
|
|
"({} && {})",
|
|
SparqlExpression(&*a),
|
|
SparqlExpression(&*b)
|
|
),
|
|
Expression::Equal(a, b) => {
|
|
write!(f, "({} = {})", SparqlExpression(&*a), SparqlExpression(&*b))
|
|
}
|
|
Expression::NotEqual(a, b) => write!(
|
|
f,
|
|
"({} != {})",
|
|
SparqlExpression(&*a),
|
|
SparqlExpression(&*b)
|
|
),
|
|
Expression::Greater(a, b) => {
|
|
write!(f, "({} > {})", SparqlExpression(&*a), SparqlExpression(&*b))
|
|
}
|
|
Expression::GreaterOrEq(a, b) => write!(
|
|
f,
|
|
"({} >= {})",
|
|
SparqlExpression(&*a),
|
|
SparqlExpression(&*b)
|
|
),
|
|
Expression::Lower(a, b) => {
|
|
write!(f, "({} < {})", SparqlExpression(&*a), SparqlExpression(&*b))
|
|
}
|
|
Expression::LowerOrEq(a, b) => write!(
|
|
f,
|
|
"({} <= {})",
|
|
SparqlExpression(&*a),
|
|
SparqlExpression(&*b)
|
|
),
|
|
Expression::In(a, b) => write!(
|
|
f,
|
|
"({} IN ({}))",
|
|
a,
|
|
b.iter()
|
|
.map(|v| SparqlExpression(v).to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
Expression::NotIn(a, b) => write!(
|
|
f,
|
|
"({} NOT IN ({}))",
|
|
a,
|
|
b.iter()
|
|
.map(|v| SparqlExpression(v).to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
Expression::Add(a, b) => {
|
|
write!(f, "{} + {}", SparqlExpression(&*a), SparqlExpression(&*b))
|
|
}
|
|
Expression::Sub(a, b) => {
|
|
write!(f, "{} - {}", SparqlExpression(&*a), SparqlExpression(&*b))
|
|
}
|
|
Expression::Mul(a, b) => {
|
|
write!(f, "{} * {}", SparqlExpression(&*a), SparqlExpression(&*b))
|
|
}
|
|
Expression::Div(a, b) => {
|
|
write!(f, "{} / {}", SparqlExpression(&*a), SparqlExpression(&*b))
|
|
}
|
|
Expression::UnaryPlus(e) => write!(f, "+{}", SparqlExpression(&*e)),
|
|
Expression::UnaryMinus(e) => write!(f, "-{}", SparqlExpression(&*e)),
|
|
Expression::UnaryNot(e) => match e.as_ref() {
|
|
Expression::Exists(p) => write!(f, "NOT EXISTS {{ {} }}", SparqlGraphPattern(&*p)),
|
|
e => write!(f, "!{}", e),
|
|
},
|
|
Expression::FunctionCall(function, parameters) => {
|
|
write!(f, "{}(", function)?;
|
|
let mut cont = false;
|
|
for p in parameters {
|
|
if cont {
|
|
write!(f, ", ")?;
|
|
}
|
|
SparqlExpression(&*p).fmt(f)?;
|
|
cont = true;
|
|
}
|
|
write!(f, ")")
|
|
}
|
|
Expression::Bound(v) => write!(f, "BOUND({})", v),
|
|
Expression::Exists(p) => write!(f, "EXISTS {{ {} }}", SparqlGraphPattern(&*p)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum Function {
|
|
Str,
|
|
Lang,
|
|
LangMatches,
|
|
Datatype,
|
|
IRI,
|
|
BNode,
|
|
Rand,
|
|
Abs,
|
|
Ceil,
|
|
Floor,
|
|
Round,
|
|
Concat,
|
|
SubStr,
|
|
StrLen,
|
|
Replace,
|
|
UCase,
|
|
LCase,
|
|
EncodeForURI,
|
|
Contains,
|
|
StrStarts,
|
|
StrEnds,
|
|
StrBefore,
|
|
StrAfter,
|
|
Year,
|
|
Month,
|
|
Day,
|
|
Hours,
|
|
Minutes,
|
|
Seconds,
|
|
Timezone,
|
|
Tz,
|
|
Now,
|
|
UUID,
|
|
StrUUID,
|
|
MD5,
|
|
SHA1,
|
|
SHA256,
|
|
SHA384,
|
|
SHA512,
|
|
Coalesce,
|
|
If,
|
|
StrLang,
|
|
StrDT,
|
|
SameTerm,
|
|
IsIRI,
|
|
IsBlank,
|
|
IsLiteral,
|
|
IsNumeric,
|
|
Regex,
|
|
Custom(NamedNode),
|
|
}
|
|
|
|
impl fmt::Display for Function {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Function::Str => write!(f, "STR"),
|
|
Function::Lang => write!(f, "LANG"),
|
|
Function::LangMatches => write!(f, "LANGMATCHES"),
|
|
Function::Datatype => write!(f, "DATATYPE"),
|
|
Function::IRI => write!(f, "IRI"),
|
|
Function::BNode => write!(f, "BNODE"),
|
|
Function::Rand => write!(f, "RAND"),
|
|
Function::Abs => write!(f, "ABS"),
|
|
Function::Ceil => write!(f, "CEIL"),
|
|
Function::Floor => write!(f, "FLOOR"),
|
|
Function::Round => write!(f, "ROUND"),
|
|
Function::Concat => write!(f, "CONCAT"),
|
|
Function::SubStr => write!(f, "SUBSTR"),
|
|
Function::StrLen => write!(f, "STRLEN"),
|
|
Function::Replace => write!(f, "REPLACE"),
|
|
Function::UCase => write!(f, "UCASE"),
|
|
Function::LCase => write!(f, "LCASE"),
|
|
Function::EncodeForURI => write!(f, "ENCODE_FOR_URI"),
|
|
Function::Contains => write!(f, "CONTAINS"),
|
|
Function::StrStarts => write!(f, "STRSTATS"),
|
|
Function::StrEnds => write!(f, "STRENDS"),
|
|
Function::StrBefore => write!(f, "STRBEFORE"),
|
|
Function::StrAfter => write!(f, "STRAFTER"),
|
|
Function::Year => write!(f, "YEAR"),
|
|
Function::Month => write!(f, "MONTH"),
|
|
Function::Day => write!(f, "DAY"),
|
|
Function::Hours => write!(f, "HOURS"),
|
|
Function::Minutes => write!(f, "MINUTES"),
|
|
Function::Seconds => write!(f, "SECONDS"),
|
|
Function::Timezone => write!(f, "TIMEZONE"),
|
|
Function::Tz => write!(f, "TZ"),
|
|
Function::Now => write!(f, "NOW"),
|
|
Function::UUID => write!(f, "UUID"),
|
|
Function::StrUUID => write!(f, "STRUUID"),
|
|
Function::MD5 => write!(f, "MD5"),
|
|
Function::SHA1 => write!(f, "SHA1"),
|
|
Function::SHA256 => write!(f, "SHA256"),
|
|
Function::SHA384 => write!(f, "SHA384"),
|
|
Function::SHA512 => write!(f, "SHA512"),
|
|
Function::Coalesce => write!(f, "COALESCE"),
|
|
Function::If => write!(f, "IF"),
|
|
Function::StrLang => write!(f, "STRLANG"),
|
|
Function::StrDT => write!(f, "STRDT"),
|
|
Function::SameTerm => write!(f, "sameTerm"),
|
|
Function::IsIRI => write!(f, "isIRI"),
|
|
Function::IsBlank => write!(f, "isBLANK"),
|
|
Function::IsLiteral => write!(f, "isLITERAL"),
|
|
Function::IsNumeric => write!(f, "isNUMERIC"),
|
|
Function::Regex => write!(f, "REGEX"),
|
|
Function::Custom(iri) => iri.fmt(f),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum GraphPattern {
|
|
BGP(Vec<TripleOrPathPattern>),
|
|
Join(Box<GraphPattern>, Box<GraphPattern>),
|
|
LeftJoin(Box<GraphPattern>, Box<GraphPattern>, Option<Expression>),
|
|
Filter(Expression, Box<GraphPattern>),
|
|
Union(Box<GraphPattern>, Box<GraphPattern>),
|
|
Graph(NamedNodeOrVariable, Box<GraphPattern>),
|
|
Extend(Box<GraphPattern>, Variable, Expression),
|
|
Minus(Box<GraphPattern>, Box<GraphPattern>),
|
|
Service(NamedNodeOrVariable, Box<GraphPattern>, bool),
|
|
AggregateJoin(GroupPattern, Vec<(Aggregation, Variable)>),
|
|
Data(StaticBindings),
|
|
OrderBy(Box<GraphPattern>, Vec<OrderComparator>),
|
|
Project(Box<GraphPattern>, Vec<Variable>),
|
|
Distinct(Box<GraphPattern>),
|
|
Reduced(Box<GraphPattern>),
|
|
Slice(Box<GraphPattern>, usize, Option<usize>),
|
|
}
|
|
|
|
impl fmt::Display for GraphPattern {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
GraphPattern::BGP(p) => write!(
|
|
f,
|
|
"BGP({})",
|
|
p.iter()
|
|
.map(|v| v.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(" . ")
|
|
),
|
|
GraphPattern::Join(a, b) => write!(f, "Join({}, {})", a, b),
|
|
GraphPattern::LeftJoin(a, b, e) => {
|
|
if let Some(e) = e {
|
|
write!(f, "LeftJoin({}, {}, {})", a, b, e)
|
|
} else {
|
|
write!(f, "LeftJoin({}, {})", a, b)
|
|
}
|
|
}
|
|
GraphPattern::Filter(e, p) => write!(f, "Filter({}, {})", e, p),
|
|
GraphPattern::Union(a, b) => write!(f, "Union({}, {})", a, b),
|
|
GraphPattern::Graph(g, p) => write!(f, "Graph({}, {})", g, p),
|
|
GraphPattern::Extend(p, v, e) => write!(f, "Extend({}), {}, {})", p, v, e),
|
|
GraphPattern::Minus(a, b) => write!(f, "Minus({}, {})", a, b),
|
|
GraphPattern::Service(n, p, s) => write!(f, "Service({}, {}, {})", n, p, s),
|
|
GraphPattern::AggregateJoin(g, a) => write!(
|
|
f,
|
|
"AggregateJoin({}, {})",
|
|
g,
|
|
a.iter()
|
|
.map(|(a, v)| format!("{}: {}", v, a))
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
GraphPattern::Data(bs) => {
|
|
let variables = bs.variables();
|
|
write!(f, "{{ ")?;
|
|
for values in bs.values_iter() {
|
|
write!(f, "{{")?;
|
|
for i in 0..values.len() {
|
|
if let Some(ref val) = values[i] {
|
|
write!(f, " {} \u{2192} {} ", variables[i], val)?;
|
|
}
|
|
}
|
|
write!(f, "}}")?;
|
|
}
|
|
write!(f, "}}")
|
|
}
|
|
GraphPattern::OrderBy(l, o) => write!(
|
|
f,
|
|
"OrderBy({}, ({}))",
|
|
l,
|
|
o.iter()
|
|
.map(|c| c.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
GraphPattern::Project(l, pv) => write!(
|
|
f,
|
|
"Project({}, ({}))",
|
|
l,
|
|
pv.iter()
|
|
.map(|v| v.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", ")
|
|
),
|
|
GraphPattern::Distinct(l) => write!(f, "Distinct({})", l),
|
|
GraphPattern::Reduced(l) => write!(f, "Reduce({})", l),
|
|
GraphPattern::Slice(l, start, length) => write!(
|
|
f,
|
|
"Slice({}, {}, {})",
|
|
l,
|
|
start,
|
|
length
|
|
.map(|l| l.to_string())
|
|
.unwrap_or_else(|| '?'.to_string())
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for GraphPattern {
|
|
fn default() -> Self {
|
|
GraphPattern::BGP(Vec::default())
|
|
}
|
|
}
|
|
|
|
impl From<TripleOrPathPattern> for GraphPattern {
|
|
fn from(p: TripleOrPathPattern) -> Self {
|
|
GraphPattern::BGP(vec![p])
|
|
}
|
|
}
|
|
|
|
impl GraphPattern {
|
|
pub fn visible_variables(&self) -> BTreeSet<&Variable> {
|
|
let mut vars = BTreeSet::default();
|
|
self.add_visible_variables(&mut vars);
|
|
vars
|
|
}
|
|
|
|
fn add_visible_variables<'a>(&'a self, vars: &mut BTreeSet<&'a Variable>) {
|
|
match self {
|
|
GraphPattern::BGP(p) => {
|
|
for pattern in p {
|
|
match pattern {
|
|
TripleOrPathPattern::Triple(tp) => {
|
|
if let TermOrVariable::Variable(ref s) = tp.subject {
|
|
vars.insert(s);
|
|
}
|
|
if let NamedNodeOrVariable::Variable(ref p) = tp.predicate {
|
|
vars.insert(p);
|
|
}
|
|
if let TermOrVariable::Variable(ref o) = tp.object {
|
|
vars.insert(o);
|
|
}
|
|
}
|
|
TripleOrPathPattern::Path(ppp) => {
|
|
if let TermOrVariable::Variable(ref s) = ppp.subject {
|
|
vars.insert(s);
|
|
}
|
|
if let TermOrVariable::Variable(ref o) = ppp.object {
|
|
vars.insert(o);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
GraphPattern::Join(a, b) => {
|
|
a.add_visible_variables(vars);
|
|
b.add_visible_variables(vars);
|
|
}
|
|
GraphPattern::LeftJoin(a, b, _) => {
|
|
a.add_visible_variables(vars);
|
|
b.add_visible_variables(vars);
|
|
}
|
|
GraphPattern::Filter(_, p) => p.add_visible_variables(vars),
|
|
GraphPattern::Union(a, b) => {
|
|
a.add_visible_variables(vars);
|
|
b.add_visible_variables(vars);
|
|
}
|
|
GraphPattern::Graph(g, p) => {
|
|
if let NamedNodeOrVariable::Variable(ref g) = g {
|
|
vars.insert(g);
|
|
}
|
|
p.add_visible_variables(vars);
|
|
}
|
|
GraphPattern::Extend(p, v, _) => {
|
|
vars.insert(v);
|
|
p.add_visible_variables(vars);
|
|
}
|
|
GraphPattern::Minus(a, _) => a.add_visible_variables(vars),
|
|
GraphPattern::Service(_, p, _) => p.add_visible_variables(vars),
|
|
GraphPattern::AggregateJoin(_, a) => {
|
|
for (_, v) in a {
|
|
vars.insert(v);
|
|
}
|
|
}
|
|
GraphPattern::Data(b) => vars.extend(b.variables_iter()),
|
|
GraphPattern::OrderBy(l, _) => l.add_visible_variables(vars),
|
|
GraphPattern::Project(_, pv) => vars.extend(pv.iter()),
|
|
GraphPattern::Distinct(l) => l.add_visible_variables(vars),
|
|
GraphPattern::Reduced(l) => l.add_visible_variables(vars),
|
|
GraphPattern::Slice(l, _, _) => l.add_visible_variables(vars),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SparqlGraphPattern<'a>(&'a GraphPattern);
|
|
|
|
impl<'a> fmt::Display for SparqlGraphPattern<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self.0 {
|
|
GraphPattern::BGP(p) => {
|
|
for pattern in p {
|
|
write!(f, "{} .", SparqlTripleOrPathPattern(pattern))?
|
|
}
|
|
Ok(())
|
|
}
|
|
GraphPattern::Join(a, b) => write!(
|
|
f,
|
|
"{{ {} }} {{ {} }}",
|
|
SparqlGraphPattern(&*a),
|
|
SparqlGraphPattern(&*b)
|
|
),
|
|
GraphPattern::LeftJoin(a, b, e) => {
|
|
if let Some(e) = e {
|
|
write!(
|
|
f,
|
|
"{} OPTIONAL {{ {} FILTER({}) }}",
|
|
SparqlGraphPattern(&*a),
|
|
SparqlGraphPattern(&*b),
|
|
SparqlExpression(e)
|
|
)
|
|
} else {
|
|
write!(
|
|
f,
|
|
"{} OPTIONAL {{ {} }}",
|
|
SparqlGraphPattern(&*a),
|
|
SparqlGraphPattern(&*b)
|
|
)
|
|
}
|
|
}
|
|
GraphPattern::Filter(e, p) => write!(
|
|
f,
|
|
"{} FILTER({})",
|
|
SparqlGraphPattern(&*p),
|
|
SparqlExpression(e)
|
|
),
|
|
GraphPattern::Union(a, b) => write!(
|
|
f,
|
|
"{{ {} }} UNION {{ {} }}",
|
|
SparqlGraphPattern(&*a),
|
|
SparqlGraphPattern(&*b),
|
|
),
|
|
GraphPattern::Graph(g, p) => {
|
|
write!(f, "GRAPH {} {{ {} }}", g, SparqlGraphPattern(&*p),)
|
|
}
|
|
GraphPattern::Extend(p, v, e) => write!(
|
|
f,
|
|
"{} BIND({} AS {})",
|
|
SparqlGraphPattern(&*p),
|
|
SparqlExpression(e),
|
|
v
|
|
),
|
|
GraphPattern::Minus(a, b) => write!(
|
|
f,
|
|
"{} MINUS {{ {} }}",
|
|
SparqlGraphPattern(&*a),
|
|
SparqlGraphPattern(&*b)
|
|
),
|
|
GraphPattern::Service(n, p, s) => {
|
|
if *s {
|
|
write!(f, "SERVICE SILENT {} {{ {} }}", n, SparqlGraphPattern(&*p))
|
|
} else {
|
|
write!(f, "SERVICE {} {{ {} }}", n, SparqlGraphPattern(&*p))
|
|
}
|
|
}
|
|
GraphPattern::Data(bs) => {
|
|
if bs.is_empty() {
|
|
Ok(())
|
|
} else {
|
|
write!(f, "VALUES ( ")?;
|
|
for var in bs.variables() {
|
|
write!(f, "{} ", var)?;
|
|
}
|
|
write!(f, ") {{ ")?;
|
|
for values in bs.values_iter() {
|
|
write!(f, "( ")?;
|
|
for val in values {
|
|
match val {
|
|
Some(val) => write!(f, "{} ", val),
|
|
None => write!(f, "UNDEF "),
|
|
}?;
|
|
}
|
|
write!(f, ") ")?;
|
|
}
|
|
write!(f, " }}")
|
|
}
|
|
}
|
|
GraphPattern::AggregateJoin(GroupPattern(group, p), agg) => write!(
|
|
f,
|
|
"{{ SELECT {} WHERE {{ {} }} GROUP BY {} }}",
|
|
agg.iter()
|
|
.map(|(a, v)| format!("({} AS {})", SparqlAggregation(a), v))
|
|
.chain(group.iter().map(|e| e.to_string()))
|
|
.collect::<Vec<String>>()
|
|
.join(" "),
|
|
SparqlGraphPattern(&*p),
|
|
group
|
|
.iter()
|
|
.map(|e| format!("({})", e.to_string()))
|
|
.collect::<Vec<String>>()
|
|
.join(" ")
|
|
),
|
|
p => write!(
|
|
f,
|
|
"{{ {} }}",
|
|
SparqlGraphRootPattern {
|
|
algebra: p,
|
|
dataset: &EMPTY_DATASET
|
|
}
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SparqlGraphRootPattern<'a> {
|
|
algebra: &'a GraphPattern,
|
|
dataset: &'a DatasetSpec,
|
|
}
|
|
|
|
impl<'a> fmt::Display for SparqlGraphRootPattern<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let mut distinct = false;
|
|
let mut reduced = false;
|
|
let mut order = None;
|
|
let mut start = 0;
|
|
let mut length = None;
|
|
let mut project: &[Variable] = &[];
|
|
|
|
let mut child = self.algebra;
|
|
loop {
|
|
match child {
|
|
GraphPattern::OrderBy(l, o) => {
|
|
order = Some(o);
|
|
child = &*l;
|
|
}
|
|
GraphPattern::Project(l, pv) if project.is_empty() => {
|
|
project = pv;
|
|
child = &*l;
|
|
}
|
|
GraphPattern::Distinct(l) => {
|
|
distinct = true;
|
|
child = &*l;
|
|
}
|
|
GraphPattern::Reduced(l) => {
|
|
reduced = true;
|
|
child = &*l;
|
|
}
|
|
GraphPattern::Slice(l, s, len) => {
|
|
start = *s;
|
|
length = *len;
|
|
child = l;
|
|
}
|
|
p => {
|
|
write!(f, "SELECT ")?;
|
|
if distinct {
|
|
write!(f, "DISTINCT ")?;
|
|
}
|
|
if reduced {
|
|
write!(f, "REDUCED ")?;
|
|
}
|
|
write!(
|
|
f,
|
|
"{} {} WHERE {{ {} }}",
|
|
build_sparql_select_arguments(project),
|
|
self.dataset,
|
|
SparqlGraphPattern(p)
|
|
)?;
|
|
if let Some(order) = order {
|
|
write!(
|
|
f,
|
|
" ORDER BY {}",
|
|
order
|
|
.iter()
|
|
.map(|c| SparqlOrderComparator(c).to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(" ")
|
|
)?;
|
|
}
|
|
if start > 0 {
|
|
write!(f, " OFFSET {}", start)?;
|
|
}
|
|
if let Some(length) = length {
|
|
write!(f, " LIMIT {}", length)?;
|
|
}
|
|
return Ok(());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub struct GroupPattern(pub Vec<Variable>, pub Box<GraphPattern>);
|
|
|
|
impl fmt::Display for GroupPattern {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(
|
|
f,
|
|
"Group(({}), {})",
|
|
self.0
|
|
.iter()
|
|
.map(|c| c.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(", "),
|
|
self.1
|
|
)
|
|
}
|
|
}
|
|
|
|
fn build_sparql_select_arguments(args: &[Variable]) -> String {
|
|
if args.is_empty() {
|
|
"*".to_owned()
|
|
} else {
|
|
args.iter()
|
|
.map(|v| v.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(" ")
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum Aggregation {
|
|
Count(Option<Box<Expression>>, bool),
|
|
Sum(Box<Expression>, bool),
|
|
Min(Box<Expression>, bool),
|
|
Max(Box<Expression>, bool),
|
|
Avg(Box<Expression>, bool),
|
|
Sample(Box<Expression>, bool),
|
|
GroupConcat(Box<Expression>, bool, Option<String>),
|
|
}
|
|
|
|
impl fmt::Display for Aggregation {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Aggregation::Count(e, distinct) => {
|
|
if *distinct {
|
|
if let Some(ex) = e {
|
|
write!(f, "COUNT(DISTINCT {})", ex)
|
|
} else {
|
|
write!(f, "COUNT(DISTINCT *)")
|
|
}
|
|
} else if let Some(ex) = e {
|
|
write!(f, "COUNT({})", ex)
|
|
} else {
|
|
write!(f, "COUNT(*)")
|
|
}
|
|
}
|
|
Aggregation::Sum(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "Aggregation(Distinct({}), Sum, {{}})", e)
|
|
} else {
|
|
write!(f, "Aggregation({}, Sum, {{}})", e)
|
|
}
|
|
}
|
|
Aggregation::Min(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "Aggregation(Distinct({}), Min, {{}})", e)
|
|
} else {
|
|
write!(f, "Aggregation({}, Min, {{}})", e)
|
|
}
|
|
}
|
|
Aggregation::Max(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "Aggregation(Distinct({}), Max, {{}})", e)
|
|
} else {
|
|
write!(f, "Aggregation({}, Max, {{}})", e)
|
|
}
|
|
}
|
|
Aggregation::Avg(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "Aggregation(Distinct({}), Avg, {{}})", e)
|
|
} else {
|
|
write!(f, "Aggregation({}, Avg, {{}})", e)
|
|
}
|
|
}
|
|
Aggregation::Sample(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "Aggregation(Distinct({}), Sum, {{}})", e)
|
|
} else {
|
|
write!(f, "Aggregation({}, Sample, {{}})", e)
|
|
}
|
|
}
|
|
Aggregation::GroupConcat(e, distinct, sep) => {
|
|
if *distinct {
|
|
if let Some(s) = sep {
|
|
write!(
|
|
f,
|
|
"Aggregation(Distinct({}), GroupConcat, {{\"separator\" \u{2192} {}}})",
|
|
e,
|
|
fmt_str(s)
|
|
)
|
|
} else {
|
|
write!(f, "Aggregation(Distinct({}), GroupConcat, {{}})", e)
|
|
}
|
|
} else if let Some(s) = sep {
|
|
write!(
|
|
f,
|
|
"Aggregation({}, GroupConcat, {{\"separator\" \u{2192} {}}})",
|
|
e,
|
|
fmt_str(s)
|
|
)
|
|
} else {
|
|
write!(f, "Aggregation(Distinct({}), GroupConcat, {{}})", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SparqlAggregation<'a>(&'a Aggregation);
|
|
|
|
impl<'a> fmt::Display for SparqlAggregation<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self.0 {
|
|
Aggregation::Count(e, distinct) => {
|
|
if *distinct {
|
|
if let Some(e) = e {
|
|
write!(f, "COUNT(DISTINCT {})", SparqlExpression(e))
|
|
} else {
|
|
write!(f, "COUNT(DISTINCT *)")
|
|
}
|
|
} else if let Some(e) = e {
|
|
write!(f, "COUNT({})", SparqlExpression(e))
|
|
} else {
|
|
write!(f, "COUNT(*)")
|
|
}
|
|
}
|
|
Aggregation::Sum(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "SUM(DISTINCT {})", SparqlExpression(e))
|
|
} else {
|
|
write!(f, "SUM({})", SparqlExpression(e))
|
|
}
|
|
}
|
|
Aggregation::Min(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "MIN(DISTINCT {})", SparqlExpression(e))
|
|
} else {
|
|
write!(f, "MIN({})", SparqlExpression(e))
|
|
}
|
|
}
|
|
Aggregation::Max(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "MAX(DISTINCT {})", SparqlExpression(e))
|
|
} else {
|
|
write!(f, "MAX({})", SparqlExpression(e))
|
|
}
|
|
}
|
|
Aggregation::Avg(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "AVG(DISTINCT {})", SparqlExpression(e))
|
|
} else {
|
|
write!(f, "AVG({})", SparqlExpression(e))
|
|
}
|
|
}
|
|
Aggregation::Sample(e, distinct) => {
|
|
if *distinct {
|
|
write!(f, "SAMPLE(DISTINCT {})", SparqlExpression(e))
|
|
} else {
|
|
write!(f, "SAMPLE({})", SparqlExpression(e))
|
|
}
|
|
}
|
|
Aggregation::GroupConcat(e, distinct, sep) => {
|
|
if *distinct {
|
|
if let Some(sep) = sep {
|
|
write!(
|
|
f,
|
|
"GROUP_CONCAT(DISTINCT {}; SEPARATOR = {})",
|
|
SparqlExpression(e),
|
|
fmt_str(sep)
|
|
)
|
|
} else {
|
|
write!(f, "GROUP_CONCAT(DISTINCT {})", SparqlExpression(e))
|
|
}
|
|
} else if let Some(sep) = sep {
|
|
write!(
|
|
f,
|
|
"GROUP_CONCAT({}; SEPARATOR = {})",
|
|
SparqlExpression(e),
|
|
fmt_str(sep)
|
|
)
|
|
} else {
|
|
write!(f, "GROUP_CONCAT({})", SparqlExpression(e))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn fmt_str(value: &str) -> rio::Literal<'_> {
|
|
rio::Literal::Simple { value }
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum OrderComparator {
|
|
Asc(Expression),
|
|
Desc(Expression),
|
|
}
|
|
|
|
impl fmt::Display for OrderComparator {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
OrderComparator::Asc(e) => write!(f, "ASC({})", e),
|
|
OrderComparator::Desc(e) => write!(f, "DESC({})", e),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Expression> for OrderComparator {
|
|
fn from(e: Expression) -> Self {
|
|
OrderComparator::Asc(e)
|
|
}
|
|
}
|
|
|
|
struct SparqlOrderComparator<'a>(&'a OrderComparator);
|
|
|
|
impl<'a> fmt::Display for SparqlOrderComparator<'a> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self.0 {
|
|
OrderComparator::Asc(e) => write!(f, "ASC({})", SparqlExpression(e)),
|
|
OrderComparator::Desc(e) => write!(f, "DESC({})", SparqlExpression(e)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash, Default)]
|
|
pub struct DatasetSpec {
|
|
pub default: Vec<NamedNode>,
|
|
pub named: Vec<NamedNode>,
|
|
}
|
|
|
|
impl DatasetSpec {
|
|
pub fn new_with_default(graph: NamedNode) -> Self {
|
|
Self {
|
|
default: vec![graph],
|
|
named: Vec::default(),
|
|
}
|
|
}
|
|
|
|
pub fn new_with_named(graph: NamedNode) -> Self {
|
|
Self {
|
|
default: Vec::default(),
|
|
named: vec![graph],
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Add for DatasetSpec {
|
|
type Output = Self;
|
|
|
|
fn add(mut self, rhs: Self) -> Self {
|
|
self.default.extend_from_slice(&rhs.default);
|
|
self.named.extend_from_slice(&rhs.named);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for DatasetSpec {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
for g in &self.default {
|
|
write!(f, "FROM {} ", g)?;
|
|
}
|
|
for g in &self.named {
|
|
write!(f, "FROM NAMED {} ", g)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
const EMPTY_DATASET: DatasetSpec = DatasetSpec {
|
|
default: Vec::new(),
|
|
named: Vec::new(),
|
|
};
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
|
|
pub enum QueryVariants {
|
|
Select {
|
|
dataset: Rc<DatasetSpec>,
|
|
algebra: Rc<GraphPattern>,
|
|
base_iri: Option<Rc<Iri<String>>>,
|
|
},
|
|
Construct {
|
|
construct: Rc<Vec<TriplePattern>>,
|
|
dataset: Rc<DatasetSpec>,
|
|
algebra: Rc<GraphPattern>,
|
|
base_iri: Option<Rc<Iri<String>>>,
|
|
},
|
|
Describe {
|
|
dataset: Rc<DatasetSpec>,
|
|
algebra: Rc<GraphPattern>,
|
|
base_iri: Option<Rc<Iri<String>>>,
|
|
},
|
|
Ask {
|
|
dataset: Rc<DatasetSpec>,
|
|
algebra: Rc<GraphPattern>,
|
|
base_iri: Option<Rc<Iri<String>>>,
|
|
},
|
|
}
|
|
|
|
impl fmt::Display for QueryVariants {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
QueryVariants::Select {
|
|
dataset,
|
|
algebra,
|
|
base_iri,
|
|
} => {
|
|
if let Some(base_iri) = base_iri {
|
|
writeln!(f, "BASE <{}>", base_iri)?;
|
|
}
|
|
write!(f, "{}", SparqlGraphRootPattern { algebra, dataset })
|
|
}
|
|
QueryVariants::Construct {
|
|
construct,
|
|
dataset,
|
|
algebra,
|
|
base_iri,
|
|
} => {
|
|
if let Some(base_iri) = base_iri {
|
|
writeln!(f, "BASE <{}>", base_iri)?;
|
|
}
|
|
write!(
|
|
f,
|
|
"CONSTRUCT {{ {} }} {} WHERE {{ {} }}",
|
|
construct
|
|
.iter()
|
|
.map(|t| t.to_string())
|
|
.collect::<Vec<String>>()
|
|
.join(" . "),
|
|
dataset,
|
|
SparqlGraphRootPattern {
|
|
algebra,
|
|
dataset: &EMPTY_DATASET
|
|
}
|
|
)
|
|
}
|
|
QueryVariants::Describe {
|
|
dataset,
|
|
algebra,
|
|
base_iri,
|
|
} => {
|
|
if let Some(base_iri) = base_iri {
|
|
writeln!(f, "BASE <{}>", base_iri.as_str())?;
|
|
}
|
|
write!(
|
|
f,
|
|
"DESCRIBE * {} WHERE {{ {} }}",
|
|
dataset,
|
|
SparqlGraphRootPattern {
|
|
algebra,
|
|
dataset: &EMPTY_DATASET
|
|
}
|
|
)
|
|
}
|
|
QueryVariants::Ask {
|
|
dataset,
|
|
algebra,
|
|
base_iri,
|
|
} => {
|
|
if let Some(base_iri) = base_iri {
|
|
writeln!(f, "BASE <{}>", base_iri)?;
|
|
}
|
|
write!(
|
|
f,
|
|
"ASK {} WHERE {{ {} }}",
|
|
dataset,
|
|
SparqlGraphRootPattern {
|
|
algebra,
|
|
dataset: &EMPTY_DATASET
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|