import type { ConnectedLdoDataset } from "@ldo/connected"; import ng from "nextgraph"; import type { NextGraphConnectedPlugin, NextGraphResource, NextGraphUri, } from "../src/index.js"; import { createNextGraphLdoDataset } from "../src/createNextGraphLdoDataset.js"; import { parseRdf } from "@ldo/ldo"; import { namedNode } from "@ldo/rdf-utils"; import type { NextGraphReadSuccess } from "../src/results/NextGraphReadSuccess.js"; import { rm, cp } from "fs/promises"; import path from "path"; import { describe, it, expect, beforeEach, afterAll } from "vitest"; const SAMPLE_TTL = `@base . @prefix rdf: . @prefix rdfs: . @prefix foaf: . @prefix rel: . <#green-goblin> rel:enemyOf <#spiderman> ; a foaf:Person ; # in the context of the Marvel universe foaf:name "Green Goblin" . <#spiderman> rel:enemyOf <#green-goblin> ; a foaf:Person ; foaf:name "Spiderman", "Человек-паук"@ru .`; describe("NextGraph Plugin", () => { let nextgraphLdoDataset: ConnectedLdoDataset; beforeEach(async () => { // Generate a wallet const [wallet, mnemonic] = await ng.gen_wallet_for_test( "lL2mo9Jtgz8yWN5PSaEMMftDGXyKJNbv9atQOygmeTcA", ); const openedWallet = await ng.wallet_open_with_mnemonic_words( wallet.wallet, mnemonic, [1, 2, 1, 2], ); const userId = openedWallet.V0.personal_site; const walletName = openedWallet.V0.wallet_id; const session = await ng.session_in_memory_start(walletName, userId); const sessionId = session.session_id; const protectedStoreId = session.protected_store_id.substring(2, 46); const publicStoreId = session.protected_store_id.substring(2, 46); const privateStoreId = session.protected_store_id.substring(2, 46); // Get SessionId for that wallet nextgraphLdoDataset = createNextGraphLdoDataset(); nextgraphLdoDataset.setContext("nextgraph", { ng, sessionId, protectedStoreId, publicStoreId, privateStoreId, }); }); afterAll(async () => { const dataDir = path.resolve(__dirname, "./nextgraph-data"); const backupDir = path.resolve(__dirname, "./nextgraph-data-backup"); // Remove the existing data directory await rm(dataDir, { recursive: true, force: true }); // Copy the entire backup directory to data directory await cp(backupDir, dataDir, { recursive: true }); }); describe("createResource", () => { it("creates a resource by assuming the protected store", async () => { const resource = await nextgraphLdoDataset.createResource("nextgraph"); expect(resource.isError).toBe(false); const resourceAsR = resource as NextGraphResource; expect(resourceAsR.uri).toBeDefined(); expect(resourceAsR.isFetched()).toBe(true); expect(resourceAsR.isPresent()).toBe(true); }); }); describe("read and subscribe", () => { let populatedResourceUri: NextGraphUri; beforeEach(async () => { const resource = (await nextgraphLdoDataset.createResource( "nextgraph", )) as NextGraphResource; await resource.update({ added: await parseRdf(SAMPLE_TTL), }); nextgraphLdoDataset.forgetAllResources(); nextgraphLdoDataset.deleteMatches( undefined, undefined, undefined, undefined, ); populatedResourceUri = resource.uri; }); it("reads a resource that exists", async () => { expect(nextgraphLdoDataset.size).toBe(0); const resource = nextgraphLdoDataset.getResource(populatedResourceUri); const result = await resource.read(); expect(result.isError).toBe(false); expect(result.type).toBe("nextGraphReadSuccess"); expect(resource.isAbsent()).toBe(false); expect(resource.isPresent()).toBe(true); expect(resource.isLoading()).toBe(false); expect(nextgraphLdoDataset.size).toBe(7); expect( nextgraphLdoDataset.match( namedNode("http://example.org/#spiderman"), namedNode("http://www.perceive.net/schemas/relationship/enemyOf"), namedNode("http://example.org/#green-goblin"), namedNode(resource.uri), ).size, ).toBe(1); }); it("reads a resource that is absent", async () => { const nuri = "did:ng:o:W6GCQRfQkNTLtSS_2-QhKPJPkhEtLVh-B5lzpWMjGNEA:v:h8ViqyhCYMS2I6IKwPrY6UZi4ougUm1gpM4QnxlmNMQA"; const resource = nextgraphLdoDataset.getResource(nuri); const readResult = await resource.read(); expect(resource.uri).toBe(nuri); expect(readResult.type).toBe("nextGraphReadSuccess"); expect(nextgraphLdoDataset.size).toBe(0); expect(resource.isLoading()).toBe(false); expect(resource.isAbsent()).toBe(true); }); it("Reads a resource from memory.", async () => { const resource = nextgraphLdoDataset.getResource(populatedResourceUri); await resource.read(); const result2 = await resource.readIfUnfetched(); expect(result2.isError).toBe(false); const result = result2 as NextGraphReadSuccess; expect(result.type).toBe("nextGraphReadSuccess"); expect(result.recalledFromMemory).toBe(true); }); it("Subscribes to a resource", async () => { const resource = nextgraphLdoDataset.getResource(populatedResourceUri); await resource.subscribeToNotifications(); // Wait for subscription await new Promise((resolve) => setTimeout(resolve, 200)); expect(nextgraphLdoDataset.size).toBe(7); expect( nextgraphLdoDataset.match( namedNode("http://example.org/#spiderman"), namedNode("http://www.perceive.net/schemas/relationship/enemyOf"), namedNode("http://example.org/#green-goblin"), namedNode(resource.uri), ).size, ).toBe(1); await resource.unsubscribeFromAllNotifications(); }); }); });