Struct oxigraph::store::Store

source ·
pub struct Store { /* private fields */ }
Expand description

An on-disk RDF dataset. Allows to query and update it using SPARQL. It is based on the RocksDB key-value store.

This store ensures the “repeatable read” isolation level: the store only exposes changes that have been “committed” (i.e. no partial writes) and the exposed state does not change for the complete duration of a read operation (e.g. a SPARQL query) or a read/write operation (e.g. a SPARQL update).

Usage example:

use oxigraph::store::Store;
use oxigraph::sparql::QueryResults;
use oxigraph::model::*;

let store = Store::open("example.db")?;

// insertion
let ex = NamedNode::new("http://example.com")?;
let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), GraphName::DefaultGraph);
store.insert(&quad)?;

// quad filter
let results: Result<Vec<Quad>,_> = store.quads_for_pattern(None, None, None, None).collect();
assert_eq!(vec![quad], results?);

// SPARQL query
if let QueryResults::Solutions(mut solutions) = store.query("SELECT ?s WHERE { ?s ?p ?o }")? {
    assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into()));
};

Implementations§

source§

impl Store

source

pub fn new() -> Result<Self, StorageError>

Creates a temporary Store that will be deleted after drop.

source

pub fn open(path: impl AsRef<Path>) -> Result<Self, StorageError>

Opens a read-write Store and creates it if it does not exist yet.

Only one read-write Store can exist at the same time. If you want to have extra Store instance opened on a same data use Store::open_secondary or Store::open_read_only.

source

pub fn open_secondary( primary_path: impl AsRef<Path> ) -> Result<Self, StorageError>

Opens a read-only clone of a running read-write Store.

Changes done while this process is running will be replicated after a possible lag.

It should only be used if a primary instance opened with Store::open is running at the same time. primary_path must be the path of the primary instance. This secondary instance will use temporary storage for the secondary instance cache. If you prefer persistent storage use Store::open_persistent_secondary.

If you want to simple read-only Store use Store::open_read_only.

source

pub fn open_persistent_secondary( primary_path: impl AsRef<Path>, secondary_path: impl AsRef<Path> ) -> Result<Self, StorageError>

Opens a read-only clone of a running read-write Store with persistence of the secondary instance cache.

Changes done while this process is running will be replicated after a possible lag.

It should only be used if a primary instance opened with Store::open is running at the same time. primary_path must be the path of the primary instance and secondary_path an other directory for the secondary instance cache.

If you want to simple read-only Store use Store::open_read_only.

source

pub fn open_read_only(path: impl AsRef<Path>) -> Result<Self, StorageError>

Opens a read-only Store from disk.

Opening as read-only while having an other process writing the database is undefined behavior. Store::open_secondary should be used in this case.

source

pub fn query( &self, query: impl TryInto<Query, Error = impl Into<EvaluationError>> ) -> Result<QueryResults, EvaluationError>

Executes a SPARQL 1.1 query.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;
use oxigraph::sparql::QueryResults;

let store = Store::new()?;

// insertions
let ex = NamedNodeRef::new("http://example.com")?;
store.insert(QuadRef::new(ex, ex, ex, GraphNameRef::DefaultGraph))?;

// SPARQL query
if let QueryResults::Solutions(mut solutions) =  store.query("SELECT ?s WHERE { ?s ?p ?o }")? {
    assert_eq!(solutions.next().unwrap()?.get("s"), Some(&ex.into_owned().into()));
}
source

pub fn query_opt( &self, query: impl TryInto<Query, Error = impl Into<EvaluationError>>, options: QueryOptions ) -> Result<QueryResults, EvaluationError>

Executes a SPARQL 1.1 query with some options.

Usage example with a custom function serializing terms to N-Triples:

use oxigraph::store::Store;
use oxigraph::model::*;
use oxigraph::sparql::{QueryOptions, QueryResults};

