From 12b930042a289d5ab030b3c325605b667fc48178 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Champin Date: Mon, 18 Dec 2023 18:18:49 +0100 Subject: [PATCH] improve doc and mdbook --- api/src/dataset.rs | 9 +- api/src/graph.rs | 16 +- api/src/prelude.rs | 2 +- api/src/quad.rs | 4 +- api/src/triple.rs | 4 +- book/src/SUMMARY.md | 5 + book/src/ch00_introduction.md | 2 +- book/src/ch02_rdf_terms.md | 39 +++-- book/src/ch03_rdf_statements.md | 92 +++++++++++ book/src/ch04_rdf_graphs.md | 195 +++++++++++++++++++++++ book/src/ch05_term_matchers.md | 3 + book/src/ch06_rdf_datasets.md | 8 + book/src/ch07_parsing_and_serializing.md | 6 + book/src/ch90_changes_since_07.md | 3 +- inmem/src/dataset.rs | 2 +- inmem/src/graph.rs | 2 +- sophia/src/lib.rs | 5 + 17 files changed, 362 insertions(+), 35 deletions(-) create mode 100644 book/src/ch03_rdf_statements.md create mode 100644 book/src/ch04_rdf_graphs.md create mode 100644 book/src/ch05_term_matchers.md create mode 100644 book/src/ch06_rdf_datasets.md create mode 100644 book/src/ch07_parsing_and_serializing.md diff --git a/api/src/dataset.rs b/api/src/dataset.rs index 436265f6..6dd2da62 100644 --- a/api/src/dataset.rs +++ b/api/src/dataset.rs @@ -106,8 +106,7 @@ pub trait Dataset { /// [`SimpleTerm`]: crate::term::SimpleTerm /// [`Any`]: crate::term::matcher::Any /// ``` - /// # use sophia_api::dataset::Dataset; - /// # use sophia_api::quad::Quad; + /// # use sophia_api::prelude::*; /// # use sophia_api::ns::{Namespace, rdf}; /// # /// # fn test(dataset: &G) -> Result<(), Box> @@ -115,8 +114,6 @@ pub trait Dataset { /// # G: Dataset, /// # { /// # - /// use sophia_api::term::matcher::Any; - /// /// let s = Namespace::new("http://schema.org/")?; /// let city = s.get("City")?; /// let country = s.get("Country")?; @@ -357,6 +354,8 @@ pub trait MutableDataset: Dataset { /// a return value of `false` means that the dataset was not changed, /// because the quad was already present in this [`SetDataset`]. /// + /// See also [`MutableDataset::insert_quad`] + /// /// # Usage /// ``` /// # use sophia_api::dataset::{MutableDataset, MdResult}; @@ -393,7 +392,7 @@ pub trait MutableDataset: Dataset { /// NB: if you want to insert a quad `q` while keeping its ownership, /// you can still pass [`q.spog()`](Quad::spog). /// - /// See also [MutableDataset::insert] + /// See also [`MutableDataset::insert`] fn insert_quad(&mut self, quad: T) -> MdResult where T: Quad, diff --git a/api/src/graph.rs b/api/src/graph.rs index e05377b6..94017606 100644 --- a/api/src/graph.rs +++ b/api/src/graph.rs @@ -103,8 +103,7 @@ pub trait Graph { /// [`SimpleTerm`]: crate::term::SimpleTerm /// [`Any`]: crate::term::matcher::Any /// ``` - /// # use sophia_api::graph::Graph; - /// # use sophia_api::triple::Triple; + /// # use sophia_api::prelude::*; /// # use sophia_api::ns::{Namespace, rdf}; /// # /// # fn test(graph: &G) -> Result<(), Box> @@ -112,8 +111,6 @@ pub trait Graph { /// # G: Graph, /// # { /// # - /// use sophia_api::term::matcher::Any; - /// /// let s = Namespace::new("http://schema.org/")?; /// let city = s.get("City")?; /// let country = s.get("Country")?; @@ -128,18 +125,15 @@ pub trait Graph { /// Here is another example using a closure as a [`TermMatcher`]. /// /// ``` - /// # use sophia_api::graph::Graph; - /// # use sophia_api::term::{SimpleTerm, Term}; - /// # use sophia_api::triple::Triple; + /// # use sophia_api::prelude::*; /// # use sophia_api::ns::rdfs; + /// # use sophia_api::term::SimpleTerm; /// # /// # fn test(graph: &G) -> Result<(), Box> /// # where /// # G: Graph, /// # { /// # - /// use sophia_api::term::matcher::Any; - /// /// for t in graph.triples_matching( /// Any, /// [&rdfs::label], @@ -323,6 +317,8 @@ pub trait MutableGraph: Graph { /// a return value of `false` means that the graph was not changed, /// because the triple was already present in this [`SetGraph`]. /// + /// See also [`insert_triple`](MutableGraph::insert_triple) + /// /// # Usage /// ``` /// # use sophia_api::graph::{MutableGraph, MgResult}; @@ -350,7 +346,7 @@ pub trait MutableGraph: Graph { /// NB: if you want to insert a triple `t` while keeping its ownership, /// you can still pass [`t.spo()`](Triple::spo). /// - /// See also [MutableGraph::insert] + /// See also [`MutableGraph::insert`] fn insert_triple(&mut self, triple: T) -> MgResult where T: Triple, diff --git a/api/src/prelude.rs b/api/src/prelude.rs index aaa13a7d..3d4a0522 100644 --- a/api/src/prelude.rs +++ b/api/src/prelude.rs @@ -7,7 +7,7 @@ pub use crate::quad::Quad; pub use crate::serializer::{QuadSerializer, Stringifier, TripleSerializer}; pub use crate::source::{QuadSource, StreamResultExt, TripleSource}; pub use crate::sparql::{SparqlBindings, SparqlDataset}; -pub use crate::term::Term; +pub use crate::term::{matcher::Any, Term, TermKind}; pub use crate::triple::Triple; pub use sophia_iri::{Iri, IriRef}; diff --git a/api/src/quad.rs b/api/src/quad.rs index cb643de4..6b3745c3 100644 --- a/api/src/quad.rs +++ b/api/src/quad.rs @@ -86,7 +86,7 @@ pub trait Quad: Sized { /// Check whether `other` is term-wise equal (using [`Term::eq`]) to `self`. /// - /// See also [`eq_spog`](Quad::eq_spog). + /// See also [`eq_spog`](Quad::eq_spog), [`matched_by`](Quad::matched_by). #[inline] fn eq(&self, other: T) -> bool { self.eq_spog(other.s(), other.p(), other.o(), other.g()) @@ -94,7 +94,7 @@ pub trait Quad: Sized { /// Check whether the quad (`s`, `p`, `o`) is term-wise equal (using [`Term::eq`]) to `self`. /// - /// See also [`eq`](Quad::eq). + /// See also [`eq`](Quad::eq), [`matched_by`](Quad::matched_by). fn eq_spog( &self, s: S, diff --git a/api/src/triple.rs b/api/src/triple.rs index cf601853..c55bd59c 100644 --- a/api/src/triple.rs +++ b/api/src/triple.rs @@ -80,7 +80,7 @@ pub trait Triple: Sized { /// Check whether `other` is term-wise equal (using [`Term::eq`]) to `self`. /// - /// See also [`eq_spo`](Triple::eq_spo). + /// See also [`eq_spo`](Triple::eq_spo), [`matched_by`](Triple::matched_by). #[inline] fn eq(&self, other: T) -> bool { self.eq_spo(other.s(), other.p(), other.o()) @@ -88,7 +88,7 @@ pub trait Triple: Sized { /// Check whether the triple (`s`, `p`, `o`) is term-wise equal (using [`Term::eq`]) to `self`. /// - /// See also [`eq`](Triple::eq). + /// See also [`eq`](Triple::eq), [`matched_by`](Triple::matched_by). fn eq_spo(&self, s: S, p: P, o: O) -> bool { self.s().eq(s) && self.p().eq(p) && self.o().eq(o) } diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index e2eec291..9e8615f3 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -5,4 +5,9 @@ - [Introduction](./ch00_introduction.md) - [Getting Started](./ch01_getting_started.md) - [RDF Terms](./ch02_rdf_terms.md) +- [RDF Statements](./ch03_rdf_statements.md) +- [RDF Graphs](./ch04_rdf_graphs.md) +- [Term Matchers](./ch05_term_matchers.md) +- [RDF Datasets](./ch06_rdf_datasets.md) +- [Parsing and Serializing](./ch07_parsing_and_serializing.md) - [Changes since version 0.7](./ch90_changes_since_07.md) diff --git a/book/src/ch00_introduction.md b/book/src/ch00_introduction.md index 01019a66..f496169b 100644 --- a/book/src/ch00_introduction.md +++ b/book/src/ch00_introduction.md @@ -6,7 +6,7 @@ The [sophia crate](https://crates.io/crates/sophia) aims at providing a comprehe In Sophia, each of these core concepts is modeled by a trait, which can be implemented in multiple ways (see for example the [`Graph`] trait and [some of the types implementing it](https://docs.rs/sophia_api/latest/sophia_api/graph/trait.Graph.html#foreign-impls)). Sophia is therefore not meant to provide the "ultimate" implementation of RDF in Rust, but a generic framework to help various implementations to interoperate with each other (in the spirit of [Apache Commons RDF] for Java or [RDFJS] for Javascript/Typescript). -## Generalized vs. Strict RDF model +## Generalized vs. Strict RDF model {#generialized} The data model supported by this Sophia is in fact a superset of the RDF data model as defined by the W3C. When the distinction matters, diff --git a/book/src/ch02_rdf_terms.md b/book/src/ch02_rdf_terms.md index 84572793..1a05f5ce 100644 --- a/book/src/ch02_rdf_terms.md +++ b/book/src/ch02_rdf_terms.md @@ -1,6 +1,6 @@ # RDF Terms -The [`Term`] trait defines how you interad with [RDF terms] in Sophia. +The [`Term`] trait defines how you interact with [RDF terms] in Sophia. ## Using terms @@ -9,9 +9,9 @@ The kind is described by the [`TermKind`] enum, and available from the [`Term::kind`] method. ```rust,noplayground -# use sophia::api::term::{FromTerm, SimpleTerm, Term, TermKind}; +# use sophia::api::term::{SimpleTerm, Term, TermKind}; # use TermKind::*; -# let some_term = SimpleTerm::from_term("foo"); +# let some_term: SimpleTerm = "foo".into_term(); match some_term.kind() { Iri => { /* ... */ } Literal => { /* ... */ } @@ -24,12 +24,12 @@ Alternatively, when only one kind is of interest, you can use [`Term::is_iri`], If you are interested in the "value" of the term, the trait provides the following methods. All of them return an `Option`, which will be `None` if the term does not have the corresponding kind. -* If the term is an IRI, [`Term::iri`] returns that IRI. +* If the term is an IRI, [`Term::iri`] returns that IRI[^relative_iris]. * If the term is a blank node, [`Term::bnode_id`] returns its [blank node identifier]. * If the term is a literal: + [`Term::lexical_form`] returns its [lexical form] (the "textual value" of the literal), - + [`Term::datatype`] returns its datatype IRI, + + [`Term::datatype`] returns its datatype IRI[^relative_iris], + [`Term::language_tag`] returns its [language tag], if any. * If the term is a [quoted triple]: @@ -39,7 +39,7 @@ If you are interested in the "value" of the term, the trait provides the followi + [`Term::atoms`] iterates over all its atomic (i.e. non quoted-triple) constituents. + (those three methods also have a `to_X` version that destructs the original term instead of borrowing it) -* If the term is a variable, [`Term::variable`] returns its name. +* If the term is a variable[^variables], [`Term::variable`] returns its name. Finally, the method [`Term::eq`] can be used to check whether two values implementing [`Term`] represent the same RDF term. Note that the `==` operator may give a different result than [`Term::eq`] on some types implementing the [`Term`] trait. @@ -49,7 +49,7 @@ Finally, the method [`Term::eq`] can be used to check whether two values impleme Below is a list of useful types implementing the [`Term`] trait: * [`Iri`]`` and [`IriRef`]``, where `T: Borrow`, representing IRIs -* [`BnodeId`]`, where `T: Borrow`, representing blank nodes +* [`BnodeId`]``, where `T: Borrow`, representing blank nodes * `str`, representing literals of type `xsd:string`, * `i32`, `isize` and `usize` representing literals of type `xsd:integer`, * `f64` representing literals of type `xsd:double`, @@ -57,7 +57,9 @@ Below is a list of useful types implementing the [`Term`] trait: [`SimpleTerm`] is a straightforward implementation of [`Term`], that can represent any kind of term, and can either own its own underlying data or borrow it from something else. -Any term can be converted to a [`SimpleTerm`] using the [`Term::as_simple`] method. This method borrows as much as possible from the initial term. Alternatively, to convert any term to a self-sufficient [`SimpleTerm`], you can use [`Term::into_term`] +Any term can be converted to a [`SimpleTerm`] using the [`Term::as_simple`] method. +This method borrows as much as possible from the initial term to avoid spurious memory allocation. +Alternatively, to convert any term to a self-sufficient [`SimpleTerm`], you can use [`Term::into_term`] See also the list of [recipes](#recipes-for-constructing-terms) below. @@ -129,10 +131,27 @@ let b = BnodeId::new("x"); # Ok(()) } ``` +### Converting terms into a different type +```rust,noplayground +# use sophia::api::{ns::xsd, term::{SimpleTerm, Term}}; +fn main() -> Result<(), Box> { +# let some_term = "42" * xsd::integer; +let t1: SimpleTerm = "hello".into_term(); +let t2: i32 = some_term.try_into_term()?; +# Ok(()) } +``` + +---- + +[^relative_iris]: Note that in Sophia's [generalized RDF] model, +IRIs can be *relative* IRI reference. + +[^variables]: Note that this kind only exist in Sophia's [generalized RDF] model. + [`Term`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/trait.Term.html [RDF terms]: https://www.w3.org/TR/rdf-concepts/#dfn-rdf-term -[generalized RDF]: ch00_introduction.html#generalized-vs-strict-rdf-model +[generalized RDF]: ch00_introduction.html#generalized [`TermKind`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/enum.TermKind.html [`Term::kind`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/trait.Term.html#tymethod.kind [`Term::is_iri`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/trait.Term.html#method.is_iri @@ -166,4 +185,4 @@ let b = BnodeId::new("x"); [`Iri`]: https://docs.rs/sophia_iri/0.8.0-alpha.3/sophia_iri/struct.Iri.html [`IriRef`]: https://docs.rs/sophia_iri/0.8.0-alpha.3/sophia_iri/struct.IriRef.html [`BnodeId`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/bnode_id/struct.BnodeId.html -[`SimpleTerm`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/enum.SimpleTerm.html \ No newline at end of file +[`SimpleTerm`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/enum.SimpleTerm.html diff --git a/book/src/ch03_rdf_statements.md b/book/src/ch03_rdf_statements.md new file mode 100644 index 00000000..c1d29eb6 --- /dev/null +++ b/book/src/ch03_rdf_statements.md @@ -0,0 +1,92 @@ +# RDF Statements + +The [`Triple`] and [`Quad`] traits define how you interact with [RDF statements] in Sophia. + +Note that in Sophia's [generalized RDF] model, terms of any kind can occur in any position in a statement. +This contrasts to strict RDF where only IRIs can occur in predicate position, +and where literals can not occur in the subject position. + + +## Using triples + +Triples in RDF are made of a subject, a predicate and an object. +They can be obtained respectively via the methods [`Triple::s`], [`Triple::p`] and [`Triple::o`], +or all at once (as an array of three terms) via the method [`Triple::spo`]. +These methods also have a `to_X` version that destructs the original triple instead of borrowing it. + +```rust,noplayground +# use sophia::api::{ns::rdf, prelude::*}; +// Example: yield all the tems besing used as types in the given triples +fn all_types(triples: IT) -> impl Iterator +where + IT: IntoIterator, + T: Triple, +{ + triples + .into_iter() + .filter(|t| rdf::type_ == t.p()) + .map(|t| t.to_o()) +} +``` + +## Using quads + +Quads are used to represent triples in the context of an optional [named graph]. +Like triples, they have methods [`Quad::s`], [`Quad::p`] and [`Quad::o`], +but also [`Quad::g`] to access the optional graph name, +and [`Quad::spog`] to obtain all four components all at once. +These methods also have a `to_X` version that destructs the original quad instead of borrowing it. + +```rust,noplayground +# use sophia::api::{ns::rdf, prelude::*}; +// Example: yield all the triples in the default graph, from a list of quads +fn all_types(quads: IQ) -> impl Iterator +where + IQ: IntoIterator, + Q: Quad, +{ + quads + .into_iter() + .filter(|q| q.g().is_none()) + .map(|q| { let (spo, _g) = q.to_spog(); spo }) +} +``` + +## Comparing triples or quads + +To check whether two values implementing [`Triple`] (resp. [`Quad`]) +represent the same RDF statements, the method [`Triple::eq`] (resp. [`Quad::eq`]) +must be used.r +It will compare each component of the statements using the [`Term::eq`] method. +Note that the `==` operator may give a different result than [`Triple::eq`] or [`Quad::eq`] +on some types implementing the [`Triple`] or the [`Quad`] trait. + + +## Useful types implementing [`Triple`] + +While the [`Triple`] and [`Quad`] traits can be implemented by multiple types, +in most situations the following types will be used: + +* `[T; 3]` where `T: `[`Term`] implements [`Triple`] +* `([T; 3], Option)` where `T: `[`Term`] implements [`Quad`] + + + +[RDF statements]: https://www.w3.org/TR/rdf-concepts/#dfn-rdf-statement +[generalized RDF]: ch00_introduction.html#generalized +[`Triple`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html +[`Quad`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/quad/trait.Quad.html +[`Triple::s`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html#tymethod.s +[`Triple::p`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html#tymethod.p +[`Triple::o`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html#tymethod.o +[`Triple::spo`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html#method.spo +[named graph]: https://www.w3.org/TR/rdf-concepts/#dfn-named-graph +[`Quad::s`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/quad/trait.Quad.html#tymethod.s +[`Quad::p`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/quad/trait.Quad.html#tymethod.p +[`Quad::o`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/quad/trait.Quad.html#tymethod.o +[`Quad::g`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/quad/trait.Quad.html#tymethod.g +[`Quad::spog`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/quad/trait.Quad.html#method.spog +[`Term::eq`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/trait.Term.html#method.eq +[`Triple::eq`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html#method.eq +[`Quad::eq`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/quad/trait.Quad.html#method.eq +[`Term`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/term/trait.Term.html diff --git a/book/src/ch04_rdf_graphs.md b/book/src/ch04_rdf_graphs.md new file mode 100644 index 00000000..ed32d50f --- /dev/null +++ b/book/src/ch04_rdf_graphs.md @@ -0,0 +1,195 @@ +# RDF Graphs + +The [`Graph`] and [`MutableGraph`] traits define how you interact with [RDF graphs] in Sophia. + +## Using graphs + +RDF graphs are sets of triples, +so the most common thing you need to do with a graph is to iterate over its triples. +This is achieved with the [`Graph::triples`] method: + +```rust,noplayground +# use sophia::api::prelude::*; +# use sophia::inmem::graph::LightGraph; +# fn main() -> Result<(), Box> { +# let g = LightGraph::new(); +for result in g.triples() { + let triple = result?; + // do something with t; +} +# Ok(()) } +``` +Notice that [`Graph::triples`] yields [`Result`]s, +as some implementations of [`Graph`] may fail at any point of the iteration. + +When only a subset of the triples in the graph are of interest, +you will want to use the [`Graph::triples_matching`] method: + +```rust,noplayground +# use sophia::api::{ns::rdf, prelude::*, term::SimpleTerm}; +# use sophia::inmem::graph::LightGraph; + +# let graph = LightGraph::new(); +// Utility closure to recognize IRIs in the schema.org namespace +let in_schema_org = |t: SimpleTerm| -> bool { + t.iri() + .map(|iri| iri.as_str().starts_with(("http://schema.org/"))) + .unwrap_or(false) +}; +// Iter over all instances of schema.org types +graph + .triples_matching(Any, [rdf::type_], in_schema_org) + .map(|res| { let [s, _, o] = res.unwrap().to_spo(); (s, o)}) + .for_each(|(instance, typ)| { + // do something + }) +``` + +[`Graph::triples_matching`] accepts a large variety of parameters, +which will be described in more detail [in the next chapter](./ch05_term_matchers.md). + +[`Graph`] also provide methods to iterate over all unique [subjects](https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.subjects), +[predicate](https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.predicates) +and [object](https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.objects) +in the graph, +as well as over all unique terms of a certain kind +([`Graph::iris`], [`Graph::blank_nodes`], [`Graph::literals`], etc.). + +Finally, it is possible to check whether a graph contains a specific triple with the method [`Graph::contains`]. + + +## Mutating graphs + +Any implementation of [`Graph`] that can be mutated should also implement [`MutableGraph`], +which comes with additional methods for modifying the graph. +Individual triples can be added to the graph (resp. removed from the graph) +with [`MutableGraph::insert`] (resp. [`MutableGraph::remove`]). +Inserting (resp. removing) a triple that is already (resp. not) present in the graph will be essentially a noop. + +```rust,noplayground +# use sophia::{api::{ns::rdf, prelude::*}, iri::*}; +/// Example: increment the rdf:value of a given subject +# fn f(mut g: G) -> Result<(), Box> { +# let s = Iri::new_unchecked("https://example.org/foo"); +let old_value: i32 = g.triples_matching([s], [rdf::value], Any) + .next() + .unwrap()? + .o() + .try_into_term()?; +g.remove(s, rdf::value, old_value)?; +g.insert(s, rdf::value, old_value + 1)?; +# Ok(()) } +``` + +Batch modifications can also be performed on mutable graphs: + +* [`MutableGraph::insert_all`](https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html#method.insert_all) + inserts all the triples from a triple source[^triple_source]; +* [`MutableGraph::remove_all`](https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html#method.remove_all) + removes all the triples from a triple source[^triple_source]; +* [`MutableGraph::remove_matching`](https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html#method.remove_matching) + removes all the triples matching the parameters; +* [`MutableGraph::retain_matching`](https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraphremove.html#method.retain_matching) + removes all the triples *except* those matching the parameters. + +The parameters of `remove_matching` and `retain_matching` are similar to those of [`Graph::triples_matching`] +and are described in more detail in the [next chapter](./ch05_term_matchers.md). + + +## Useful types implementing [`Graph`] + +* slices of [triples] implement [`Graph`]; +* standard collections ([`Vec`], [`HashSet`] and [`BTreeSet`]) of [triples] implement [`Graph`] and [`MutableGraph`]; +* [`sophia::inmem::LightGraph`] provides a [`Graph`] and [`MutableGraph`] implementation with a low memory footprint; +* [`sophia::inmem::FastGraph`] provides a [`Graph`] and [`MutableGraph`] implementation design for fast retrieval of any given triple. + +## Recipies for constructing graphs + +### Constructing and populating an empty graph + +```rust,noplayground +# use sophia::{api::{ns::{Namespace, rdf}, prelude::*}, inmem::graph::FastGraph}; +let mut g = FastGraph::new(); +let ex = Namespace::new_unchecked("https://example.org/ns#"); +let alice = ex.get_unchecked("alice"); +let s = Namespace::new_unchecked("http://schema.org/"); +g.insert( + &alice, + rdf::type_, + s.get_unchecked("Person") +).unwrap(); +g.insert( + &alice, + s.get_unchecked("name"), + "Alice" +).unwrap(); +``` + +### Constructing a graph from a triple source[^triple_source] + +```rust,noplayground +# use sophia::{api::prelude::*, inmem::graph::FastGraph, iri::Iri}; +# fn main() -> Result<(), Box> { +# let big_graph = FastGraph::new(); +// Extract all triples about 'alice' from big_graph in a new graph +let alice = Iri::new_unchecked("https://example.org/ns#alice"); +let graph: FastGraph = big_graph + .triples_matching([alice], Any, Any) + .collect_triples()?; +# Ok(()) } +``` + +NB: Only types implementing [`CollectibleGraph`] +can actually be constructed with the `collected_triples` method as above. +However, most types implementing [`Graph`] should implement [`CollectibleGraph`]. + +### Constructing a graph from a file + +```rust,noplayground +# use sophia::{api::prelude::*, inmem::graph::FastGraph, iri::Iri}; +# use std::{io::BufReader, fs::File}; +use sophia::turtle::parser::turtle; + +# fn main() -> Result<(), Box> { +dbg!(std::env::current_dir()); +let f = BufReader::new(File::open("../sophia_doap.ttl")?); +let graph: FastGraph = turtle::parse_bufread(f) + .collect_triples()?; +# Ok(()) } +``` + +For more about parsing (and serializing), see [the corresponding chapter](./ch07_parsing_and_serializing.md). + +---- + +[^triple_source]: a [`TripleSource`] is a fallible stream of triples, +such as those returned by [`Graph::triples`] or [`Graph::triples_matching`], +or those returned by [parsers]. +In particular, any iterator of `Result` where `T: `[`Triple`] is a [`TripleSource`]. + + +[`Graph`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html +[`MutableGraph`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html +[RDF graphs]: https://www.w3.org/TR/rdf-concepts/#dfn-rdf-graph +[`Graph::triples`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#tymethod.triples +[`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +[`Graph::triples_matching`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.triples_matching +[`Graph::iris`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.iris +[`Graph::literals`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.literals +[`Graph::blank_nodes`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.blank_nodes +[`Graph::contains`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.Graph.html#method.contains +[`MutableGraph::insert`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html#tymethod.insert +[`MutableGraph::remove`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html#tymethod.remove +[`MutableGraph::insert_triple`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html#method.insert_triple +[`MutableGraph::remove_triple`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.MutableGraph.html#method.remove_triple +[`Triple`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html +[triple source]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/source/trait.TripleSource.html +[triples]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/triple/trait.Triple.html +[`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html +[`HashSet`]: https://doc.rust-lang.org/std/collections/struct.HashSet.html +[`BTreeSet`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html +[`sophia::inmem::LightGraph`]: https://docs.rs/sophia_inmem/0.8.0-alpha.3/sophia_inmem/graph/type.LightGraph.html +[`sophia::inmem::FastGraph`]: https://docs.rs/sophia_inmem/0.8.0-alpha.3/sophia_inmem/graph/type.FastGraph.html +[`TripleSource`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/source/trait.TripleSource.html +[parsers]: ./ch07_parsing_and_serializing.md +[`CollectibeGraph`]: https://docs.rs/sophia_api/0.8.0-alpha.3/sophia_api/graph/trait.CollectibleGraph.html diff --git a/book/src/ch05_term_matchers.md b/book/src/ch05_term_matchers.md new file mode 100644 index 00000000..45acf14a --- /dev/null +++ b/book/src/ch05_term_matchers.md @@ -0,0 +1,3 @@ +# Term matchers + +TODO diff --git a/book/src/ch06_rdf_datasets.md b/book/src/ch06_rdf_datasets.md new file mode 100644 index 00000000..04242194 --- /dev/null +++ b/book/src/ch06_rdf_datasets.md @@ -0,0 +1,8 @@ +# RDF Datasets + +TODO explain briefly how the Dataset and MutableDataset traits are similar to Graph and MutableGraph, +replacing Triple's with Quad's and TripleSource's with QuadSource's. + +TODO add a chapter on how to access and manipulate individual named graphs, union graphs. + +TODO add recipes diff --git a/book/src/ch07_parsing_and_serializing.md b/book/src/ch07_parsing_and_serializing.md new file mode 100644 index 00000000..4fe80cf1 --- /dev/null +++ b/book/src/ch07_parsing_and_serializing.md @@ -0,0 +1,6 @@ +# Parsing and Serializing + +TODO describe the different parsers and serializers available in Sophia (mentioning the feature gates) + +TODO explain how to use the options (e.g. to produce pretty Turtle) + diff --git a/book/src/ch90_changes_since_07.md b/book/src/ch90_changes_since_07.md index 53160253..3f9b38a8 100644 --- a/book/src/ch90_changes_since_07.md +++ b/book/src/ch90_changes_since_07.md @@ -79,8 +79,7 @@ for t in g.triples_with_s(mys) { one should now write ```rust,noplayground # extern crate sophia; -# use sophia::api::graph::Graph; -# use sophia::api::term::matcher::Any; +# use sophia::api::prelude::*; # let g: Vec<[i32; 3]> = vec![]; // dummy graph type # let mys = 42; for t in g.triples_matching([mys], Any, Any) { diff --git a/inmem/src/dataset.rs b/inmem/src/dataset.rs index 33116def..ca44abbc 100644 --- a/inmem/src/dataset.rs +++ b/inmem/src/dataset.rs @@ -572,7 +572,7 @@ mod test { /// Flavors of Dataset implementations with a smaller memory-footprint. /// -/// The trade-off is that these implementations can only contain a small number (2^16) of terms. +/// The trade-off is that these implementations can only contain a small number (2^16) of distinct terms. /// pub mod small { use crate::index::SimpleTermIndex; diff --git a/inmem/src/graph.rs b/inmem/src/graph.rs index aa21688f..434d86e0 100644 --- a/inmem/src/graph.rs +++ b/inmem/src/graph.rs @@ -362,7 +362,7 @@ mod test { /// Flavors of Graph implementations with a smaller memory-footprint. /// -/// The trade-off is that these implementations can only contain a small number (2^16) of terms. +/// The trade-off is that these implementations can only contain a small number (2^16) of distinct terms. /// pub mod small { use crate::index::SimpleTermIndex; diff --git a/sophia/src/lib.rs b/sophia/src/lib.rs index 6834d866..9eccb3a8 100644 --- a/sophia/src/lib.rs +++ b/sophia/src/lib.rs @@ -49,5 +49,10 @@ mod booktest { } booktest!(ch01_getting_started); booktest!(ch02_rdf_terms); + booktest!(ch03_rdf_statements); + booktest!(ch04_rdf_graphs); + booktest!(ch05_term_matchers); + booktest!(ch06_rdf_datasets); + booktest!(ch07_parsing_and_serializing); booktest!(ch90_changes_since_07); }