From 156781fb19a6c8b6bd7d4df6199299850ec66933 Mon Sep 17 00:00:00 2001 From: Laurin Weger Date: Thu, 25 Sep 2025 19:24:22 +0200 Subject: [PATCH] orm tests: sparql construct not working: Invalid graph_name (not a NamedNode) in parse_graph_name --- Cargo.lock | 1 + nextgraph/Cargo.toml | 14 ++++-- nextgraph/src/local_broker.rs | 81 +++++++++++++++++++++++++---------- nextgraph/src/tests/orm.rs | 34 +++++++++++---- ng-verifier/src/orm.rs | 22 +++++++--- 5 files changed, 112 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82c8588..8dea1ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2160,6 +2160,7 @@ dependencies = [ "lazy_static", "ng-client-ws", "ng-net", + "ng-oxigraph", "ng-repo", "ng-storage-rocksdb", "ng-verifier", diff --git a/nextgraph/Cargo.toml b/nextgraph/Cargo.toml index 15dc148..1b30f3a 100644 --- a/nextgraph/Cargo.toml +++ b/nextgraph/Cargo.toml @@ -1,14 +1,20 @@ [package] name = "nextgraph" description = "NextGraph client library. Nextgraph is a decentralized, secure and local-first web 3.0 ecosystem based on Semantic Web and CRDTs" -categories = ["asynchronous","text-editors","web-programming","development-tools","database-implementations"] +categories = [ + "asynchronous", + "text-editors", + "web-programming", + "development-tools", + "database-implementations", +] version = "0.1.2" edition.workspace = true license.workspace = true authors.workspace = true repository.workspace = true homepage.workspace = true -keywords = [ "crdt","e2ee","local-first","p2p","semantic-web" ] +keywords = ["crdt", "e2ee", "local-first", "p2p", "semantic-web"] documentation = "https://docs.rs/nextgraph" rust-version.workspace = true @@ -23,7 +29,7 @@ base64-url = "2.0.0" once_cell = "1.17.1" zeroize = { version = "1.7.0", features = ["zeroize_derive"] } futures = "0.3.24" -async-std = { version = "1.12.0", features = [ "attributes", "unstable" ] } +async-std = { version = "1.12.0", features = ["attributes", "unstable"] } async-trait = "0.1.64" async-once-cell = "0.5.3" lazy_static = "1.4.0" @@ -37,6 +43,7 @@ ng-net = { path = "../ng-net", version = "0.1.2" } ng-wallet = { path = "../ng-wallet", version = "0.1.2" } ng-client-ws = { path = "../ng-client-ws", version = "0.1.2" } ng-verifier = { path = "../ng-verifier", version = "0.1.2" } +ng-oxigraph = { path = "../ng-oxigraph", version = "0.4.0-alpha.8-ngalpha" } [target.'cfg(all(not(target_family = "wasm"),not(docsrs)))'.dependencies] ng-storage-rocksdb = { path = "../ng-storage-rocksdb", version = "0.1.2" } @@ -52,4 +59,3 @@ required-features = [] [[example]] name = "open" required-features = [] - diff --git a/nextgraph/src/local_broker.rs b/nextgraph/src/local_broker.rs index ea6fd6c..7d2db65 100644 --- a/nextgraph/src/local_broker.rs +++ b/nextgraph/src/local_broker.rs @@ -18,6 +18,7 @@ use async_std::sync::{Arc, Condvar, Mutex, RwLock}; use futures::channel::mpsc; use futures::{SinkExt, StreamExt}; use lazy_static::lazy_static; +use ng_oxigraph::oxrdf::Triple; use once_cell::sync::Lazy; use pdf_writer::{Content, Finish, Name, Pdf, Rect, Ref, Str}; use qrcode::{render::svg, QrCode}; @@ -626,33 +627,43 @@ async fn pump( event, overlay, user, - } => { + } => { let mut broker = match LOCAL_BROKER.get() { - None | Some(Err(_)) => return Err(Box::new(NgError::LocalBrokerNotInitialized)), + None | Some(Err(_)) => { + return Err(Box::new(NgError::LocalBrokerNotInitialized)) + } Some(Ok(broker)) => broker.write().await, }; broker.deliver(event, overlay, user).await - }, - LocalBrokerMessage::Inbox {msg, user_id, from_queue} => { + } + LocalBrokerMessage::Inbox { + msg, + user_id, + from_queue, + } => { async_std::task::spawn_local(async move { let mut broker = match LOCAL_BROKER.get() { - None | Some(Err(_)) => return Err(Box::new(NgError::LocalBrokerNotInitialized)), + None | Some(Err(_)) => { + return Err(Box::new(NgError::LocalBrokerNotInitialized)) + } Some(Ok(broker)) => broker.write().await, }; if let Some(session) = broker.get_mut_session_for_user(&user_id) { session.verifier.inbox(&msg, from_queue).await; } Ok(()) - }).await?; - - }, - LocalBrokerMessage::Disconnected { user_id } => { + }) + .await?; + } + LocalBrokerMessage::Disconnected { user_id } => { let mut broker = match LOCAL_BROKER.get() { - None | Some(Err(_)) => return Err(Box::new(NgError::LocalBrokerNotInitialized)), + None | Some(Err(_)) => { + return Err(Box::new(NgError::LocalBrokerNotInitialized)) + } Some(Ok(broker)) => broker.write().await, }; broker.user_disconnected(user_id).await - }, + } } } @@ -2517,7 +2528,11 @@ pub async fn user_connect_with_device_info( // try to pop inbox msg let broker = BROKER.read().await; broker - .send_client_event(&Some(*user), &Some(server_key), ClientEvent::InboxPopRequest) + .send_client_event( + &Some(*user), + &Some(server_key), + ClientEvent::InboxPopRequest, + ) .await?; } break; @@ -2561,7 +2576,9 @@ pub async fn session_stop(user_id: &UserId) -> Result<(), NgError> { force_close: false, }); - broker.send_request_headless::<_, EmptyAppResponse>(request).await?; + broker + .send_request_headless::<_, EmptyAppResponse>(request) + .await?; } _ => { // TODO implement for Remote @@ -2606,7 +2623,9 @@ pub async fn session_headless_stop(session_id: u64, force_close: bool) -> Result force_close, }); - broker.send_request_headless::<_, EmptyAppResponse>(request).await?; + broker + .send_request_headless::<_, EmptyAppResponse>(request) + .await?; } _ => { return Err(NgError::LocalBrokerIsNotHeadless); @@ -2723,10 +2742,28 @@ pub async fn doc_sparql_update( match res { AppResponse::V0(AppResponseV0::Error(e)) => Err(e), AppResponse::V0(AppResponseV0::Commits(commits)) => Ok(commits), - _ => Err(NgError::InvalidResponse.to_string()) + _ => Err(NgError::InvalidResponse.to_string()), } } +async fn get_broker() -> Result, NgError> { + let broker = match LOCAL_BROKER.get() { + None | Some(Err(_)) => return Err(NgError::LocalBrokerNotInitialized), + Some(Ok(broker)) => broker.write().await, + }; + return Ok(broker); +} + +pub async fn doc_sparql_construct( + session_id: u64, + sparql: String, + nuri: Option, +) -> Result, NgError> { + let broker = get_broker().await?; + let session = broker.get_session(session_id)?; + session.verifier.sparql_construct(sparql, nuri) +} + pub async fn doc_create( session_id: u64, crdt: String, @@ -2735,14 +2772,16 @@ pub async fn doc_create( store_type: Option, store_repo: Option, ) -> Result { - let store_repo = if store_type.is_none() || store_repo.is_none() { None } else { - Some(StoreRepo::from_type_and_repo(&store_type.unwrap(), &store_repo.unwrap())?) + Some(StoreRepo::from_type_and_repo( + &store_type.unwrap(), + &store_repo.unwrap(), + )?) }; - doc_create_with_store_repo(session_id,crdt,class_name,destination,store_repo).await + doc_create_with_store_repo(session_id, crdt, class_name, destination, store_repo).await } pub async fn doc_create_with_store_repo( @@ -2752,7 +2791,6 @@ pub async fn doc_create_with_store_repo( destination: String, store_repo: Option, ) -> Result { - let class = BranchCrdt::from(crdt, class_name)?; let nuri = if store_repo.is_none() { @@ -2768,10 +2806,7 @@ pub async fn doc_create_with_store_repo( command: AppRequestCommandV0::new_create(), nuri, payload: Some(AppRequestPayload::V0(AppRequestPayloadV0::Create( - DocCreate { - class, - destination, - }, + DocCreate { class, destination }, ))), }); diff --git a/nextgraph/src/tests/orm.rs b/nextgraph/src/tests/orm.rs index 8860b78..2a329b5 100644 --- a/nextgraph/src/tests/orm.rs +++ b/nextgraph/src/tests/orm.rs @@ -12,8 +12,8 @@ use std::io::{Read, Write}; use std::path::PathBuf; use crate::local_broker::{ - doc_create, doc_sparql_update, init_local_broker, session_start, session_stop, user_disconnect, - wallet_close, wallet_create_v0, wallet_get_file, wallet_import, + doc_create, doc_sparql_construct, doc_sparql_update, init_local_broker, session_start, + session_stop, user_disconnect, wallet_close, wallet_create_v0, wallet_get_file, wallet_import, wallet_open_with_mnemonic_words, wallet_read_file, LocalBrokerConfig, SessionConfig, }; use ng_net::types::BootstrapContentV0; @@ -91,6 +91,7 @@ async fn create_or_open_wallet() -> (SensitiveWallet, u64) { )) .await .unwrap(); + session_id = session.session_id; } else { // first run: create wallet @@ -173,6 +174,17 @@ INSERT DATA { .to_string() } +fn build_construct_sparql() -> String { + r#" +CONSTRUCT { + ?s ?p ?o . +} WHERE { + ?s ?p ?o . +} +"# + .to_string() +} + #[async_std::test] async fn test_wallet_and_sparql_insert() { let (wallet, session_id) = create_or_open_wallet().await; @@ -191,12 +203,18 @@ async fn test_wallet_and_sparql_insert() { log_info!("session_id: {:?} doc nuri: {:?}", session_id, doc_nuri); - let result = doc_sparql_update(session_id, sparql.clone(), Some(doc_nuri.clone())).await; - assert!(result.is_ok(), "SPARQL update failed: {:?}", result.err()); - - // Optional: a second idempotent insert should not duplicate (implementation dependent) - let second = doc_sparql_update(session_id, sparql, Some(doc_nuri)).await; - assert!(second.is_ok()); + let update_result = doc_sparql_update(session_id, sparql.clone(), Some(doc_nuri.clone())).await; + assert!( + update_result.is_ok(), + "SPARQL update failed: {:?}", + update_result.err() + ); + log_info!("Sparql update result: {:?}", update_result.unwrap()); + + // Query the data. + let query_result = + doc_sparql_construct(session_id, build_construct_sparql(), Some(doc_nuri.clone())).await; + log_info!("Sparql construct result: {:?}", query_result.unwrap()); user_disconnect(&wallet.personal_identity()) .await diff --git a/ng-verifier/src/orm.rs b/ng-verifier/src/orm.rs index 11244fc..8dabd38 100644 --- a/ng-verifier/src/orm.rs +++ b/ng-verifier/src/orm.rs @@ -30,17 +30,23 @@ use crate::types::*; use crate::verifier::*; impl Verifier { - fn sparql_construct(&self, query: String) -> Result, NgError> { + pub fn sparql_construct( + &self, + query: String, + nuri: Option, + ) -> Result, NgError> { let oxistore = self.graph_dataset.as_ref().unwrap(); // let graph_nuri = NuriV0::repo_graph_name( // &update.repo_id, // &update.overlay_id, // ); - //let base = NuriV0::repo_id(&repo.id); + + let nuri_str = nuri.as_ref().map(|s| s.as_str()); + let parsed = - Query::parse(&query, None).map_err(|e| NgError::OxiGraphError(e.to_string()))?; + Query::parse(&query, nuri_str).map_err(|e| NgError::OxiGraphError(e.to_string()))?; let results = oxistore .query(parsed, None) .map_err(|e| NgError::OxiGraphError(e.to_string()))?; @@ -62,7 +68,11 @@ impl Verifier { } } - fn sparql_select(&self, query: String) -> Result>>, NgError> { + pub fn sparql_select( + &self, + query: String, + nuri: Option, + ) -> Result>>, NgError> { let oxistore = self.graph_dataset.as_ref().unwrap(); // let graph_nuri = NuriV0::repo_graph_name( @@ -71,8 +81,10 @@ impl Verifier { // ); //let base = NuriV0::repo_id(&repo.id); + let nuri_str = nuri.as_ref().map(|s| s.as_str()); + let parsed = - Query::parse(&query, None).map_err(|e| NgError::OxiGraphError(e.to_string()))?; + Query::parse(&query, nuri_str).map_err(|e| NgError::OxiGraphError(e.to_string()))?; let results = oxistore .query(parsed, None) .map_err(|e| NgError::OxiGraphError(e.to_string()))?;