let store = Store::new()?;
if let QueryResults::Solutions(mut solutions) = store.query_opt(
    "SELECT (<http://www.w3.org/ns/formats/N-Triples>(1) AS ?nt) WHERE {}",
    QueryOptions::default().with_custom_function(
        NamedNode::new("http://www.w3.org/ns/formats/N-Triples")?,
        |args| args.get(0).map(|t| Literal::from(t.to_string()).into())
    )
)? {
    assert_eq!(solutions.next().unwrap()?.get("nt"), Some(&Literal::from("\"1\"^^<http://www.w3.org/2001/XMLSchema#integer>").into()));
}
source

pub fn explain_query_opt( &self, query: impl TryInto<Query, Error = impl Into<EvaluationError>>, options: QueryOptions, with_stats: bool ) -> Result<(Result<QueryResults, EvaluationError>, QueryExplanation), EvaluationError>

Executes a SPARQL 1.1 query with some options and returns a query explanation with some statistics (if enabled with the with_stats parameter).

Beware: if you want to compute statistics you need to exhaust the results iterator before having a look at them.

Usage example serialising the explanation with statistics in JSON:

use oxigraph::store::Store;
use oxigraph::sparql::{QueryOptions, QueryResults};

let store = Store::new()?;
if let (Ok(QueryResults::Solutions(solutions)), explanation) =  store.explain_query_opt("SELECT ?s WHERE { VALUES ?s { 1 2 3 } }", QueryOptions::default(), true)? {
    // We make sure to have read all the solutions
    for _ in solutions {
    }
    let mut buf = Vec::new();
    explanation.write_in_json(&mut buf)?;
}
source

pub fn quads_for_pattern( &self, subject: Option<SubjectRef<'_>>, predicate: Option<NamedNodeRef<'_>>, object: Option<TermRef<'_>>, graph_name: Option<GraphNameRef<'_>> ) -> QuadIter

Retrieves quads with a filter on each quad component

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let store = Store::new()?;

// insertion
let ex = NamedNode::new("http://example.com")?;
let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), GraphName::DefaultGraph);
store.insert(&quad)?;

// quad filter by object
let results = store.quads_for_pattern(None, None, Some((&ex).into()), None).collect::<Result<Vec<_>,_>>()?;
assert_eq!(vec![quad], results);
source

pub fn iter(&self) -> QuadIter

Returns all the quads contained in the store.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let store = Store::new()?;

// insertion
let ex = NamedNode::new("http://example.com")?;
let quad = Quad::new(ex.clone(), ex.clone(), ex.clone(), GraphName::DefaultGraph);
store.insert(&quad)?;

// quad filter by object
let results = store.iter().collect::<Result<Vec<_>,_>>()?;
assert_eq!(vec![quad], results);
source

pub fn contains<'a>( &self, quad: impl Into<QuadRef<'a>> ) -> Result<bool, StorageError>

Checks if this store contains a given quad.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let ex = NamedNodeRef::new("http://example.com")?;
let quad = QuadRef::new(ex, ex, ex, ex);

let store = Store::new()?;
assert!(!store.contains(quad)?);

store.insert(quad)?;
assert!(store.contains(quad)?);
source

pub fn len(&self) -> Result<usize, StorageError>

Returns the number of quads in the store.

Warning: this function executes a full scan.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let ex = NamedNodeRef::new("http://example.com")?;
let store = Store::new()?;
store.insert(QuadRef::new(ex, ex, ex, ex))?;
store.insert(QuadRef::new(ex, ex, ex, GraphNameRef::DefaultGraph))?;    
assert_eq!(2, store.len()?);
source

pub fn is_empty(&self) -> Result<bool, StorageError>

Returns if the store is empty.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let store = Store::new()?;
assert!(store.is_empty()?);

let ex = NamedNodeRef::new("http://example.com")?;
store.insert(QuadRef::new(ex, ex, ex, ex))?;
assert!(!store.is_empty()?);
source

pub fn transaction<'a, 'b: 'a, T, E: Error + 'static + From<StorageError>>( &'b self, f: impl Fn(Transaction<'a>) -> Result<T, E> ) -> Result<T, E>

