From 63f49d2260c7d9e7754a56ae66cbf36b820f8272 Mon Sep 17 00:00:00 2001
From: Niko PLP <niko@nextgraph.org>
Date: Tue, 4 Mar 2025 05:32:17 +0200
Subject: [PATCH] JS SDK: doc_subscribe

---
 ng-sdk-js/app-node/index.js | 102 ++++++++++++++++++++++++------------
 ng-sdk-js/prepare-node.js   |   2 +-
 ng-sdk-js/src/lib.rs        |  13 +++++
 3 files changed, 83 insertions(+), 34 deletions(-)

diff --git a/ng-sdk-js/app-node/index.js b/ng-sdk-js/app-node/index.js
index b5833f5..73e21d5 100644
--- a/ng-sdk-js/app-node/index.js
+++ b/ng-sdk-js/app-node/index.js
@@ -58,8 +58,8 @@ ng.wallet_read_file(buffer).then(async (wallet)=>{
 
         console.log(connection_status);
 
-        let dump = await ng.rdf_dump(session_id);
         console.log("==== DUMP ====");
+        let dump = await ng.rdf_dump(session_id);
         console.log(dump);
         console.log("==== END of DUMP ====");
 
@@ -71,53 +71,89 @@ ng.wallet_read_file(buffer).then(async (wallet)=>{
         let base = nuri.substring(0,53);
         console.log("base=",base);
 
-        await ng.sparql_update(session_id, "INSERT DATA { <> <example:predicate> \"An example value1000\". }", nuri );
+        // EXAMPLE OF SUBSCRIBING TO A DOCUMENT. base is the Nuri half first part (the document ID proper).
+
+        //call unsub when you are done subscribing you don't want to receive updates anymore
+        let unsub = await ng.doc_subscribe(base, session_id,
+            async (response) => {
+
+                if (response.V0.State?.graph) {
+                    
+                    let json_str = new TextDecoder().decode(response.V0.State.graph.triples);
+                    triples = JSON.parse(json_str);
+                
+                    for (const triple of triples){
+                        // deal with each triple
+                        console.log("STATE",triple);
+                    }
+                    
+                } else if (response.V0.Patch?.graph) {
+                    
+                    let inserts_json_str = new TextDecoder().decode(response.V0.Patch.graph.inserts);
+                    let inserts = JSON.parse(inserts_json_str);
+                    let removes_json_str = new TextDecoder().decode(response.V0.Patch.graph.removes);
+                    let removes = JSON.parse(removes_json_str);
+
+                    for (const insert of inserts){
+                        // deal with each insert
+                        console.log("INSERT",insert);
+                    }
+                    for (const remove of removes){
+                        // deal with each remove
+                        console.log("REMOVE",remove);
+                    }
+                    
+                }
+            }
+        );
+
+        //await ng.sparql_update(session_id, "INSERT DATA { <> <example:predicate> \"An example value1000\". }", nuri );
 
         // SELECT
         // we use base to replace <> in the subject
 
-        let sparql_result = await ng.sparql_query(session_id, "SELECT ?p ?o ?g WHERE { GRAPH ?g { <> ?p ?o } }", base);
-        console.log(sparql_result);
-        for (const q of sparql_result.results.bindings) {
-            console.log(q);
-        }
+        // let sparql_result = await ng.sparql_query(session_id, "SELECT ?p ?o ?g WHERE { GRAPH ?g { <> ?p ?o } }", base);
+        // console.log(sparql_result);
+        // for (const q of sparql_result.results.bindings) {
+        //     console.log(q);
+        // }
 
-        // specifying a nuri in the query arguments, is equivalent to settings the GRAPH in the WHERE
-        sparql_result = await ng.sparql_query(session_id, "SELECT ?s ?p ?o WHERE { ?s ?p ?o }", undefined, nuri);
-        console.log(sparql_result);
-        for (const q of sparql_result.results.bindings) {
-            console.log(q);
-        }
+        // // specifying a nuri in the query arguments, is equivalent to settings the GRAPH in the WHERE
+        // sparql_result = await ng.sparql_query(session_id, "SELECT ?s ?p ?o WHERE { ?s ?p ?o }", undefined, nuri);
+        // console.log(sparql_result);
+        // for (const q of sparql_result.results.bindings) {
+        //     console.log(q);
+        // }
 
-        // base can be omitted if it isn't used
+        // // base can be omitted if it isn't used
 
-        sparql_result = await ng.sparql_query(session_id, "SELECT ?s ?p ?o ?g WHERE { GRAPH ?g { ?s ?p ?o } }");
-        console.log(sparql_result);
-        for (const q of sparql_result.results.bindings) {
-            console.log(q);
-        }
+        // sparql_result = await ng.sparql_query(session_id, "SELECT ?s ?p ?o ?g WHERE { GRAPH ?g { ?s ?p ?o } }");
+        // console.log(sparql_result);
+        // for (const q of sparql_result.results.bindings) {
+        //     console.log(q);
+        // }
 
-        // CONSTRUCT
+        // // CONSTRUCT
 
-        let triples = await ng.sparql_query(session_id, `CONSTRUCT { ?s ?p ?o } WHERE { GRAPH <${nuri}> { ?s ?p ?o } }`, base);
-        for (const q of triples) {
-            console.log(q.subject.toString(), q.predicate.toString(), q.object.toString())
-        }
+        // let triples = await ng.sparql_query(session_id, `CONSTRUCT { ?s ?p ?o } WHERE { GRAPH <${nuri}> { ?s ?p ?o } }`, base);
+        // for (const q of triples) {
+        //     console.log(q.subject.toString(), q.predicate.toString(), q.object.toString())
+        // }
 
-        // is equivalent to 
+        // // is equivalent to 
 
-        triples = await ng.sparql_query(session_id, "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }", base, nuri);
-        for (const q of triples) {
-            console.log(q.subject.toString(), q.predicate.toString(), q.object.toString())
-        }
+        // triples = await ng.sparql_query(session_id, "CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }", base, nuri);
+        // for (const q of triples) {
+        //     console.log(q.subject.toString(), q.predicate.toString(), q.object.toString())
+        // }
 
-        // cleaning up
+        // // cleaning up
 
-        await ng.user_disconnect(user_id_string);
+        // await ng.user_disconnect(user_id_string);
 
-        await ng.session_stop(user_id_string);
+        // await ng.session_stop(user_id_string);
 
-        await ng.wallet_close(wallet_name);
+        // await ng.wallet_close(wallet_name);
 
         console.log("the end");
     } catch (e) {
diff --git a/ng-sdk-js/prepare-node.js b/ng-sdk-js/prepare-node.js
index 17158a3..47b9eb7 100644
--- a/ng-sdk-js/prepare-node.js
+++ b/ng-sdk-js/prepare-node.js
@@ -6,7 +6,7 @@ const PATH_README = './pkg-node/README.md';
 const pkg_json = fs.readFileSync(PATH);
 let pkg = JSON.parse(pkg_json)
 pkg.name = "nextgraph";
-pkg.version = "0.1.1-alpha.1";
+pkg.version = "0.1.1-alpha.3";
 pkg.description = "nodeJS SDK of NextGraph";
 pkg.files.push("ng_sdk_js_bg.wasm.d.ts");
 pkg.files.push("snippets/**/*.js");
diff --git a/ng-sdk-js/src/lib.rs b/ng-sdk-js/src/lib.rs
index 2427504..d746660 100644
--- a/ng-sdk-js/src/lib.rs
+++ b/ng-sdk-js/src/lib.rs
@@ -1688,6 +1688,19 @@ pub async fn doc_fetch_repo_subscribe(repo_o: String) -> Result<JsValue, String>
     .unwrap())
 }
 
+#[wasm_bindgen]
+pub async fn doc_subscribe(
+    repo_o: String,
+    session_id: JsValue,
+    callback: &js_sys::Function,
+) -> Result<JsValue, String> {
+    let session_id: u64 = serde_wasm_bindgen::from_value::<u64>(session_id)
+        .map_err(|_| "Deserialization error of session_id".to_string())?;
+    let mut request = AppRequest::doc_fetch_repo_subscribe(repo_o).map_err(|e| e.to_string())?;
+    request.set_session_id(session_id);
+    app_request_stream_(request, callback).await
+}
+
 // // #[wasm_bindgen]
 // pub async fn get_readcap() -> Result<JsValue, String> {
 //     let request = ObjectRef::nil();