diff --git a/Cargo.lock b/Cargo.lock index 6cff4a2..1e9082d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1676,6 +1676,7 @@ dependencies = [ "tracing", "tracing-appender", "tracing-subscriber", + "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 23c9053..a378090 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,4 +41,5 @@ tonic-prost-build = "0.14" tracing = "0.1" tracing-appender = "0.2" tracing-futures = "0.2" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } \ No newline at end of file +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +url = "2.5" \ No newline at end of file diff --git a/graph/src/curie.rs b/graph/src/curie.rs index 18e0dd8..24211ea 100644 --- a/graph/src/curie.rs +++ b/graph/src/curie.rs @@ -42,7 +42,6 @@ pub static PREFIXES: LazyLock> = LazyLock::new(|| { ("rdamt", "http://rdaregistry.info/termList/RDAMediaType/"), ("rdaft", "http://rdaregistry.info/termList/fileType/"), ("schema", "https://schema.org/"), - ("gl", "http://fedora.quill.lan/rest/"), ("glo", ONTOLOGY_PREFIX), ] .map(|(k, v)| (k.to_string(), v.to_string())), diff --git a/graph/src/index.rs b/graph/src/index.rs index e648a0a..872fbba 100644 --- a/graph/src/index.rs +++ b/graph/src/index.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use oxigraph::model::NamedNode; use oxigraph::sparql::results::{QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput}; -use gl_inference::Channel; +use gl_inference::tonic::transport::Channel; use gl_inference::proto::ontology_client::OntologyClient; use gl_inference::proto::OntologyQueryRequest; use gl_search::{Field, OwnedValue, Schema}; diff --git a/inference/src/lib.rs b/inference/src/lib.rs index f31abce..52a8864 100644 --- a/inference/src/lib.rs +++ b/inference/src/lib.rs @@ -2,4 +2,4 @@ pub mod proto { tonic::include_proto!("org.graphofliberty.inference"); } -pub use tonic::transport::Channel; \ No newline at end of file +pub use tonic; \ No newline at end of file diff --git a/inference/src/service.rs b/inference/src/service.rs index d5e9e76..32a1d65 100644 --- a/inference/src/service.rs +++ b/inference/src/service.rs @@ -110,8 +110,18 @@ impl Ontology for OntologyService { ONTOLOGY_GRAPH.into_owned() }; - let mut query = SparqlEvaluator::new() - .parse_query(&request.sparql_query) + let mut evaluator = SparqlEvaluator::new(); + for (name, iri) in &request.prefixes { + evaluator = evaluator.with_prefix(name, iri) + .map_err(|err| Status::internal(err.to_string()))?; + } + + if let Some(base) = &request.base { + evaluator = evaluator.with_base_iri(base) + .map_err(|err| Status::internal(err.to_string()))?; + } + + let mut query = evaluator.parse_query(&request.sparql_query) .map_err(|err| Status::internal(err.to_string()))?; query.dataset_mut().set_default_graph(vec![graph_name.clone()]); @@ -137,15 +147,17 @@ impl Ontology for OntologyService { output_buffer = writer.finish()?; } QueryResults::Graph(graph) => { - let mut serializer = RdfSerializer::from_format(RdfFormat::Turtle) - .with_prefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#").map_err(|err| Status::internal(err.to_string()))? - .with_prefix("rdac", "http://rdaregistry.info/Elements/c/").map_err(|err| Status::internal(err.to_string()))? - .with_prefix("ldp", "http://www.w3.org/ns/ldp#").map_err(|err| Status::internal(err.to_string()))? - .with_prefix("fedora", "http://fedora.info/definitions/v4/repository#").map_err(|err| Status::internal(err.to_string()))? - .with_prefix("lrmer", "http://iflastandards.info/ns/lrm/lrmer/").map_err(|err| Status::internal(err.to_string()))? - .with_prefix("owl", "http://www.w3.org/2002/07/owl#").map_err(|err| Status::internal(err.to_string()))? - .with_base_iri("http://fedora.quill.lan/rest/").map_err(|err| Status::internal(err.to_string()))? - .for_writer(output_buffer); + let mut serializer = RdfSerializer::from_format(RdfFormat::Turtle); + for (name, iri) in &request.prefixes { + serializer = serializer.with_prefix(name, iri) + .map_err(|err| Status::internal(err.to_string()))?; + } + if let Some(base) = &request.base { + serializer = serializer.with_base_iri(base) + .map_err(|err| Status::internal(err.to_string()))?; + } + + let mut serializer = serializer.for_writer(output_buffer); for triple in graph.filter_map(Result::ok) { serializer.serialize_triple(triple.as_ref())?; } diff --git a/proto/inference.proto b/proto/inference.proto index 5fc115e..42b7892 100644 --- a/proto/inference.proto +++ b/proto/inference.proto @@ -20,6 +20,8 @@ message OntologyClearResponse { message OntologyQueryRequest { optional string turtle = 1; string sparql_query = 2; + map prefixes = 3; + optional string base = 4; } message OntologyQueryResponse { diff --git a/publish/Cargo.toml b/publish/Cargo.toml index 82937ce..3f34199 100644 --- a/publish/Cargo.toml +++ b/publish/Cargo.toml @@ -23,4 +23,5 @@ tokio.workspace = true tonic.workspace = true tracing.workspace = true tracing-appender.workspace = true -tracing-subscriber.workspace = true \ No newline at end of file +tracing-subscriber.workspace = true +url.workspace = true \ No newline at end of file diff --git a/publish/src/args.rs b/publish/src/args.rs index deaf2c8..b2d6d31 100644 --- a/publish/src/args.rs +++ b/publish/src/args.rs @@ -8,6 +8,9 @@ pub(crate) struct QueryArgs { #[arg(short, long, value_name = "QUERY PATH")] pub(crate) query_path: PathBuf, + + #[arg(short, long, value_name = "BASE IRI")] + pub(crate) base: Option, } #[derive(Args)] diff --git a/publish/src/error.rs b/publish/src/error.rs index 84b6424..e85c417 100644 --- a/publish/src/error.rs +++ b/publish/src/error.rs @@ -11,7 +11,10 @@ pub(crate) enum Error { Storage(#[from] oxigraph::store::StorageError), #[error(transparent)] - IriParse(#[from] oxigraph::model::IriParseError), + ParseIri(#[from] oxigraph::model::IriParseError), + + #[error(transparent)] + ParseUrl(#[from] url::ParseError), #[error(transparent)] RdfSyntax(#[from] oxigraph::io::RdfSyntaxError), @@ -36,4 +39,7 @@ pub(crate) enum Error { #[error(transparent)] Join(#[from] tokio::task::JoinError), + + #[error(transparent)] + TonicTransport(#[from] tonic::transport::Error), } \ No newline at end of file diff --git a/publish/src/main.rs b/publish/src/main.rs index d7d8a11..596d5ba 100644 --- a/publish/src/main.rs +++ b/publish/src/main.rs @@ -7,13 +7,14 @@ mod theme; mod widget; mod windows; +use std::collections::HashMap; use crate::app::Publisher; use crate::args::{AppArgs, Command}; use clap::Parser; use gl_search::{Schema, SearchIndex}; use iced::futures::StreamExt; use ldp::middleware::BasicAuthMiddleware; -use ldp::reqwest::{Client, Url}; +use ldp::reqwest::Client; use ldp::reqwest_middleware::ClientBuilder; use ldp::traverse::Traverse; use oxigraph::model::Dataset; @@ -22,6 +23,7 @@ use tracing_subscriber::fmt::format::FmtSpan; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{EnvFilter, fmt}; +use url::Url; use gl_graph::index::index_ontology; use gl_graph::language; use gl_inference::proto::ontology_client::OntologyClient; @@ -53,6 +55,12 @@ fn main() -> color_eyre::Result<()> { Some(String::from_utf8(std::fs::read(dataset_path)?)?) } else { None }; + let mut request = OntologyQueryRequest::default(); + request.sparql_query = raw_query; + request.turtle = graph; + request.prefixes = HashMap::from_iter(gl_graph::PREFIXES.iter().map(|(name, iri)| (name.clone(), iri.clone()))); + request.base = args.base.clone(); + let runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() .name("inference-client") @@ -60,11 +68,6 @@ fn main() -> color_eyre::Result<()> { runtime.block_on(async { let mut client = OntologyClient::connect("http://[::1]:3000").await.unwrap(); - - let mut request = OntologyQueryRequest::default(); - request.sparql_query = raw_query; - request.turtle = graph; - let response = client.query(request).await.unwrap(); println!("{}", response.get_ref().results); }); @@ -87,14 +90,15 @@ fn main() -> color_eyre::Result<()> { .build()?; runtime.block_on(async { - let mut client = OntologyClient::connect("http://[::1]:3000").await.unwrap(); - let documents = index_ontology(&mut client, &language::ENGLISH_OR_UNTAGGED).await.unwrap(); + let mut client = OntologyClient::connect("http://[::1]:3000").await?; + let documents = index_ontology(&mut client, &language::ENGLISH_OR_UNTAGGED).await?; debug_span!("Index Ontology", documents = field::Empty).in_scope(|| { for document in documents { writer.add_document(document).unwrap(); } }); - }); + Ok::<_, crate::error::Error>(()) + })?; let mut writer = runtime.block_on(async move { let http_client = ClientBuilder::new(Client::new()) @@ -104,18 +108,23 @@ fn main() -> color_eyre::Result<()> { )) .build(); - let starting_url = Url::parse("http://fedora.quill.lan/rest/").unwrap(); + let starting_url = Url::parse("http://fedora.quill.lan/rest/")?; let mut dataset = Dataset::new(); let mut traversal = Traverse::new(http_client, starting_url, None); + let mut rdf_source_count = 0usize; while let Some(result) = traversal.next().await { match result { - Ok(rdf_source) => dataset.extend(rdf_source.dataset()), + Ok(rdf_source) => { + dataset.extend(rdf_source.dataset()); + rdf_source_count += 1; + }, Err(err) => error!(?err), } } let span = debug_span!("Index Repository", rdf_sources = field::Empty, documents = field::Empty).entered(); - Ok::<_, gl_search::SearchError>(writer) + span.record("rdf_sources", rdf_source_count); + Ok::<_, crate::error::Error>(writer) })?; debug_span!("Commit").in_scope(|| writer.commit())?;