Executes a transaction.

Transactions ensure the “repeatable read” isolation level: the store only exposes changes that have been “committed” (i.e. no partial writes) and the exposed state does not change for the complete duration of a read operation (e.g. a SPARQL query) or a read/write operation (e.g. a SPARQL update).

Usage example:

use oxigraph::store::{StorageError, Store};
use oxigraph::model::*;

let store = Store::new()?;
let a = NamedNodeRef::new("http://example.com/a")?;
let b = NamedNodeRef::new("http://example.com/b")?;

// Copy all triples about ex:a to triples about ex:b
store.transaction(|mut transaction| {
    for q in transaction.quads_for_pattern(Some(a.into()), None, None, None) {
        let q = q?;
        transaction.insert(QuadRef::new(b, &q.predicate, &q.object, &q.graph_name))?;
    }
    Result::<_, StorageError>::Ok(())
})?;
source

pub fn update( &self, update: impl TryInto<Update, Error = impl Into<EvaluationError>> ) -> Result<(), EvaluationError>

Executes a SPARQL 1.1 update.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let store = Store::new()?;

// insertion
store.update("INSERT DATA { <http://example.com> <http://example.com> <http://example.com> }")?;

// we inspect the store contents
let ex = NamedNodeRef::new("http://example.com")?;
assert!(store.contains(QuadRef::new(ex, ex, ex, GraphNameRef::DefaultGraph))?);
source

pub fn update_opt( &self, update: impl TryInto<Update, Error = impl Into<EvaluationError>>, options: impl Into<UpdateOptions> ) -> Result<(), EvaluationError>

Executes a SPARQL 1.1 update with some options.

use oxigraph::store::Store;
use oxigraph::model::*;
use oxigraph::sparql::QueryOptions;

let store = Store::new()?;
store.update_opt(
    "INSERT { ?s <http://example.com/n-triples-representation> ?n } WHERE { ?s ?p ?o BIND(<http://www.w3.org/ns/formats/N-Triples>(?s) AS ?nt) }",
    QueryOptions::default().with_custom_function(
        NamedNode::new("http://www.w3.org/ns/formats/N-Triples")?,
        |args| args.get(0).map(|t| Literal::from(t.to_string()).into())
    )
)?;
source

pub fn load_graph<'a>( &self, reader: impl BufRead, format: GraphFormat, to_graph_name: impl Into<GraphNameRef<'a>>, base_iri: Option<&str> ) -> Result<(), LoaderError>

Loads a graph file (i.e. triples) into the store.

This function is atomic, quite slow and memory hungry. To get much better performances you might want to use the bulk_loader.

Usage example:

use oxigraph::store::Store;
use oxigraph::io::GraphFormat;
use oxigraph::model::*;

let store = Store::new()?;

// insertion
let file = b"<http://example.com> <http://example.com> <http://example.com> .";
store.load_graph(file.as_ref(), GraphFormat::NTriples, GraphNameRef::DefaultGraph, None)?;

// we inspect the store contents
let ex = NamedNodeRef::new("http://example.com")?;
assert!(store.contains(QuadRef::new(ex, ex, ex, GraphNameRef::DefaultGraph))?);
source

pub fn load_dataset( &self, reader: impl BufRead, format: DatasetFormat, base_iri: Option<&str> ) -> Result<(), LoaderError>

Loads a dataset file (i.e. quads) into the store.

This function is atomic, quite slow and memory hungry. To get much better performances you might want to use the bulk_loader.

Usage example:

use oxigraph::store::Store;
use oxigraph::io::DatasetFormat;
use oxigraph::model::*;

let store = Store::new()?;

// insertion
let file = b"<http://example.com> <http://example.com> <http://example.com> <http://example.com> .";
store.load_dataset(file.as_ref(), DatasetFormat::NQuads, None)?;

// we inspect the store contents
let ex = NamedNodeRef::new("http://example.com")?;
assert!(store.contains(QuadRef::new(ex, ex, ex, ex))?);
source

