skolemization of blank nodes and BASE in SPARQl query and update

master
Niko PLP 3 months ago
parent d03d15f9b7
commit 077ba6265e
  1. 51
      nextgraph/src/local_broker.rs
  2. 9
      ng-app/src-tauri/src/lib.rs
  3. 2
      ng-app/src/apps/SparqlUpdateEditor.svelte
  4. 2
      ng-app/src/lib/FullLayout.svelte
  5. 3
      ng-app/src/lib/Home.svelte
  6. 6
      ng-app/src/routes/NURI.svelte
  7. 2
      ng-app/src/routes/Shared.svelte
  8. 2
      ng-app/src/routes/Site.svelte
  9. 6
      ng-app/src/store.ts
  10. 2
      ng-app/src/tab.ts
  11. 30
      ng-app/src/wallet_emojis.ts
  12. 26
      ng-net/src/app_protocol.rs
  13. 3
      ng-oxigraph/src/oxrdf/parser.rs
  14. 50
      ng-sdk-js/README.md
  15. 44
      ng-sdk-js/app-node/index.js
  16. 40
      ng-sdk-js/src/lib.rs
  17. 52
      ng-verifier/src/commits/transaction.rs
  18. 35
      ng-verifier/src/request_processor.rs
  19. 13
      ng-verifier/src/verifier.rs

@ -1085,15 +1085,15 @@ impl LocalBroker {
}
fn add_session(&mut self, session: Session) -> Result<SessionInfo, NgError> {
let private_store_id = self
.get_site_store_of_session(&session, SiteStoreType::Private)?
.to_string();
let protected_store_id = self
.get_site_store_of_session(&session, SiteStoreType::Protected)?
.to_string();
let public_store_id = self
.get_site_store_of_session(&session, SiteStoreType::Public)?
.to_string();
let private_store_id = NuriV0::to_store_nuri_string(
&self.get_site_store_of_session(&session, SiteStoreType::Private)?,
);
let protected_store_id = NuriV0::to_store_nuri_string(
&self.get_site_store_of_session(&session, SiteStoreType::Protected)?,
);
let public_store_id = NuriV0::to_store_nuri_string(
&self.get_site_store_of_session(&session, SiteStoreType::Public)?,
);
let user_id = session.config.user_id();
@ -2216,9 +2216,9 @@ pub async fn session_start(config: SessionConfig) -> Result<SessionInfo, NgError
}
if let Ok(AppResponse::V0(AppResponseV0::SessionStart(AppSessionStartResponse::V0(response)))) = res {
session_info.private_store_id = response.private_store.to_string();
session_info.protected_store_id = response.protected_store.to_string();
session_info.public_store_id = response.public_store.to_string();
session_info.private_store_id = NuriV0::to_store_nuri_string(&response.private_store);
session_info.protected_store_id = NuriV0::to_store_nuri_string(&response.protected_store);
session_info.public_store_id = NuriV0::to_store_nuri_string(&response.public_store);
}
Ok(session_info)
@ -2245,15 +2245,24 @@ pub async fn session_start(config: SessionConfig) -> Result<SessionInfo, NgError
return Ok(SessionInfo {
session_id: *idx,
user: user_id,
private_store_id: broker
.get_site_store_of_session(sess, SiteStoreType::Private)?
.to_string(),
protected_store_id: broker
.get_site_store_of_session(sess, SiteStoreType::Protected)?
.to_string(),
public_store_id: broker
.get_site_store_of_session(sess, SiteStoreType::Public)?
.to_string(),
private_store_id: NuriV0::to_store_nuri_string(
&broker.get_site_store_of_session(
sess,
SiteStoreType::Private,
)?,
),
protected_store_id: NuriV0::to_store_nuri_string(
&broker.get_site_store_of_session(
sess,
SiteStoreType::Protected,
)?,
),
public_store_id: NuriV0::to_store_nuri_string(
&broker.get_site_store_of_session(
sess,
SiteStoreType::Public,
)?,
),
});
}
}

