rudof_lib 0.3.25

RDF and Knowledge Graphs processing tool
use crate::{
    Result, Rudof,
    api::data::implementations::{
        add_triple, dereference, list_endpoints, load_data, load_service_description, node_neighborhood, remove_triple,
        reset_data, reset_service_description, serialize_data, serialize_service_description, show_node_info, triples,
    },
    formats::{
        DataFormat, DataReaderMode, InputSpec, IriNormalizationMode, NodeInspectionMode, ResultDataFormat,
        ResultServiceFormat,
    },
    types::{NodeNeighborhood, Triples},
};
use rudof_rdf::rdf_impl::EndpointStrategy;
use rudof_viz::VizEngine;
use std::io;

/// Operations for managing RDF data.
pub trait DataOperations {
    /// Loads RDF data from one or more input sources.
    ///
    /// # Arguments
    ///
    /// * `data` - Optional array of input specifications defining data sources (uses None by default)
    /// * `data_format` - The RDF format of the input data (uses default if None)
    /// * `base` - Optional base IRI for resolving relative IRIs (uses default if None)
    /// * `endpoint` - Optional SPARQL endpoint URL to load data from. If stablished it overrides data (uses None by default)
    /// * `reader_mode` - The parsing mode (uses default if None)
    /// * `endpoint_strategy` - How `endpoint` (if given) answers lookups: SPARQL queries
    ///   or HTTP dereferencing. Ignored when `endpoint` is `None`.
    ///
    /// # Errors
    ///
    /// Returns an error if the data cannot be parsed or loaded.
    #[allow(clippy::too_many_arguments)]
    fn load_data(
        &mut self,
        data: Option<&[InputSpec]>,
        data_format: Option<&DataFormat>,
        base: Option<&str>,
        endpoint: Option<&str>,
        reader_mode: Option<&DataReaderMode>,
        merge: Option<bool>,
        prefixes: Option<&[InputSpec]>,
        endpoint_strategy: EndpointStrategy,
    ) -> Result<()>;

    /// Serializes the current RDF data to a writer.
    ///
    /// # Arguments
    ///
    /// * `result_data_format` - Optional output format (uses default if None)
    /// * `viz_engine` - Optional visualization engine to use for image formats (SVG/PNG); uses
    ///   `VizEngine::PlantUml` if None. Ignored for non-image formats.
    /// * `writer` - The destination to write the serialized data to
    ///
    /// # Errors
    ///
    /// Returns an error if serialization fails.
    fn serialize_data<W: io::Write>(
        &mut self,
        result_data_format: Option<&ResultDataFormat>,
        viz_engine: Option<&VizEngine>,
        writer: &mut W,
    ) -> Result<()>;

    /// Resets the current data to an empty state.
    fn reset_data(&mut self);

    /// Loads a SPARQL service description from an input specification.
    ///
    /// # Arguments
    ///
    /// * `service` - Input specification defining the service description source
    /// * `data_format` - Optional format (uses default if None)
    /// * `reader_mode` - Optional parsing mode (uses default if None)
    /// * `base` - Optional base IRI for resolving relative IRIs in the service description (uses default if None)
    ///
    /// # Errors
    ///
    /// Returns an error if the service description cannot be parsed or loaded.
    fn load_service_description(
        &mut self,
        service: &InputSpec,
        data_format: Option<&DataFormat>,
        reader_mode: Option<&DataReaderMode>,
        base: Option<&str>,
    ) -> Result<()>;

    /// Serializes the current service description to a writer.
    ///
    /// # Arguments
    ///
    /// * `result_service_format` - Optional output format for the service description (uses default if None)
    /// * `writer` - The destination to write the serialized service description to
    ///
    /// # Errors
    ///
    /// Returns an error if no service description is loaded or serialization fails.
    fn serialize_service_description<W: io::Write>(
        &self,
        result_service_format: Option<&ResultServiceFormat>,
        writer: &mut W,
    ) -> Result<()>;

    /// Resets the current service description.
    fn reset_service_description(&mut self);

    /// Shows detailed information about a node in the current RDF data.
    ///
    /// # Arguments
    ///
    /// * `node` - Node identifier (IRI or prefixed name) to inspect
    /// * `predicates` - Optional list of predicates used to filter displayed relations
    /// * `show_node_mode` - Optional inspection mode controlling the level of detail (uses default if None)
    /// * `depth` - Optional maximum traversal depth when expanding related nodes (uses 1 by default)
    /// * `show_hyperlinks` - Whether hyperlinks should be included in the output (uses false by default)
    /// * `show_colors` - Whether colored output should be used (uses false by default)
    /// * `iri_mode` - IRI normalization mode to apply when parsing the node identifier
    /// * `writer` - The destination to write the node information to
    ///
    /// # Errors
    ///
    /// Returns an error if the node information cannot be retrieved or serialized.
    fn show_node_info<W: io::Write>(
        &mut self,
        node: &str,
        predicates: Option<&[String]>,
        show_node_mode: Option<&NodeInspectionMode>,
        depth: Option<usize>,
        show_hyperlinks: Option<bool>,
        show_colors: Option<bool>,
        iri_mode: IriNormalizationMode,
        writer: &mut W,
    ) -> Result<()>;