pub fn insert<'a>( &self, quad: impl Into<QuadRef<'a>> ) -> Result<bool, StorageError>

Adds a quad to this store.

Returns true if the quad was not already in the store.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let ex = NamedNodeRef::new("http://example.com")?;
let quad = QuadRef::new(ex, ex, ex, GraphNameRef::DefaultGraph);

let store = Store::new()?;
assert!(store.insert(quad)?);
assert!(!store.insert(quad)?);

assert!(store.contains(quad)?);
source

pub fn extend( &self, quads: impl IntoIterator<Item = impl Into<Quad>> ) -> Result<(), StorageError>

Adds atomically a set of quads to this store.

Warning: This operation uses a memory heavy transaction internally, use the bulk_loader if you plan to add ten of millions of triples.

source

pub fn remove<'a>( &self, quad: impl Into<QuadRef<'a>> ) -> Result<bool, StorageError>

Removes a quad from this store.

Returns true if the quad was in the store and has been removed.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let ex = NamedNodeRef::new("http://example.com")?;
let quad = QuadRef::new(ex, ex, ex, GraphNameRef::DefaultGraph);

let store = Store::new()?;
store.insert(quad)?;
assert!(store.remove(quad)?);
assert!(!store.remove(quad)?);

assert!(!store.contains(quad)?);
source

pub fn dump_graph<'a>( &self, writer: impl Write, format: GraphFormat, from_graph_name: impl Into<GraphNameRef<'a>> ) -> Result<(), SerializerError>

Dumps a store graph into a file.

Usage example:

use oxigraph::store::Store;
use oxigraph::io::GraphFormat;
use oxigraph::model::GraphNameRef;

let file = "<http://example.com> <http://example.com> <http://example.com> .\n".as_bytes();

let store = Store::new()?;
store.load_graph(file, GraphFormat::NTriples, GraphNameRef::DefaultGraph, None)?;

let mut buffer = Vec::new();
store.dump_graph(&mut buffer, GraphFormat::NTriples, GraphNameRef::DefaultGraph)?;
assert_eq!(file, buffer.as_slice());
source

pub fn dump_dataset( &self, writer: impl Write, format: DatasetFormat ) -> Result<(), SerializerError>

Dumps the store into a file.

use oxigraph::store::Store;
use oxigraph::io::DatasetFormat;

let file = "<http://example.com> <http://example.com> <http://example.com> <http://example.com> .\n".as_bytes();

let store = Store::new()?;
store.load_dataset(file, DatasetFormat::NQuads, None)?;

let mut buffer = Vec::new();
store.dump_dataset(&mut buffer, DatasetFormat::NQuads)?;
assert_eq!(file, buffer.as_slice());
source

pub fn named_graphs(&self) -> GraphNameIter

Returns all the store named graphs.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let ex = NamedNode::new("http://example.com")?;
let store = Store::new()?;
store.insert(QuadRef::new(&ex, &ex, &ex, &ex))?;
store.insert(QuadRef::new(&ex, &ex, &ex, GraphNameRef::DefaultGraph))?;
assert_eq!(vec![NamedOrBlankNode::from(ex)], store.named_graphs().collect::<Result<Vec<_>,_>>()?);
source

pub fn contains_named_graph<'a>( &self, graph_name: impl Into<NamedOrBlankNodeRef<'a>> ) -> Result<bool, StorageError>

Checks if the store contains a given graph

Usage example:

use oxigraph::store::Store;
use oxigraph::model::{NamedNode, QuadRef};

let ex = NamedNode::new("http://example.com")?;
let store = Store::new()?;
store.insert(QuadRef::new(&ex, &ex, &ex, &ex))?;
assert!(store.contains_named_graph(&ex)?);
source

pub fn insert_named_graph<'a>( &self, graph_name: impl Into<NamedOrBlankNodeRef<'a>> ) -> Result<bool, StorageError>

Inserts a graph into this store.

Returns true if the graph was not already in the store.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::NamedNodeRef;