@ -537,12 +537,12 @@ async fn branch_history(session_id: u64, nuri: String) -> Result<AppHistoryJs, S
#[tauri::command(rename_all = "snake_case")]
async fn sparql_update(session_id: u64, sparql: String, nuri: String) -> Result<(), String> {
let nuri = NuriV0::new_from(&nuri).map_err(|e| e.to_string())?;
let nuriv0 = NuriV0::new_from(&nuri).map_err(|e| e.to_string())?;
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_write_query(),
nuri,
payload: Some(AppRequestPayload::new_sparql_query(sparql)),
nuri: nuriv0,
payload: Some(AppRequestPayload::new_sparql_query(sparql, Some(nuri))),
session_id,
});
@ -560,6 +560,7 @@ async fn sparql_update(session_id: u64, sparql: String, nuri: String) -> Result<
async fn sparql_query(
session_id: u64,
sparql: String,
base: Option<String>,
nuri: Option<String>,
) -> Result<Value, String> {
let nuri = if nuri.is_some() {
@ -571,7 +572,7 @@ async fn sparql_query(
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_read_query(),
nuri,
payload: Some(AppRequestPayload::new_sparql_query(sparql)),
payload: Some(AppRequestPayload::new_sparql_query(sparql, base)),
session_id,
});

@ -33,7 +33,7 @@
onMount(()=>{
reset_in_memory();
if (!$in_memory_discrete){
$in_memory_discrete = "INSERT DATA { \n <did:ng:test> <test:predicate> \"An example value\".\r}";
$in_memory_discrete = "INSERT DATA { \n <> <example:predicate> \"An example value\".\r}";
}
});
const run = async () => {

@ -558,7 +558,7 @@
await reset_toasts();
let store_repo = $cur_tab.store.repo;
if (!store_repo) {
store_repo = $all_tabs["o:"+$active_session.private_store_id].store.repo
store_repo = $all_tabs[$active_session.private_store_id].store.repo
}
let nuri = await ng.doc_create($active_session.session_id, get_class(class_name)["ng:crdt"], class_name, store_repo, destination);
push("#/"+nuri);

@ -51,7 +51,7 @@
reset_in_memory();
});
let nuri = $active_session && ("o:"+$active_session.private_store_id);
let nuri = $active_session && $active_session.private_store_id;
</script>
<FullLayout withoutNavBar={true}>
@ -119,6 +119,7 @@
<Square3Stack3d tabindex="-1" class="mt-1 flex-none w-7 h-7 mr-1 focus:outline-none "/><div class="text-xs xs:text-sm flex items-center"><div style="overflow-wrap: anywhere;" class="max-h-8 xs:max-h-10">{$t("doc.header.buttons.all_docs")}</div></div>
</div>
</div>
<Document {nuri}/>
</FullLayout>
<svelte:window bind:innerWidth={width} />

@ -32,9 +32,9 @@
} from "svelte-heros-v2";
//console.log(params);
let nuri = "";
$: if ($active_session && params[1]) { if (params[1].startsWith("o:"+$active_session.private_store_id)) push("#/");
else if (params[1].startsWith("o:"+$active_session.protected_store_id)) push("#/shared");
else if (params[1].startsWith("o:"+$active_session.public_store_id)) push("#/site"); else nuri = params[1]; }
$: if ($active_session && params[1]) { if (params[1].startsWith($active_session.private_store_id)) push("#/");
else if (params[1].startsWith($active_session.protected_store_id)) push("#/shared");
else if (params[1].startsWith($active_session.public_store_id)) push("#/site"); else nuri = params[1]; }
onMount(() => {
if ($cur_tab.store.store_type)
change_nav_bar(`nav:${$cur_tab.store.store_type}`,$t(`doc.${$cur_tab.store.store_type}_store`), true);

@ -30,7 +30,7 @@
change_nav_bar("nav:protected",$t("doc.protected_store"), false);
reset_in_memory();
});
let nuri = $active_session && ("o:"+$active_session.protected_store_id);
let nuri = $active_session && $active_session.protected_store_id;
</script>
<FullLayout>

@ -28,7 +28,7 @@
change_nav_bar("nav:public",$t("doc.public_store"), false);
reset_in_memory();
});
let nuri = $active_session && ("o:"+$active_session.public_store_id);
let nuri = $active_session && $active_session.public_store_id;
</script>
<FullLayout>

