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/term.rs

704 lines
20 KiB

//! Data structures for [RDF 1.1 Concepts](https://www.w3.org/TR/rdf11-concepts/) like IRI, literal or triples.
use std::fmt;
use std::fmt::Write;
/// An RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri).
///
/// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
///
/// ```
/// use spargebra::term::NamedNode;
///
/// assert_eq!(
/// "<http://example.com/foo>",
/// NamedNode { iri: "http://example.com/foo".into() }.to_string()
/// )
/// ```
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub struct NamedNode {
/// The [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) itself.
pub iri: String,
}
impl fmt::Display for NamedNode {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<{}>", self.iri)
}
}
/// An RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node).
///
///
/// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
///
/// ```
/// use spargebra::term::BlankNode;
///
/// assert_eq!(
/// "_:a1",
/// BlankNode { id: "a1".into() }.to_string()
/// )
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct BlankNode {
/// The [blank node identifier](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node-identifier).
pub id: String,
}
impl fmt::Display for BlankNode {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "_:{}", self.id)
}
}
/// An RDF [literal](https://www.w3.org/TR/rdf11-concepts/#dfn-literal).
///
/// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
///
/// The language tags should be lowercased [as suggested by the RDF specification](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string).
///
/// ```
/// use spargebra::term::NamedNode;
/// use spargebra::term::Literal;
///
/// assert_eq!(
/// "\"foo\\nbar\"",
/// Literal::Simple { value: "foo\nbar".into() }.to_string()
/// );
///
/// assert_eq!(
/// "\"1999-01-01\"^^<http://www.w3.org/2001/XMLSchema#date>",
/// Literal::Typed { value: "1999-01-01".into(), datatype: NamedNode { iri: "http://www.w3.org/2001/XMLSchema#date".into() }}.to_string()
/// );
///
/// assert_eq!(
/// "\"foo\"@en",
/// Literal::LanguageTaggedString { value: "foo".into(), language: "en".into() }.to_string()
/// );
/// ```
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum Literal {
/// A [simple literal](https://www.w3.org/TR/rdf11-concepts/#dfn-simple-literal) without datatype or language form.
Simple {
/// The [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form).
value: String,
},
/// A [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string)
LanguageTaggedString {
/// The [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form).
value: String,
/// The [language tag](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tag).
language: String,
},
/// A literal with an explicit datatype
Typed {
/// The [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form).
value: String,
/// The [datatype IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-datatype-iri).
datatype: NamedNode,
},
}
impl fmt::Display for Literal {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Literal::Simple { value } => print_quoted_str(value, f),
Literal::LanguageTaggedString { value, language } => {
print_quoted_str(value, f)?;
write!(f, "@{}", language)
}
Literal::Typed { value, datatype } => {
print_quoted_str(value, f)?;
write!(f, "^^{}", datatype)
}
}
}
}
/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node).
///
/// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum NamedOrBlankNode {
NamedNode(NamedNode),
BlankNode(BlankNode),
}
impl fmt::Display for NamedOrBlankNode {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NamedOrBlankNode::NamedNode(node) => node.fmt(f),
NamedOrBlankNode::BlankNode(node) => node.fmt(f),
}
}
}
impl From<NamedNode> for NamedOrBlankNode {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<BlankNode> for NamedOrBlankNode {
#[inline]
fn from(node: BlankNode) -> Self {
Self::BlankNode(node)
}
}
/// An RDF [term](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term).
///
/// It is the union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node) and [literals](https://www.w3.org/TR/rdf11-concepts/#dfn-literal).
///
/// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum Term {
NamedNode(NamedNode),
BlankNode(BlankNode),
Literal(Literal),
}
impl fmt::Display for Term {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Term::NamedNode(node) => node.fmt(f),
Term::BlankNode(node) => node.fmt(f),
Term::Literal(literal) => literal.fmt(f),
}
}
}
impl From<NamedNode> for Term {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<BlankNode> for Term {
#[inline]
fn from(node: BlankNode) -> Self {
Self::BlankNode(node)
}
}
impl From<Literal> for Term {
#[inline]
fn from(literal: Literal) -> Self {
Self::Literal(literal)
}
}
impl From<NamedOrBlankNode> for Term {
#[inline]
fn from(resource: NamedOrBlankNode) -> Self {
match resource {
NamedOrBlankNode::NamedNode(node) => Self::NamedNode(node),
NamedOrBlankNode::BlankNode(node) => Self::BlankNode(node),
}
}
}
/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [literals](https://www.w3.org/TR/rdf11-concepts/#dfn-literal).
///
/// The default string formatter is returning an N-Triples, Turtle and SPARQL compatible representation.
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GroundTerm {
NamedNode(NamedNode),
Literal(Literal),
}
impl fmt::Display for GroundTerm {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GroundTerm::NamedNode(node) => node.fmt(f),
GroundTerm::Literal(literal) => literal.fmt(f),
}
}
}
impl From<NamedNode> for GroundTerm {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<Literal> for GroundTerm {
#[inline]
fn from(literal: Literal) -> Self {
Self::Literal(literal)
}
}
/// A possible graph name.
///
/// It is the union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and the [default graph name](https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph).
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GraphName {
NamedNode(NamedNode),
DefaultGraph,
}
impl fmt::Display for GraphName {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GraphName::NamedNode(node) => node.fmt(f),
GraphName::DefaultGraph => write!(f, "DEFAULT"),
}
}
}
impl From<NamedNode> for GraphName {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
/// 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).
///
/// The default string formatter is returning a N-Quads representation.
///
/// ```
/// use spargebra::term::NamedNode;
/// use spargebra::term::Quad;
///
/// assert_eq!(
/// "<http://example.com/foo> <http://schema.org/sameAs> <http://example.com/foo> <http://example.com/> .",
/// Quad {
/// 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 Quad {
pub subject: NamedOrBlankNode,
pub predicate: NamedNode,
pub object: Term,
pub graph_name: GraphName,
}
impl fmt::Display for Quad {
#[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
)
}
}
}
/// 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
)
}
}
}
/// A [SPARQL query variable](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
///
/// ```
/// use spargebra::term::Variable;
///
/// assert_eq!(
/// "?foo",
/// Variable { name: "foo".into() }.to_string()
/// );
/// ```
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
pub struct Variable {
pub name: String,
}
impl fmt::Display for Variable {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "?{}", self.name)
}
}
/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum NamedNodePattern {
NamedNode(NamedNode),
Variable(Variable),
}
impl fmt::Display for NamedNodePattern {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NamedNodePattern::NamedNode(node) => node.fmt(f),
NamedNodePattern::Variable(var) => var.fmt(f),
}
}
}
impl From<NamedNode> for NamedNodePattern {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<Variable> for NamedNodePattern {
#[inline]
fn from(var: Variable) -> Self {
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 TermPattern {
NamedNode(NamedNode),
BlankNode(BlankNode),
Literal(Literal),
Variable(Variable),
}
impl fmt::Display for TermPattern {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TermPattern::NamedNode(term) => term.fmt(f),
TermPattern::BlankNode(term) => term.fmt(f),
TermPattern::Literal(term) => term.fmt(f),
TermPattern::Variable(var) => var.fmt(f),
}
}
}
impl From<NamedNode> for TermPattern {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<BlankNode> for TermPattern {
#[inline]
fn from(node: BlankNode) -> Self {
Self::BlankNode(node)
}
}
impl From<Literal> for TermPattern {
#[inline]
fn from(literal: Literal) -> Self {
Self::Literal(literal)
}
}
impl From<Variable> for TermPattern {
fn from(var: Variable) -> Self {
Self::Variable(var)
}
}
impl From<Term> for TermPattern {
#[inline]
fn from(term: Term) -> Self {
match term {
Term::NamedNode(node) => Self::NamedNode(node),
Term::BlankNode(node) => Self::BlankNode(node),
Term::Literal(literal) => Self::Literal(literal),
}
}
}
impl From<NamedNodePattern> for TermPattern {
#[inline]
fn from(element: NamedNodePattern) -> Self {
match element {
NamedNodePattern::NamedNode(node) => Self::NamedNode(node),
NamedNodePattern::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) without blank nodes.
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub enum GroundTermPattern {
NamedNode(NamedNode),
Literal(Literal),
Variable(Variable),
}
impl fmt::Display for GroundTermPattern {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GroundTermPattern::NamedNode(term) => term.fmt(f),
GroundTermPattern::Literal(term) => term.fmt(f),
GroundTermPattern::Variable(var) => var.fmt(f),
}
}
}
impl From<NamedNode> for GroundTermPattern {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<Literal> for GroundTermPattern {
#[inline]
fn from(literal: Literal) -> Self {
Self::Literal(literal)
}
}
impl From<Variable> for GroundTermPattern {
#[inline]
fn from(var: Variable) -> Self {
Self::Variable(var)
}
}
impl From<GroundTerm> for GroundTermPattern {
#[inline]
fn from(term: GroundTerm) -> Self {
match term {
GroundTerm::NamedNode(node) => Self::NamedNode(node),
GroundTerm::Literal(literal) => Self::Literal(literal),
}
}
}
impl From<NamedNodePattern> for GroundTermPattern {
#[inline]
fn from(element: NamedNodePattern) -> Self {
match element {
NamedNodePattern::NamedNode(node) => Self::NamedNode(node),
NamedNodePattern::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 GraphNamePattern {
NamedNode(NamedNode),
DefaultGraph,
Variable(Variable),
}
impl fmt::Display for GraphNamePattern {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
GraphNamePattern::NamedNode(node) => node.fmt(f),
GraphNamePattern::DefaultGraph => f.write_str("DEFAULT"),
GraphNamePattern::Variable(var) => var.fmt(f),
}
}
}
impl From<NamedNode> for GraphNamePattern {
#[inline]
fn from(node: NamedNode) -> Self {
Self::NamedNode(node)
}
}
impl From<Variable> for GraphNamePattern {
#[inline]
fn from(var: Variable) -> Self {
Self::Variable(var)
}
}
impl From<GraphName> for GraphNamePattern {
#[inline]
fn from(graph_name: GraphName) -> Self {
match graph_name {
GraphName::NamedNode(node) => Self::NamedNode(node),
GraphName::DefaultGraph => Self::DefaultGraph,
}
}
}
impl From<NamedNodePattern> for GraphNamePattern {
#[inline]
fn from(graph_name: NamedNodePattern) -> Self {
match graph_name {
NamedNodePattern::NamedNode(node) => Self::NamedNode(node),
NamedNodePattern::Variable(var) => Self::Variable(var),
}
}
}
/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern)
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct TriplePattern {
pub subject: TermPattern,
pub predicate: NamedNodePattern,
pub object: TermPattern,
}
impl TriplePattern {
pub(crate) fn new(
subject: impl Into<TermPattern>,
predicate: impl Into<NamedNodePattern>,
object: impl Into<TermPattern>,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
}
}
}
impl fmt::Display for TriplePattern {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"(triple {} {} {})",
self.subject, self.predicate, self.object
)
}
}
/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct QuadPattern {
pub subject: TermPattern,
pub predicate: NamedNodePattern,
pub object: TermPattern,
pub graph_name: GraphNamePattern,
}
impl QuadPattern {
pub(crate) fn new(
subject: impl Into<TermPattern>,
predicate: impl Into<NamedNodePattern>,
object: impl Into<TermPattern>,
graph_name: impl Into<GraphNamePattern>,
) -> Self {
Self {
subject: subject.into(),
predicate: predicate.into(),
object: object.into(),
graph_name: graph_name.into(),
}
}
}
impl fmt::Display for QuadPattern {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.graph_name == GraphNamePattern::DefaultGraph {
write!(
f,
"(triple {} {} {})",
self.subject, self.predicate, self.object
)
} else {
write!(
f,
"(graph {} (triple {} {} {}))",
self.graph_name, self.subject, self.predicate, self.object
)
}
}
}
/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph without blank nodes
#[derive(Eq, PartialEq, Debug, Clone, Hash)]
pub struct GroundQuadPattern {
pub subject: GroundTermPattern,
pub predicate: NamedNodePattern,
pub object: GroundTermPattern,
pub graph_name: GraphNamePattern,
}
impl fmt::Display for GroundQuadPattern {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.graph_name == GraphNamePattern::DefaultGraph {
write!(
f,
"(triple {} {} {})",
self.subject, self.predicate, self.object
)
} else {
write!(
f,
"(graph {} (triple {} {} {}))",
self.graph_name, self.subject, self.predicate, self.object
)
}
}
}
#[inline]
pub(crate) fn print_quoted_str(string: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('"')?;
for c in string.chars() {
match c {
'\n' => f.write_str("\\n"),
'\r' => f.write_str("\\r"),
'"' => f.write_str("\\\""),
'\\' => f.write_str("\\\\"),
c => f.write_char(c),
}?;
}
f.write_char('"')
}