    /// Returns a lazy iterator over the neighborhood of every node matched by `node`
    ///
    /// # Arguments
    ///
    /// * `node` - Node identifier (IRI, prefixed name, or blank node) whose neighborhood is traversed
    /// * `predicates` - Optional list of predicates; when given, only arcs with these predicates are followed
    /// * `mode - Optional inspection mode selecting the arc directions
    /// * `depth`- Optional maximum transversal depth (default is 1)
    /// * `iri_mode` - IRI normalization mode to apply when parsing the node identifier
    ///
    /// # Errors
    ///
    /// Returns an error if no RDF data is loaded or the node selector or predicates can´t be resolved.
    fn node_neighborhood<'a>(
        &'a self,
        node: &str,
        predicates: Option<&[String]>,
        mode: Option<&NodeInspectionMode>,
        depth: Option<usize>,
        iri_mode: IriNormalizationMode,
    ) -> Result<NodeNeighborhood<'a>>;

    /// Adds a triple to the current RDF data.
    ///
    /// # Arguments
    ///
    /// * `subject` - The subject, as an IRI (`<http://example.org/alice>`, `ex:alice`)
    ///   or a blank node (`_:b1`)
    /// * `predicate` - The predicate, as an angle-bracketed IRI or a prefixed name
    /// * `object` - The object, as an IRI, a blank node or a literal (`"Alice"`,
    ///   `"Alice"@en`, `23`, `"23"^^xsd:integer`)
    /// * `iri_mode` - IRI normalization mode to apply when parsing the terms
    ///
    /// Prefixed names are resolved against the prefixes of the loaded data,
    /// supplemented by the session's default prefixes. Adding a triple the data
    /// already contains changes nothing, an RDF graph being a set of triples.
    ///
    /// # Errors
    ///
    /// Returns an error if no RDF data is loaded, or if a term cannot be parsed or
    /// its prefix resolved.
    ///
    /// Also if the data cannot be modified: only the in-memory graph can be. A SPARQL
    /// endpoint and the QLever backend are read-only, and so is data federated with
    /// SPARQL endpoints — the local graph of such a session is deliberately not
    /// written to instead, since [`triples`](Self::triples) reads it and the
    /// endpoints' as one.
    fn add_triple(
        &mut self,
        subject: &str,
        predicate: &str,
        object: &str,
        iri_mode: IriNormalizationMode,
    ) -> Result<()>;

    /// Removes a triple from the current RDF data.
    ///
    /// # Arguments
    ///
    /// As [`add_triple`](Self::add_triple).
    ///
    /// # Errors
    ///
    /// As [`add_triple`](Self::add_triple).
    fn remove_triple(
        &mut self,
        subject: &str,
        predicate: &str,
        object: &str,
        iri_mode: IriNormalizationMode,
    ) -> Result<()>;

    /// Returns an iterator over the triples of the current RDF data matching a
    /// pattern.
    ///
    /// # Arguments
    ///
    /// * `subject` - The subject to match, as in [`add_triple`](Self::add_triple);
    ///   `None` matches any subject
    /// * `predicate` - The predicate to match; `None` matches any predicate
    /// * `object` - The object to match; `None` matches any object
    /// * `iri_mode` - IRI normalization mode to apply when parsing the terms
    ///
    /// All three `None` walks the whole graph. The iterator borrows the data, which
    /// therefore cannot be modified while its triples are being walked.
    ///
    /// # Errors
    ///
    /// Returns an error if no RDF data is loaded, or if a term of the pattern cannot
    /// be parsed or its prefix resolved.
    ///
    /// # Note
    ///
    /// The triples are retrieved before the iterator is returned, and a pattern with
    /// a SPARQL endpoint or the QLever backend as the data retrieves them from there:
    /// an unconstrained pattern then pulls the whole remote graph.
    fn triples<'a>(
        &'a self,
        subject: Option<&str>,
        predicate: Option<&str>,
        object: Option<&str>,
        iri_mode: IriNormalizationMode,
    ) -> Result<Triples<'a>>;

    /// Lists the registered SPARQL endpoints.
    ///
    /// Returns:
    ///     List of (name, url) tuples for known endpoints.
    fn list_endpoints(&mut self) -> Result<Vec<(String, String)>>;

    /// Dereferences `uri` over HTTP(S) and merges the resulting RDF data.
    ///
    /// Sends a GET request content-negotiating for an RDF serialization
    /// (`text/turtle`, `application/rdf+xml`, `application/ld+json`, ...),
    /// following redirects, and parses the response body using the format
    /// indicated by its `Content-Type` header (falling back to Turtle if the
    /// header is missing or unrecognized).
    ///
    /// # Arguments
    ///
    /// * `uri` - The absolute IRI to dereference
    /// * `reader_mode` - The parsing mode (uses default if None)
    /// * `merge` - Whether to merge with existing data or replace it (defaults to true)
    ///
    /// # Errors
    ///
    /// Returns an error if the request fails, the response status is not
    /// successful, or the body cannot be parsed as RDF.
    fn dereference(&mut self, uri: &str, reader_mode: Option<&DataReaderMode>, merge: Option<bool>) -> Result<()>;
}