@ -433,8 +433,10 @@ export const sparql_query = async function(sparql:string, union:boolean) {
});
throw new Error("no session");
}
let nuri = union ? undefined : "did:ng:"+get(cur_tab).branch.nuri;
return await ng.sparql_query(session.session_id, sparql, nuri);
let base = "did:ng:"+get(cur_tab).branch.nuri;
console.log(base)
let nuri = union ? undefined : base;
return await ng.sparql_query(session.session_id, sparql, base, nuri);
}
export const sparql_update = async function(sparql:string) {

@ -245,7 +245,7 @@ export const all_tabs = writable({
can_edit: false,
},
branch: {
nuri: "", // :o or :o:b
nuri: "", // :o:v or :o:v:b
readcap: "", // "r:"
comment_branch: "", // nuri
class: "",

@ -1434,25 +1434,25 @@ export async function load_svg() {
/************** SPORT *********************/
// sport[0].svg = await import("./assets/pazzle/emoji_u1f93a.svg?component");
// sport[1].svg = await import("./assets/pazzle/emoji_u1f3c7.svg?component");
// sport[2].svg = await import("./assets/pazzle/emoji_u26f7.svg?component");
sport[0].svg = await import("./assets/pazzle/emoji_u1f93a.svg?component");
sport[1].svg = await import("./assets/pazzle/emoji_u1f3c7.svg?component");
sport[2].svg = await import("./assets/pazzle/emoji_u26f7.svg?component");
// sport[3].svg = await import("./assets/pazzle/emoji_u1f6a3.svg?component");
// sport[4].svg = await import("./assets/pazzle/emoji_u1f3ca.svg?component");
// sport[5].svg = await import("./assets/pazzle/emoji_u1f3c4.svg?component");
sport[3].svg = await import("./assets/pazzle/emoji_u1f6a3.svg?component");
sport[4].svg = await import("./assets/pazzle/emoji_u1f3ca.svg?component");
sport[5].svg = await import("./assets/pazzle/emoji_u1f3c4.svg?component");
// sport[6].svg = await import("./assets/pazzle/emoji_u1f3cb.svg?component");
// sport[7].svg = await import("./assets/pazzle/emoji_u1f93c.svg?component");
// sport[8].svg = await import("./assets/pazzle/emoji_u1f6b4.svg?component");
sport[6].svg = await import("./assets/pazzle/emoji_u1f3cb.svg?component");
sport[7].svg = await import("./assets/pazzle/emoji_u1f93c.svg?component");
sport[8].svg = await import("./assets/pazzle/emoji_u1f6b4.svg?component");
// sport[9].svg = await import("./assets/pazzle/emoji_u1fa82.svg?component");
// sport[10].svg = await import("./assets/pazzle/emoji_u26bd.svg?component");
// sport[11].svg = await import("./assets/pazzle/emoji_u1f3c0.svg?component");
sport[9].svg = await import("./assets/pazzle/emoji_u1fa82.svg?component");
sport[10].svg = await import("./assets/pazzle/emoji_u26bd.svg?component");
sport[11].svg = await import("./assets/pazzle/emoji_u1f3c0.svg?component");
// sport[12].svg = await import("./assets/pazzle/emoji_u1f3be.svg?component");
// sport[13].svg = await import("./assets/pazzle/emoji_u1f3d3.svg?component");
// sport[14].svg = await import("./assets/pazzle/emoji_u1f94b.svg?component");
sport[12].svg = await import("./assets/pazzle/emoji_u1f3be.svg?component");
sport[13].svg = await import("./assets/pazzle/emoji_u1f3d3.svg?component");
sport[14].svg = await import("./assets/pazzle/emoji_u1f94b.svg?component");
/************** BIGGER ANIMAL *********************/

@ -238,10 +238,27 @@ impl NuriV0 {
}
}
pub fn to_store_nuri_string(store_id: &RepoId) -> String {
let overlay_id = OverlayId::outer(store_id);
format!("o:{store_id}:v:{overlay_id}")
}
pub fn repo_graph_name(repo_id: &RepoId, overlay_id: &OverlayId) -> String {
format!("{DID_PREFIX}:o:{repo_id}:v:{overlay_id}")
}
pub fn repo_skolem(
prefix: &String,
peer_id: &Vec<u8>,
random: u128,
) -> Result<String, NgError> {
let mut arr = Vec::with_capacity(32);
arr.extend_from_slice(peer_id);
arr.extend_from_slice(&random.to_be_bytes());
let sko: SymKey = arr.as_slice().try_into()?;
Ok(format!("{prefix}:u:{sko}"))
}
pub fn overlay_id(overlay_id: &OverlayId) -> String {
format!("{DID_PREFIX}:v:{overlay_id}")
}
@ -612,7 +629,10 @@ impl AppSessionStart {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum DocQuery {
V0(String), // Sparql
V0 {
sparql: String,
base: Option<String>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
@ -718,8 +738,8 @@ pub enum AppRequestPayload {
}
impl AppRequestPayload {
pub fn new_sparql_query(query: String) -> Self {
AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0(query)))
pub fn new_sparql_query(sparql: String, base: Option<String>) -> Self {
AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0 { sparql, base }))
}
pub fn new_discrete_update(
head_strings: Vec<String>,

@ -192,8 +192,7 @@ fn read_blank_node(s: &str) -> Result<(BlankNode, &str), TermParseError> {
if let Some(remain) = s.strip_prefix("_:") {
let end = remain
.find(|v: char| {
v.is_whitespace()
|| matches!(v, '<' | '_' | '?' | '$' | '"' | '\'' | '>' | '@' | '^')
v.is_whitespace() || matches!(v, '<' | '?' | '$' | '"' | '\'' | '>' | '@' | '^')
})
.unwrap_or(remain.len());
let (value, remain) = remain.split_at(end);

@ -30,10 +30,10 @@ npm i ng-sdk-js
The API is divided in 4 parts:
- the wallet API that lets user open and change their wallet and use its credentials
- the LocalVerifier API to open the documents locally
- the RemoteVerifier API that is connecting to the ngd server and runs the verifier on the server.
- a special mode of operation for ngd called `Headless` where all the users of that server have given full control of their data, to the server.
- the wallet API that lets user open and change their wallet and use its credentials
- the LocalVerifier API to open the documents locally
- the RemoteVerifier API that is connecting to the ngd server and runs the verifier on the server.
- a special mode of operation for ngd called `Headless` where all the users of that server have given full control of their data, to the server.
All of those API share a common `Session API` (all the functions that have a session_id as first argument)
@ -73,29 +73,29 @@ entrust the credentials of user to an ngd server. coming soon
## Headless API
- `ng.init_headless(config)` must be called before any other call.
- `ng.admin_create_user(config)` creates a new user on the server, and populates their 3P stores. returns the user_id
- `ng.session_headless_start(user_id)` starts a new session for the user. returns the session info, including the session_id
- `ng.sparql_query(session_id, "[SPARQL query]")` returns or:
- for SELECT queries: a JSON Sparql Query Result as a Javascript object. [SPARQL Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json/)
- for CONSTRUCT queries: a list of quads in the format [RDF-JS data model](http://rdf.js.org/data-model-spec/) that can be used as ingress to RDFjs lib.
- for ASK queries: a boolean
- `ng.sparql_update(session_id, "[SPARQL update]")` returns nothing, but can throw an error.
- `ng.file_put_to_private_store(session_id,"[filename]","[mimetype]")` returns the Nuri (NextGraph URI) of the file, as a string.
- `ng.file_get_from_private_store(session_id, "[nuri]", callback)` returns a cancel function. The `callback(file)` function will be called as follow
- once at first with some metadata information in `file.V0.FileMeta`
- one or more times with all the blobs of data, in `file.V0.FileBinary`
- finally, one more time with `file.V0 == 'EndOfStream'`. See the example on how to reconstruct a buffer out of this.
- `ng.session_headless_stop(session_id, force_close)` stops the session, but doesn't close the remote verifier, except if force_close is true. if false, the verifier is detached from the session and continues to run on the server. A new session can then be reattached to it, by calling session_headless_start with the same user_id.
- `ng.init_headless(config)` must be called before any other call.
- `ng.admin_create_user(config)` creates a new user on the server, and populates their 3P stores. returns the user_id
- `ng.session_headless_start(user_id)` starts a new session for the user. returns the session info, including the session_id
- `ng.sparql_query(session_id, "[SPARQL query]", base, nuri)` returns or:
- for SELECT queries: a JSON Sparql Query Result as a Javascript object. [SPARQL Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json/)
- for CONSTRUCT queries: a list of quads in the format [RDF-JS data model](http://rdf.js.org/data-model-spec/) that can be used as ingress to RDFjs lib.
- for ASK queries: a boolean
- `ng.sparql_update(session_id, "[SPARQL update]")` returns nothing, but can throw an error.
- `ng.file_put_to_private_store(session_id,"[filename]","[mimetype]")` returns the Nuri (NextGraph URI) of the file, as a string.
- `ng.file_get_from_private_store(session_id, "[nuri]", callback)` returns a cancel function. The `callback(file)` function will be called as follow
- once at first with some metadata information in `file.V0.FileMeta`
- one or more times with all the blobs of data, in `file.V0.FileBinary`
- finally, one more time with `file.V0 == 'EndOfStream'`. See the example on how to reconstruct a buffer out of this.
- `ng.session_headless_stop(session_id, force_close)` stops the session, but doesn't close the remote verifier, except if force_close is true. if false, the verifier is detached from the session and continues to run on the server. A new session can then be reattached to it, by calling session_headless_start with the same user_id.
Here is the format of the config object to be supplied in the calls to `init_headless` and `admin_create_user`:
```js
config = {
server_peer_id: "[your server ID]",
admin_user_key: "[your admin key]",
client_peer_key: "[the client key]",
server_addr: "[IP and PORT of the server]", // this one is optional. it will default to localhost:1440. Format is: A.A.A.A:P for IPv4 or [AAAA:::]:P for IpV6
server_peer_id: "[your server ID]",
admin_user_key: "[your admin key]",
client_peer_key: "[the client key]",
server_addr: "[IP and PORT of the server]", // this one is optional. it will default to localhost:1440. Format is: A.A.A.A:P for IPv4 or [AAAA:::]:P for IpV6
};
```
@ -182,9 +182,9 @@ If you have configured a domain, then the web app can be accessed at https://app
Licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
`SPDX-License-Identifier: Apache-2.0 OR MIT`

@ -15,7 +15,8 @@ global.WebSocket = WebSocket;
let config = {
server_peer_id: "FtdzuDYGewfXWdoPuXIPb0wnd0SAg1WoA2B14S7jW3MA",
admin_user_key: "pye0YFzk1ix1amKEwd6AeqaUAN_PNpH5zGLomh0M1PAA",
client_peer_key: "GRP0QnlzaB8o2vdiBaNoOYDNOFX-uehLZMxeCaG3JA0A"
client_peer_key: "GRP0QnlzaB8o2vdiBaNoOYDNOFX-uehLZMxeCaG3JA0A",
server_addr: "127.0.0.1:14400"
};
ng.init_headless(config).then( async() => {
@ -24,7 +25,9 @@ ng.init_headless(config).then( async() => {
//let user_id = await ng.admin_create_user(config);
//console.log("user created: ",user_id);
let user_id = "tJVG293o6xirl3Ys5rzxMgdnPE_1d3IPAdrlR5qGRAIA";
let user_id = "NnAJWxO-KapuWyCm7RGwO5VszZwaJARGit-i3i1mXbkA";
let base = "did:ng:o:8mqfhoSprneBjkAASinRk0OYvFpbiyhjMBVHKQIarDEA:v:dmn9xLARD-LrCz1tdmRiTKelikOCadGEvsLklUrwee4A";
let session = await ng.session_headless_start(user_id);
session_id = session.session_id;
@ -33,38 +36,55 @@ ng.init_headless(config).then( async() => {
let dump = await ng.rdf_dump(session.session_id);
console.log(dump);
let sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?p ?o WHERE { ?s ?p ?o }");
console.log("******** SELECT")
let sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?p ?o WHERE { ?s ?p ?o }", base);
console.log(sparql_result);
for (const q of sparql_result.results.bindings) {
console.log(q);
}
let history = await ng.branch_history(session.session_id);
for (const h of history.history) {
console.log(h[0], h[1]);
}
console.log(history.swimlane_state);
// let history = await ng.branch_history(session.session_id);
// for (const h of history.history) {
// console.log(h[0], h[1]);
// }
// console.log(history.swimlane_state);
//await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:o:8mqfhoSprneBjkAASinRk0OYvFpbiyhjMBVHKQIarDEA> <did:ng:i> <did:ng:j> }");
// await ng.sparql_update(session.session_id, "DELETE DATA { <did:ng:t:AJQ5gCLoXXjalC9diTDCvxxWu5ZQUcYWEE821nhVRMcE> <did:ng:i> <did:ng:j> }");
// await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:t:AJQ5gCLoXXjalC9diTDCvxxWu5ZQUcYWEE821nhVRMcE> <did:ng:i> <did:ng:j> }");
// await ng.sparql_update(session.session_id, "INSERT { ?s <did:ng:i> <did:ng:k> } WHERE { ?s <did:ng:i> <did:ng:j> } ");
// await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:z> <did:ng:j> <did:ng:t:BJQ5gCLoXXjalC9diTDCvxxWu5ZQUcYWEE821nhVRMcE>. <did:ng:t:BJQ5gCLoXXjalC9diTDCvxxWu5ZQUcYWEE821nhVRMcE> <did:ng:m> <did:ng:n> }");
//await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:z> <did:ng:j> [ <did:ng:m> <did:ng:n> ]. }");
//await ng.sparql_update(session.session_id, "INSERT DATA { [ <did:ng:m> <did:ng:n> ] <did:ng:ok> <did:ng:v> . }");
//await ng.sparql_update(session.session_id, "INSERT { ?a <did:ng:ok> <did:ng:v> . } WHERE { ?a <did:ng:m> <did:ng:n> } ");
//await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:z> <did:ng:j> _:1 . _:1 <did:ng:m> <did:ng:n>. }");
//await ng.sparql_update(session.session_id, "INSERT DATA { _:f766ca988268ddc60315ddd5bd621387 <did:ng:o> <did:ng:>. }");
//await ng.sparql_update(session.session_id, "INSERT { _:_ <did:ng:ok> <did:ng:v> . } WHERE { _:_ <did:ng:m> <did:ng:n> } ");
//await ng.sparql_update(session.session_id, "INSERT DATA { _:_ <abc:a> <d:a> . _:_a <abceee:a> <d:a> . }");
sparql_result = await ng.sparql_query(session.session_id, "SELECT ?a WHERE { ?a <did:ng:j> _:abc. _:abc <did:ng:m> <did:ng:n> }");
//await ng.sparql_update(session.session_id, "INSERT DATA { <> <a:self> <a:self> . }",base);
await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:TEST3> <did:ng:j> _:_ . _:_ <did:ng:m> <did:ng:n> . }", base);
await ng.sparql_update(session.session_id, "INSERT DATA { <did:ng:TEST4> <did:ng:j> [ <did:ng:m> <did:ng:n> ]. }", base);
sparql_result = await ng.sparql_query(session.session_id, "SELECT ?a WHERE { ?a <did:ng:j> _:abc. _:abc <did:ng:m> <did:ng:n> }", base);
console.log(sparql_result);
for (const q of sparql_result.results.bindings) {
console.log(q);
}
sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?a WHERE { ?s <did:ng:i> ?a }");
sparql_result = await ng.sparql_query(session.session_id, "SELECT ?s ?a WHERE { ?s <did:ng:j> ?a }", base);
console.log(sparql_result);
for (const q of sparql_result.results.bindings) {
console.log(q);
}
let quads = await ng.sparql_query(session.session_id, "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }");
console.log("******** CONSTRUCT")
let quads = await ng.sparql_query(session.session_id, "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }",base);
for (const q of quads) {
console.log(q.subject.toString(), q.predicate.toString(), q.object.toString(), q.graph.toString())
}

@ -268,6 +268,7 @@ pub async fn session_headless_stop(session_id: JsValue, force_close: bool) -> Re
pub async fn sparql_query(
session_id: JsValue,
sparql: String,
base: JsValue,
nuri: JsValue,
) -> Result<JsValue, JsValue> {
let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
@ -278,10 +279,16 @@ pub async fn sparql_query(
NuriV0::new_entire_user_site()
};
let base_opt = if base.is_string() {
Some(base.as_string().unwrap())
} else {
None
};
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_read_query(),
nuri,
payload: Some(AppRequestPayload::new_sparql_query(sparql)),
payload: Some(AppRequestPayload::new_sparql_query(sparql, base_opt)),
session_id,
});
@ -361,16 +368,22 @@ pub async fn discrete_update(
pub async fn sparql_update(
session_id: JsValue,
sparql: String,
nuri: String,
nuri: JsValue,
) -> Result<(), String> {
let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
.map_err(|_| "Invalid session_id".to_string())?;
let nuri = NuriV0::new_from(&nuri).map_err(|e| e.to_string())?;
let (nuri, base) = if nuri.is_string() {
let n = nuri.as_string().unwrap();
(NuriV0::new_from(&n).map_err(|e| e.to_string())?, Some(n))
} else {
(NuriV0::new_private_store_target(), None)
};
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_write_query(),
nuri,
payload: Some(AppRequestPayload::new_sparql_query(sparql)),
payload: Some(AppRequestPayload::new_sparql_query(sparql, base)),
session_id,
});
@ -389,6 +402,7 @@ pub async fn sparql_update(
pub async fn sparql_query(
session_id: JsValue,
sparql: String,
base: JsValue,
nuri: JsValue,
) -> Result<JsValue, JsValue> {
let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
@ -399,10 +413,16 @@ pub async fn sparql_query(
} else {
NuriV0::new_entire_user_site()
};
let base_opt = if base.is_string() {
Some(base.as_string().unwrap())
} else {
None
};
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_read_query(),
nuri,
payload: Some(AppRequestPayload::new_sparql_query(sparql)),
payload: Some(AppRequestPayload::new_sparql_query(sparql, base_opt)),
session_id,
});
@ -460,13 +480,19 @@ pub async fn rdf_dump(session_id: JsValue) -> Result<String, String> {
}
#[wasm_bindgen]
pub async fn branch_history(session_id: JsValue, nuri: String) -> Result<JsValue, String> {
pub async fn branch_history(session_id: JsValue, nuri: JsValue) -> Result<JsValue, String> {
let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
.map_err(|_| "Invalid session_id".to_string())?;
let nuri = if nuri.is_string() {
NuriV0::new_from(&nuri.as_string().unwrap()).map_err(|e| e.to_string())?
} else {
NuriV0::new_private_store_target()
};
let request = AppRequest::V0(AppRequestV0 {
command: AppRequestCommandV0::new_history(),
nuri: NuriV0::new_from(&nuri).map_err(|e| e.to_string())?,
nuri,
payload: None,
session_id,
});

@ -20,7 +20,9 @@ use yrs::updates::decoder::Decode;
use yrs::{ReadTxn, StateVector, Transact, Update};
use ng_net::app_protocol::*;
use ng_oxigraph::oxrdf::{GraphName, GraphNameRef, NamedNode, Quad, Triple, TripleRef};
use ng_oxigraph::oxrdf::{
BlankNode, GraphName, GraphNameRef, NamedNode, Quad, Subject, Term, Triple, TripleRef,
};
use ng_repo::errors::VerifierError;
use ng_repo::log::*;
use ng_repo::store::Store;
@ -668,21 +670,63 @@ impl Verifier {
&mut self,
nuri: &NuriV0,
query: &String,
base: &Option<String>,
peer_id: Vec<u8>,
) -> Result<(), String> {
let store = self.graph_dataset.as_ref().unwrap();
let update = ng_oxigraph::oxigraph::sparql::Update::parse(query, base.as_deref())
.map_err(|e| e.to_string())?;
let res = store.ng_update(
query,
update,
self.resolve_target_for_sparql(&nuri.target, true)
.map_err(|e| e.to_string())?,
);
match res {
Err(e) => Err(e.to_string()),
Ok((inserts, removes)) => {
Ok((mut inserts, removes)) => {
if inserts.is_empty() && removes.is_empty() {
Ok(())
} else {
self.prepare_sparql_update(Vec::from_iter(inserts), Vec::from_iter(removes))
let mut new_inserts = Vec::with_capacity(inserts.len());
for mut quad in inserts.drain() {
//log_debug!("INSERTING BN {}", quad);
if quad.subject.is_blank_node() {
if base.is_none() {
return Err("Cannot insert blank nodes without a base".to_string());
}
//log_debug!("INSERTING SUBJECT BN {}", quad.subject);
if let Subject::BlankNode(b) = &quad.subject {
let iri = NuriV0::repo_skolem(
base.as_ref().unwrap(),
&peer_id,
b.as_ref().unique_id().unwrap(),
)
.map_err(|e| e.to_string())?;
quad.subject = Subject::NamedNode(NamedNode::new_unchecked(iri));
}
}
if quad.object.is_blank_node() {
if base.is_none() {
return Err("Cannot insert blank nodes without a base".to_string());
}
//log_debug!("INSERTING OBJECT BN {}", quad.object);
if let Term::BlankNode(b) = &quad.object {
let iri = NuriV0::repo_skolem(
base.as_ref().unwrap(),
&peer_id,
b.as_ref().unique_id().unwrap(),
)
.map_err(|e| e.to_string())?;
quad.object = Term::NamedNode(NamedNode::new_unchecked(iri));
}
}
// TODO deal with triples in subject and object (RDF-STAR)
new_inserts.push(quad);
}
self.prepare_sparql_update(new_inserts, Vec::from_iter(removes))
.await
.map_err(|e| e.to_string())
}

@ -273,7 +273,9 @@ impl Verifier {
NuriV0::repo_graph_name(doc_create.store.repo_id(), &overlay_id);
let query = format!("INSERT DATA {{ <{store_nuri_string}> <http://www.w3.org/ns/ldp#contains> <{nuri}>. }}");
let ret = self.process_sparql_update(&store_nuri, &query).await;
let ret = self
.process_sparql_update(&store_nuri, &query, &None, vec![])
.await;
if let Err(e) = ret {
return Ok(AppResponse::error(e));
}
@ -287,19 +289,22 @@ impl Verifier {
}
AppRequestCommandV0::Fetch(fetch) => match fetch {
AppFetchContentV0::ReadQuery => {
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0(
query,
)))) = payload
if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(DocQuery::V0 {
sparql,
base,
}))) = payload
{
//log_debug!("query={}", query);
let store = self.graph_dataset.as_ref().unwrap();
let parsed = Query::parse(&query, None);
let parsed = Query::parse(&sparql, base.as_deref());
if parsed.is_err() {
return Ok(AppResponse::error(parsed.unwrap_err().to_string()));
}
let mut parsed = parsed.unwrap();
let dataset = parsed.dataset_mut();
//log_debug!("DEFAULTS {:?}", dataset.default_graph_graphs());
if dataset.has_no_default_dataset() {
//log_info!("DEFAULT GRAPH AS UNION");
dataset.set_default_graph_as_union();
}
let results = store
@ -323,13 +328,23 @@ impl Verifier {
return Err(NgError::InvalidNuri);
}
return if let Some(AppRequestPayload::V0(AppRequestPayloadV0::Query(
DocQuery::V0(query),
DocQuery::V0 { sparql, base },
))) = payload
{
Ok(match self.process_sparql_update(&nuri, &query).await {
Err(e) => AppResponse::error(e),
Ok(_) => AppResponse::ok(),
})
Ok(
match self
.process_sparql_update(
&nuri,
&sparql,
&base,
self.get_peer_id_for_skolem(),
)
.await
{
Err(e) => AppResponse::error(e),
Ok(_) => AppResponse::ok(),
},
)
} else {
Err(NgError::InvalidPayload)
};

@ -122,6 +122,10 @@ struct EventOutboxStorage {
}
impl Verifier {
pub(crate) fn get_peer_id_for_skolem(&self) -> Vec<u8> {
self.peer_id.to_dh_slice()[0..16].to_vec()
}
pub fn complement_credentials(&self, creds: &mut Credentials) {
creds.private_store = self.private_store_id().clone();
creds.protected_store = self.protected_store_id().clone();
@ -2416,6 +2420,7 @@ impl Verifier {
fn add_repo_(&mut self, repo: Repo) -> &Repo {
//self.populate_topics(&repo);
let _ = self.add_doc(&repo.id, &repo.store.overlay_id);
let repo_ref = self.repos.entry(repo.id).or_insert(repo);
repo_ref
}
@ -2547,7 +2552,15 @@ impl Verifier {
mod test {
use crate::verifier::*;
use ng_oxigraph::oxrdf::BlankNode;
use ng_repo::store::Store;
use std::str::FromStr;
#[test]
pub fn test_blank_node() {
let bn = BlankNode::from_str("_:____").expect("parse");
log_debug!("{:?}", bn);
}
#[async_std::test]
pub async fn test_new_repo_default() {

Loading…
Cancel
Save