diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 8cfa3214..f11bc780 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -1,3 +1,13 @@ +//! This crate is a work in progress of implementation of an RDF and SPARQL software stack in Rust. +//! +//! Its goal is to provide a compliant, safe and fast implementation of W3C specifications. +//! +//! It currently provides: +//! * Basic RDF data structures in the `model` package +//! * Parsers for XML, Turtle and N-Triples syntaxes in the `rio` package +//! * A memory based and a disk based stores in the `store` package +//! * A work in progress SPARQL implementation in the `sparql` package + #![cfg_attr( feature = "cargo-clippy", warn( diff --git a/lib/src/model/dataset.rs b/lib/src/model/dataset.rs index 156895c7..1c7fbcbe 100644 --- a/lib/src/model/dataset.rs +++ b/lib/src/model/dataset.rs @@ -122,7 +122,8 @@ pub trait NamedGraph: Graph { /// assert_eq!(vec![triple.in_graph(None)], results); /// ``` /// -/// The implementation backed by RocksDB could be built using `RocksDbDataset::open` and works just like its in-memory equivalent: +/// The implementation backed by RocksDB if disabled by default and requires the `"rocksdb"` feature to be activated. +/// A `RocksDbDataset` could be built using `RocksDbDataset::open` and works just like its in-memory equivalent: /// ```ignore /// use rudf::store::RocksDbDataset; /// let dataset = RocksDbDataset::open("foo.db"); diff --git a/lib/src/model/literal.rs b/lib/src/model/literal.rs index cb2d5541..15e69be3 100644 --- a/lib/src/model/literal.rs +++ b/lib/src/model/literal.rs @@ -131,7 +131,7 @@ impl Literal { } /// The literal [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form) - pub fn value(&self) -> Cow { + pub fn value(&self) -> Cow { match self.0 { LiteralContent::SimpleLiteral(ref value) | LiteralContent::String(ref value) diff --git a/lib/src/rio/ntriples/mod.rs b/lib/src/rio/ntriples/mod.rs index 2953c104..91cd8d32 100644 --- a/lib/src/rio/ntriples/mod.rs +++ b/lib/src/rio/ntriples/mod.rs @@ -1,4 +1,4 @@ -///Implements https://www.w3.org/TR/n-triples/ +//! Implementation of [N-Triples](https://www.w3.org/TR/n-triples/) RDF syntax mod grammar { #![cfg_attr( @@ -67,7 +67,7 @@ impl Iterator for NTriplesIterator { } } -/// Reads a N-Triples file from a Rust `Read` and returns an iterator on the read `Triple`s +/// Reads a [N-Triples](https://www.w3.org/TR/n-triples/) file from a Rust `Read` and returns an iterator of the read `Triple`s pub fn read_ntriples<'a, R: Read + 'a>(source: R) -> impl Iterator> { NTriplesIterator { buffer: String::default(), diff --git a/lib/src/rio/turtle/mod.rs b/lib/src/rio/turtle/mod.rs index 02c91b1f..1172a923 100644 --- a/lib/src/rio/turtle/mod.rs +++ b/lib/src/rio/turtle/mod.rs @@ -1,4 +1,4 @@ -/// Implements https://www.w3.org/TR/turtle/ +//! Implementation of [Turtle](https://www.w3.org/TR/turtle/) RDF syntax mod grammar { #![cfg_attr( @@ -39,9 +39,10 @@ mod grammar { } } - /// Reads a Turtle file from a Rust `Read` and returns an iterator on the read `Triple`s + /// Reads a [Turtle](https://www.w3.org/TR/turtle/) file from a Rust `Read` and returns an iterator on the read `Triple`s /// - /// Warning: this implementation has not been optimized yet and stores all the found triples in memory + /// Warning: this implementation has not been optimized yet and stores all the found triples in memory. + /// This implementation also requires that blank node ids are valid UTF-8 pub fn read_turtle<'a, R: Read + 'a>( source: R, base_uri: impl Into>, diff --git a/lib/src/rio/xml.rs b/lib/src/rio/xml.rs index 4439dfec..154a8007 100644 --- a/lib/src/rio/xml.rs +++ b/lib/src/rio/xml.rs @@ -1,3 +1,5 @@ +//! Implementation of [RDF XML](https://www.w3.org/TR/rdf-syntax-grammar/) syntax + use model::vocab::rdf; use model::Triple; use model::*; @@ -12,7 +14,9 @@ use std::str::FromStr; use url::Url; use Result; -/// Reads a RDF/XML file from a Rust `Read` and returns an iterator on the read `Triple`s +/// Reads a [RDF XML](https://www.w3.org/TR/rdf-syntax-grammar/) file from a Rust `Read` and returns an iterator on the read `Triple`s +/// +/// Warning: The `rdf:parseType="Literal"` and `rdf:parseType="Collection"` options are not supported yet pub fn read_rdf_xml( source: impl BufRead, base_uri: impl Into>, diff --git a/lib/src/sparql/algebra.rs b/lib/src/sparql/algebra.rs index 36a28392..bd90bbdd 100644 --- a/lib/src/sparql/algebra.rs +++ b/lib/src/sparql/algebra.rs @@ -1,3 +1,5 @@ +//! [SPARQL 1.1 Query Algebra](https://www.w3.org/TR/sparql11-query/#sparqlQuery) AST + use model::*; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/lib/src/sparql/mod.rs b/lib/src/sparql/mod.rs index d773fbaf..b62af9ab 100644 --- a/lib/src/sparql/mod.rs +++ b/lib/src/sparql/mod.rs @@ -1,5 +1,27 @@ -//! SPARQL 1.1 implementation. -//! This is a work in progress!!! +//! [SPARQL](https://www.w3.org/TR/sparql11-overview/) implementation. +//! +//! The support of RDF Dataset and SPARQL 1.1 specific features is not done yet. +//! +//! This module adds query capabilities to the `rudf::model::Dataset` implementations. +//! +//! Usage example: +//! ``` +//! use rudf::model::*; +//! use rudf::store::MemoryDataset; +//! use rudf::sparql::SparqlDataset; +//! use rudf::sparql::PreparedQuery; +//! use rudf::sparql::algebra::QueryResult; +//! use std::str::FromStr; +//! +//! let dataset = MemoryDataset::default(); +//! let ex = NamedNode::from_str("http://example.com").unwrap(); +//! dataset.insert(&Quad::new(ex.clone(), ex.clone(), ex.clone(), None)); +//! let prepared_query = dataset.prepare_query("SELECT ?s WHERE { ?s ?p ?o }".as_bytes()).unwrap(); +//! let results = prepared_query.exec().unwrap(); +//! if let QueryResult::Bindings(results) = results { +//! assert_eq!(results.into_values_iter().next().unwrap().unwrap()[0], Some(ex.into())); +//! } +//! ``` use model::Dataset; use sparql::algebra::Query; @@ -21,12 +43,21 @@ pub mod parser; mod plan; pub mod xml_results; +/// An extension of the `rudf::model::Dataset` trait to allow SPARQL operations on it. +/// +/// It is implemented by all stores provided by Rudf pub trait SparqlDataset: Dataset { type PreparedQuery: PreparedQuery; + + /// Prepares a [SPARQL 1.1](https://www.w3.org/TR/sparql11-query/) query and returns an object that could be used to execute it + /// + /// The implementation is a work in progress, RDF Dataset and SPARQL 1.1 specific features are not implemented yet. fn prepare_query(&self, query: impl Read) -> Result; } +/// A prepared [SPARQL 1.1](https://www.w3.org/TR/sparql11-query/) query pub trait PreparedQuery { + /// Evaluates the query and returns its results fn exec(&self) -> Result; } @@ -34,11 +65,11 @@ impl SparqlDataset for StoreDataset { type PreparedQuery = SimplePreparedQuery; fn prepare_query(&self, query: impl Read) -> Result> { - Ok(match read_sparql_query(query, None)? { + Ok(SimplePreparedQuery(match read_sparql_query(query, None)? { Query::Select { algebra, dataset } => { let store = self.encoded(); let (plan, variables) = PlanBuilder::build(&*store, &algebra)?; - SimplePreparedQuery::Select { + SimplePreparedQueryOptions::Select { plan, variables, evaluator: SimpleEvaluator::new(store), @@ -47,7 +78,7 @@ impl SparqlDataset for StoreDataset { Query::Ask { algebra, dataset } => { let store = self.encoded(); let (plan, _) = PlanBuilder::build(&*store, &algebra)?; - SimplePreparedQuery::Ask { + SimplePreparedQueryOptions::Ask { plan, evaluator: SimpleEvaluator::new(store), } @@ -59,7 +90,7 @@ impl SparqlDataset for StoreDataset { } => { let store = self.encoded(); let (plan, variables) = PlanBuilder::build(&*store, &algebra)?; - SimplePreparedQuery::Construct { + SimplePreparedQueryOptions::Construct { plan, construct: PlanBuilder::build_graph_template(&*store, &construct, variables)?, evaluator: SimpleEvaluator::new(store), @@ -68,16 +99,19 @@ impl SparqlDataset for StoreDataset { Query::Describe { algebra, dataset } => { let store = self.encoded(); let (plan, _) = PlanBuilder::build(&*store, &algebra)?; - SimplePreparedQuery::Describe { + SimplePreparedQueryOptions::Describe { plan, evaluator: SimpleEvaluator::new(store), } } - }) + })) } } -pub enum SimplePreparedQuery { +/// An implementation of `PreparedQuery` for internal use +pub struct SimplePreparedQuery(SimplePreparedQueryOptions); + +enum SimplePreparedQueryOptions { Select { plan: PlanNode, variables: Vec, @@ -100,19 +134,21 @@ pub enum SimplePreparedQuery { impl PreparedQuery for SimplePreparedQuery { fn exec(&self) -> Result { - match self { - SimplePreparedQuery::Select { + match &self.0 { + SimplePreparedQueryOptions::Select { plan, variables, evaluator, } => evaluator.evaluate_select_plan(&plan, &variables), - SimplePreparedQuery::Ask { plan, evaluator } => evaluator.evaluate_ask_plan(&plan), - SimplePreparedQuery::Construct { + SimplePreparedQueryOptions::Ask { plan, evaluator } => { + evaluator.evaluate_ask_plan(&plan) + } + SimplePreparedQueryOptions::Construct { plan, construct, evaluator, } => evaluator.evaluate_construct_plan(&plan, &construct), - SimplePreparedQuery::Describe { plan, evaluator } => { + SimplePreparedQueryOptions::Describe { plan, evaluator } => { evaluator.evaluate_describe_plan(&plan) } } diff --git a/lib/src/store/rocksdb.rs b/lib/src/store/rocksdb.rs index 81d715c9..39dbda28 100644 --- a/lib/src/store/rocksdb.rs +++ b/lib/src/store/rocksdb.rs @@ -20,6 +20,8 @@ use Result; /// `rudf::model::Dataset` trait implementation based on the [RocksDB](https://rocksdb.org/) key-value store /// +/// To use it, the `"rocksdb"` feature need to be activated. +/// /// Usage example: /// ``` /// use rudf::store::RocksDbDataset; diff --git a/lib/src/utils.rs b/lib/src/utils.rs index 75636135..fafa5d92 100644 --- a/lib/src/utils.rs +++ b/lib/src/utils.rs @@ -2,13 +2,7 @@ pub trait Escaper { fn escape(&self) -> String; } -impl<'a> Escaper for &'a str { - fn escape(&self) -> String { - self.chars().flat_map(EscapeRDF::new).collect() - } -} - -impl Escaper for String { +impl Escaper for str { fn escape(&self) -> String { self.chars().flat_map(EscapeRDF::new).collect() }