impl DataOperations for Rudof {
    fn load_data(
        &mut self,
        data: Option<&[InputSpec]>,
        data_format: Option<&DataFormat>,
        base: Option<&str>,
        endpoint: Option<&str>,
        reader_mode: Option<&DataReaderMode>,
        merge: Option<bool>,
        prefixes: Option<&[InputSpec]>,
        endpoint_strategy: EndpointStrategy,
    ) -> Result<()> {
        load_data(
            self,
            data,
            data_format,
            base,
            endpoint,
            reader_mode,
            merge,
            prefixes,
            endpoint_strategy,
        )
    }

    fn serialize_data<W: io::Write>(
        &mut self,
        result_data_format: Option<&ResultDataFormat>,
        viz_engine: Option<&VizEngine>,
        writer: &mut W,
    ) -> Result<()> {
        serialize_data(self, result_data_format, viz_engine, writer)
    }

    fn reset_data(&mut self) {
        reset_data(self)
    }

    fn load_service_description(
        &mut self,
        service: &InputSpec,
        data_format: Option<&DataFormat>,
        reader_mode: Option<&DataReaderMode>,
        base: Option<&str>,
    ) -> Result<()> {
        load_service_description(self, service, data_format, reader_mode, base)
    }

    fn serialize_service_description<W: io::Write>(
        &self,
        result_service_format: Option<&ResultServiceFormat>,
        writer: &mut W,
    ) -> Result<()> {
        serialize_service_description(self, result_service_format, writer)
    }

    fn reset_service_description(&mut self) {
        reset_service_description(self)
    }

    fn show_node_info<W: io::Write>(
        &mut self,
        node: &str,
        predicates: Option<&[String]>,
        show_node_mode: Option<&NodeInspectionMode>,
        depth: Option<usize>,
        show_hyperlinks: Option<bool>,
        show_colors: Option<bool>,
        iri_mode: IriNormalizationMode,
        writer: &mut W,
    ) -> Result<()> {
        show_node_info(
            self,
            node,
            predicates,
            show_node_mode,
            depth,
            show_hyperlinks,
            show_colors,
            iri_mode,
            writer,
        )
    }

    fn node_neighborhood<'a>(
        &'a self,
        node: &str,
        predicates: Option<&[String]>,
        mode: Option<&NodeInspectionMode>,
        depth: Option<usize>,
        iri_mode: IriNormalizationMode,
    ) -> Result<NodeNeighborhood<'a>> {
        node_neighborhood(self, node, predicates, mode, depth, iri_mode)
    }

    fn add_triple(
        &mut self,
        subject: &str,
        predicate: &str,
        object: &str,
        iri_mode: IriNormalizationMode,
    ) -> Result<()> {
        add_triple(self, subject, predicate, object, iri_mode)
    }

    fn remove_triple(
        &mut self,
        subject: &str,
        predicate: &str,
        object: &str,
        iri_mode: IriNormalizationMode,
    ) -> Result<()> {
        remove_triple(self, subject, predicate, object, iri_mode)
    }

    fn triples<'a>(
        &'a self,
        subject: Option<&str>,
        predicate: Option<&str>,
        object: Option<&str>,
        iri_mode: IriNormalizationMode,
    ) -> Result<Triples<'a>> {
        triples(self, subject, predicate, object, iri_mode)
    }

    fn list_endpoints(&mut self) -> Result<Vec<(String, String)>> {
        list_endpoints(self)
    }

    fn dereference(&mut self, uri: &str, reader_mode: Option<&DataReaderMode>, merge: Option<bool>) -> Result<()> {
        dereference(self, uri, reader_mode, merge)
    }
}