let ex = NamedNodeRef::new("http://example.com")?;
let store = Store::new()?;
store.insert_named_graph(ex)?;

assert_eq!(store.named_graphs().collect::<Result<Vec<_>,_>>()?, vec![ex.into_owned().into()]);
source

pub fn clear_graph<'a>( &self, graph_name: impl Into<GraphNameRef<'a>> ) -> Result<(), StorageError>

Clears a graph from this store.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::{NamedNodeRef, QuadRef};

let ex = NamedNodeRef::new("http://example.com")?;
let quad = QuadRef::new(ex, ex, ex, ex);
let store = Store::new()?;
store.insert(quad)?;
assert_eq!(1, store.len()?);

store.clear_graph(ex)?;
assert!(store.is_empty()?);
assert_eq!(1, store.named_graphs().count());
source

pub fn remove_named_graph<'a>( &self, graph_name: impl Into<NamedOrBlankNodeRef<'a>> ) -> Result<bool, StorageError>

Removes a graph from this store.

Returns true if the graph was in the store and has been removed.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::{NamedNodeRef, QuadRef};

let ex = NamedNodeRef::new("http://example.com")?;
let quad = QuadRef::new(ex, ex, ex, ex);
let store = Store::new()?;
store.insert(quad)?;
assert_eq!(1, store.len()?);

assert!(store.remove_named_graph(ex)?);
assert!(store.is_empty()?);
assert_eq!(0, store.named_graphs().count());
source

pub fn clear(&self) -> Result<(), StorageError>

Clears the store.

Usage example:

use oxigraph::store::Store;
use oxigraph::model::*;

let ex = NamedNodeRef::new("http://example.com")?;
let store = Store::new()?;
store.insert(QuadRef::new(ex, ex, ex, ex))?;
store.insert(QuadRef::new(ex, ex, ex, GraphNameRef::DefaultGraph))?;    
assert_eq!(2, store.len()?);

store.clear()?;
assert!(store.is_empty()?);
source

pub fn flush(&self) -> Result<(), StorageError>

Flushes all buffers and ensures that all writes are saved on disk.

Flushes are automatically done using background threads but might lag a little bit.

source

pub fn optimize(&self) -> Result<(), StorageError>

Optimizes the database for future workload.

Useful to call after a batch upload or another similar operation.

Warning: Can take hours on huge databases.

source

pub fn backup( &self, target_directory: impl AsRef<Path> ) -> Result<(), StorageError>

Creates database backup into the target_directory.

After its creation, the backup is usable using Store::open like a regular Oxigraph database and operates independently from the original database.

Warning: Backups are only possible for on-disk databases created using Store::open. Temporary in-memory databases created using Store::new are not compatible with RocksDB backup system.

Warning: An error is raised if the target_directory already exists.

If the target directory is in the same file system as the current database, the database content will not be fully copied but hard links will be used to point to the original database immutable snapshots. This allows cheap regular backups.

If you want to move your data to another RDF storage system, you should have a look at the Store::dump_dataset function instead.

source

pub fn bulk_loader(&self) -> BulkLoader

Creates a bulk loader allowing to load at lot of data quickly into the store.

Usage example:

use oxigraph::store::Store;
use oxigraph::io::DatasetFormat;
use oxigraph::model::*;

let store = Store::new()?;

// quads file insertion
let file = b"<http://example.com> <http://example.com> <http://example.com> <http://example.com> .";
store.bulk_loader().load_dataset(file.as_ref(), DatasetFormat::NQuads, None)?;

// we inspect the store contents
let ex = NamedNodeRef::new("http://example.com")?;
assert!(store.contains(QuadRef::new(ex, ex, ex, ex))?);

Trait Implementations§

source§

impl Clone for Store

source§

fn clone(&self) -> Store

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Display for Store

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl RefUnwindSafe for Store

§

impl Send for Store

§

impl Sync for Store

§

impl Unpin for Store

§

impl UnwindSafe for Store

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for Twhere T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

§

fn vzip(self) -> V