Completed preliminary nextgraph tests

main
Jackson Morgan 5 months ago
parent 998718375b
commit 9559bb2b39
  1. 86
      packages/connected-nextgraph/src/resources/NextGraphResource.ts
  2. 21
      packages/connected-nextgraph/test/integration.test.ts

@ -16,10 +16,13 @@ import type { NextGraphConnectedPlugin } from "../NextGraphConnectedPlugin";
import ng from "nextgraph"; import ng from "nextgraph";
import { changesToSparqlUpdate, type DatasetChanges } from "@ldo/rdf-utils"; import { changesToSparqlUpdate, type DatasetChanges } from "@ldo/rdf-utils";
import type { NextGraphNotificationMessage } from "../notifications/NextGraphNotificationMessage"; import type { NextGraphNotificationMessage } from "../notifications/NextGraphNotificationMessage";
import type { Quad } from "@rdfjs/types"; import type { Dataset, Quad } from "@rdfjs/types";
import { namedNode, quad as createQuad } from "@rdfjs/data-model"; import { namedNode, quad as createQuad } from "@rdfjs/data-model";
import { NextGraphReadSuccess } from "../results/NextGraphReadSuccess"; import { NextGraphReadSuccess } from "../results/NextGraphReadSuccess";
import { NextGraphNotificationSubscription } from "../notifications/NextGraphNotificationSubscription"; import { NextGraphNotificationSubscription } from "../notifications/NextGraphNotificationSubscription";
import { parseRdf } from "@ldo/ldo";
import type { LdoDataset } from "packages/ldo/dist/LdoDataset";
import { createDataset } from "@ldo/dataset";
export class NextGraphResource export class NextGraphResource
extends (EventEmitter as new () => ResourceEventEmitter) extends (EventEmitter as new () => ResourceEventEmitter)
@ -97,6 +100,22 @@ export class NextGraphResource
return error; return error;
} }
private overwriteQuads(quads: Quad[] | Dataset<Quad>) {
const dataset = this.context.dataset;
const graphNode = namedNode(this.uri);
dataset.deleteMatches(undefined, undefined, undefined, graphNode);
dataset.addAll(
quads.map((ngQuad) => {
return createQuad(
ngQuad.subject,
ngQuad.predicate,
ngQuad.object,
graphNode,
);
}),
);
}
async read(): Promise< async read(): Promise<
NextGraphReadSuccess | UnexpectedResourceError<NextGraphResource> NextGraphReadSuccess | UnexpectedResourceError<NextGraphResource>
> { > {
@ -112,19 +131,7 @@ export class NextGraphResource
this.uri, this.uri,
); );
// Update the dataset // Update the dataset
const graphNode = namedNode(this.uri); this.overwriteQuads(sparqlResult);
const dataset = this.context.dataset;
dataset.deleteMatches(undefined, undefined, undefined, graphNode);
dataset.addAll(
sparqlResult.map((ngQuad) => {
return createQuad(
ngQuad.subject,
ngQuad.predicate,
ngQuad.object,
graphNode,
);
}),
);
// Update statuses // Update statuses
const result = new NextGraphReadSuccess(this, false); const result = new NextGraphReadSuccess(this, false);
@ -187,35 +194,50 @@ export class NextGraphResource
} }
} }
private async notificationToQuads(
notificationString: string,
): Promise<Dataset<Quad>> {
const rawTriples = JSON.parse(notificationString);
const triples = (
await Promise.all<LdoDataset>(
rawTriples.map(async (rawTriple) =>
parseRdf(`${rawTriple}.`, { baseIRI: this.uri }),
),
)
).reduce((agg, ldoDataset) => {
ldoDataset.forEach((quad) => {
agg.add(quad);
});
return agg;
}, createDataset());
return triples;
}
protected async onNotification(response: NextGraphNotificationMessage) { protected async onNotification(response: NextGraphNotificationMessage) {
if (response.V0.State?.graph) { if (response.V0.State?.graph) {
const json_str = new TextDecoder().decode( const json_str = new TextDecoder().decode(
response.V0.State.graph.triples, response.V0.State.graph.triples,
); );
const triples = JSON.parse(json_str); const triples = await this.notificationToQuads(json_str);
this.overwriteQuads(triples);
for (const triple of triples) {
// deal with each triple
console.log("STATE", triple);
}
} else if (response.V0.Patch?.graph) { } else if (response.V0.Patch?.graph) {
const inserts_json_str = new TextDecoder().decode( const insertsString = new TextDecoder().decode(
response.V0.Patch.graph.inserts, response.V0.Patch.graph.inserts,
); );
const inserts = JSON.parse(inserts_json_str); const removesString = new TextDecoder().decode(
const removes_json_str = new TextDecoder().decode(
response.V0.Patch.graph.removes, response.V0.Patch.graph.removes,
); );
const removes = JSON.parse(removes_json_str);
for (const insert of inserts) { const [added, removed] = await Promise.all(
// deal with each insert [insertsString, removesString].map(async (str) => {
console.log("INSERT", insert); return this.notificationToQuads(str);
} }),
for (const remove of removes) { );
// deal with each remove
console.log("REMOVE", remove); this.context.dataset.bulk({
} added,
removed,
});
} }
} }

@ -9,7 +9,7 @@ import { createNextGraphLdoDataset } from "../src/createNextGraphLdoDataset";
import { parseRdf } from "@ldo/ldo"; import { parseRdf } from "@ldo/ldo";
import { namedNode } from "@rdfjs/data-model"; import { namedNode } from "@rdfjs/data-model";
import type { NextGraphReadSuccess } from "../src/results/NextGraphReadSuccess"; import type { NextGraphReadSuccess } from "../src/results/NextGraphReadSuccess";
import { rm, mkdir, cp, readdir } from "fs/promises"; import { rm, cp } from "fs/promises";
import path from "path"; import path from "path";
const SAMPLE_TTL = `@base <http://example.org/> . const SAMPLE_TTL = `@base <http://example.org/> .
@ -79,7 +79,7 @@ describe("NextGraph Plugin", () => {
}); });
}); });
describe("readResource", () => { describe("read and subscribe", () => {
let populatedResourceUri: NextGraphUri; let populatedResourceUri: NextGraphUri;
beforeEach(async () => { beforeEach(async () => {
const resource = (await nextgraphLdoDataset.createResource( const resource = (await nextgraphLdoDataset.createResource(
@ -139,5 +139,22 @@ describe("NextGraph Plugin", () => {
expect(result.type).toBe("nextGraphReadSuccess"); expect(result.type).toBe("nextGraphReadSuccess");
expect(result.recalledFromMemory).toBe(true); 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();
});
}); });
}); });

Loading…
Cancel
Save