You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
487 lines
15 KiB
487 lines
15 KiB
import type { ISubscribableDataset } from "../src/index.js";
|
|
import { TransactionDataset, createSubscribableDataset } from "../src/index.js";
|
|
import { createDataset } from "@ldo/dataset";
|
|
import {
|
|
namedNode,
|
|
literal,
|
|
quad,
|
|
defaultGraph,
|
|
blankNode,
|
|
} from "@ldo/rdf-utils";
|
|
import type { Quad, BlankNode } from "@rdfjs/types";
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
import testDataset from "@ldo/dataset/test/dataset.testHelper";
|
|
|
|
describe("SubscribableDataset", () => {
|
|
// Regular dataset tests
|
|
testDataset({
|
|
dataset: createSubscribableDataset,
|
|
});
|
|
|
|
// Subscribable Dataset tests
|
|
let subscribableDatastet: ISubscribableDataset<Quad>;
|
|
const tomTypeQuad = quad(
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
|
|
namedNode("http://example.org/cartoons#Cat"),
|
|
);
|
|
const tomNameQuad = quad(
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
namedNode("http://example.org/cartoons#name"),
|
|
literal("Tom"),
|
|
);
|
|
const tomColorQuad = quad(
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
namedNode("http://example.org/cartoons#color"),
|
|
namedNode("http://example.org/colors#grey"),
|
|
);
|
|
const lickyNameQuad = quad(
|
|
namedNode("http://example.org/cartoons#Licky"),
|
|
namedNode("http://example.org/cartoons#name"),
|
|
literal("Licky"),
|
|
);
|
|
const lickyTypeQuad = quad(
|
|
namedNode("http://example.org/cartoons#Licky"),
|
|
namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
|
|
namedNode("http://example.org/cartoons#Cat"),
|
|
);
|
|
|
|
beforeEach(() => {
|
|
subscribableDatastet = createSubscribableDataset([
|
|
tomTypeQuad,
|
|
tomNameQuad,
|
|
]);
|
|
});
|
|
|
|
it("Alerts when a node is added", () => {
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.addListener(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFunc,
|
|
);
|
|
subscribableDatastet.add(tomColorQuad);
|
|
expect(callbackFunc).toBeCalledTimes(1);
|
|
expect(callbackFunc.mock.calls[0][0].added.size).toBe(1);
|
|
expect(callbackFunc.mock.calls[0][0].added.has(tomColorQuad)).toBe(true);
|
|
expect(callbackFunc.mock.calls[0][2]).toEqual([
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
});
|
|
|
|
it("Alerts when a node is removed", () => {
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFunc,
|
|
);
|
|
subscribableDatastet.delete(tomTypeQuad);
|
|
expect(callbackFunc).toBeCalledTimes(1);
|
|
expect(callbackFunc.mock.calls[0][0].removed.size).toBe(1);
|
|
expect(callbackFunc.mock.calls[0][0].removed.has(tomTypeQuad)).toBe(true);
|
|
expect(callbackFunc.mock.calls[0][2]).toEqual([
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
});
|
|
|
|
it("Alerts when multiple quads are added", () => {
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Licky"), null, null, null],
|
|
callbackFunc,
|
|
);
|
|
subscribableDatastet.addAll([lickyNameQuad, lickyTypeQuad]);
|
|
expect(callbackFunc).toBeCalledTimes(1);
|
|
expect(callbackFunc.mock.calls[0][0].added.size).toBe(2);
|
|
expect(callbackFunc.mock.calls[0][0].added.has(lickyNameQuad)).toBe(true);
|
|
expect(callbackFunc.mock.calls[0][0].added.has(lickyTypeQuad)).toBe(true);
|
|
expect(callbackFunc.mock.calls[0][2]).toEqual([
|
|
namedNode("http://example.org/cartoons#Licky"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
});
|
|
|
|
it("Alerts when bulk updated by only adding", () => {
|
|
const callbackFuncLicky = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Licky"), null, null, null],
|
|
callbackFuncLicky,
|
|
);
|
|
subscribableDatastet.bulk({
|
|
added: createDataset([lickyTypeQuad]),
|
|
});
|
|
expect(callbackFuncLicky).toBeCalledTimes(1);
|
|
expect(
|
|
callbackFuncLicky.mock.calls[0][0].added.equals(
|
|
createDataset([lickyTypeQuad]),
|
|
),
|
|
).toBe(true);
|
|
expect(callbackFuncLicky.mock.calls[0][0].removed).toBe(undefined);
|
|
expect(callbackFuncLicky.mock.calls[0][2]).toEqual([
|
|
namedNode("http://example.org/cartoons#Licky"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
});
|
|
|
|
it("Alerts when bulk updated by only removing", () => {
|
|
const callbackFuncTom = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFuncTom,
|
|
);
|
|
subscribableDatastet.bulk({
|
|
removed: createDataset([tomTypeQuad]),
|
|
});
|
|
expect(callbackFuncTom).toBeCalledTimes(1);
|
|
expect(
|
|
callbackFuncTom.mock.calls[0][0].removed.equals(
|
|
createDataset([tomTypeQuad]),
|
|
),
|
|
).toBe(true);
|
|
expect(callbackFuncTom.mock.calls[0][0].added).toBe(undefined);
|
|
expect(callbackFuncTom.mock.calls[0][2]).toEqual([
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
});
|
|
|
|
it("Alerts when emit is called", () => {
|
|
const callbackFuncTom = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFuncTom,
|
|
);
|
|
subscribableDatastet.emit(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
{},
|
|
);
|
|
expect(callbackFuncTom.mock.calls[0][0]).toEqual({});
|
|
});
|
|
|
|
it("Alerts when bulk updated", () => {
|
|
const callbackFuncLicky = jest.fn();
|
|
const callbackFuncTom = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFuncTom,
|
|
);
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Licky"), null, null, null],
|
|
callbackFuncLicky,
|
|
);
|
|
subscribableDatastet.bulk({
|
|
added: createDataset([lickyTypeQuad]),
|
|
removed: createDataset([tomTypeQuad]),
|
|
});
|
|
expect(callbackFuncLicky).toBeCalledTimes(1);
|
|
expect(callbackFuncTom).toBeCalledTimes(1);
|
|
expect(
|
|
callbackFuncLicky.mock.calls[0][0].added.equals(
|
|
createDataset([lickyTypeQuad]),
|
|
),
|
|
).toBe(true);
|
|
expect(callbackFuncLicky.mock.calls[0][0].removed).toBe(undefined);
|
|
expect(
|
|
callbackFuncTom.mock.calls[0][0].removed.equals(
|
|
createDataset([tomTypeQuad]),
|
|
),
|
|
).toBe(true);
|
|
expect(callbackFuncTom.mock.calls[0][0].added).toBe(undefined);
|
|
});
|
|
|
|
it("Alerts when the default graph is updated but not when another graph is", () => {
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.on([null, null, null, defaultGraph()], callbackFunc);
|
|
subscribableDatastet.add(lickyNameQuad);
|
|
subscribableDatastet.add(
|
|
quad(
|
|
namedNode("https://example.com/books#Dumbledoor"),
|
|
namedNode("http://example.org/books#name"),
|
|
literal("Dubmledoor"),
|
|
namedNode("https://coolgraphs.com"),
|
|
),
|
|
);
|
|
expect(callbackFunc).toHaveBeenCalledTimes(1);
|
|
expect(
|
|
callbackFunc.mock.calls[0][0].added.equals(
|
|
createDataset([lickyNameQuad]),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("Alerts when a named graph is updated", () => {
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.on(
|
|
[null, null, null, namedNode("https://coolgraphs.com")],
|
|
callbackFunc,
|
|
);
|
|
const quadWithGraph = quad(
|
|
namedNode("https://example.com/books#Dumbledoor"),
|
|
namedNode("http://example.org/books#name"),
|
|
literal("Dubmledoor"),
|
|
namedNode("https://coolgraphs.com"),
|
|
);
|
|
subscribableDatastet.add(quadWithGraph);
|
|
expect(callbackFunc).toHaveBeenCalledTimes(1);
|
|
expect(
|
|
callbackFunc.mock.calls[0][0].added.equals(
|
|
createDataset([quadWithGraph]),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("Alerts when one blank node is updated, but not the other", () => {
|
|
const blankNodeQuadA = quad(
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
namedNode("http://example.org/cartoons#Address"),
|
|
blankNode(),
|
|
);
|
|
const blankNodeQuadB = quad(
|
|
namedNode("http://example.org/cartoons#Licky"),
|
|
namedNode("http://example.org/cartoons#Address"),
|
|
blankNode(),
|
|
);
|
|
subscribableDatastet.addAll([blankNodeQuadA, blankNodeQuadB]);
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.on(
|
|
[blankNodeQuadA.object as BlankNode, null, null, null],
|
|
callbackFunc,
|
|
);
|
|
const blankNodeAdditionA = quad(
|
|
blankNodeQuadA.object as BlankNode,
|
|
namedNode("http://example.org/cartoons#StreetNumber"),
|
|
literal("1234"),
|
|
);
|
|
subscribableDatastet.add(blankNodeAdditionA);
|
|
const blankNodeAdditionB = quad(
|
|
blankNodeQuadB.object as BlankNode,
|
|
namedNode("http://example.org/cartoons#StreetNumber"),
|
|
literal("65"),
|
|
);
|
|
subscribableDatastet.add(blankNodeAdditionB);
|
|
expect(callbackFunc).toBeCalledTimes(1);
|
|
expect(
|
|
callbackFunc.mock.calls[0][0].added.equals(
|
|
createDataset([blankNodeAdditionA]),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("Provides event names", () => {
|
|
const sampleBlankNode = blankNode();
|
|
subscribableDatastet.on(
|
|
[namedNode("https://example.com"), null, null, null],
|
|
() => {
|
|
/* Do nothing */
|
|
},
|
|
);
|
|
subscribableDatastet.on([null, null, sampleBlankNode, null], () => {
|
|
/* Do nothing */
|
|
});
|
|
subscribableDatastet.on([null, null, null, defaultGraph()], () => {
|
|
/* Do nothing */
|
|
});
|
|
const subscribableTerms = subscribableDatastet.eventNames();
|
|
expect(subscribableTerms.length).toBe(3);
|
|
expect(
|
|
subscribableTerms.some(
|
|
(curQuadMatch) =>
|
|
curQuadMatch[0]?.equals(namedNode("https://example.com")),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
subscribableTerms.some(
|
|
(curQuadMatch) => curQuadMatch[2]?.equals(sampleBlankNode),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
subscribableTerms.some((curQuadMatch) => {
|
|
return curQuadMatch[3]?.equals(defaultGraph());
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("Throws an error if somehow a bad key is registered to an event emitter", () => {
|
|
// Disable trypscript to set up a private variable you shouldn't be able to access
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
subscribableDatastet.eventEmitter.on("Blah Blah Blah", () => {
|
|
/* Do Nothing */
|
|
});
|
|
expect(() => subscribableDatastet.eventNames()).toThrowError(
|
|
"Invalid Quad Match String",
|
|
);
|
|
});
|
|
|
|
it("Gets the max listeners", () => {
|
|
expect(subscribableDatastet.getMaxListeners()).toBe(10);
|
|
});
|
|
|
|
it("Gets the current Listeners for a specific name", () => {
|
|
const dummyListener1 = () => {
|
|
/* Do Nothing */
|
|
};
|
|
const dummyListener2 = () => {
|
|
/* Do Nothing */
|
|
};
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
dummyListener1,
|
|
);
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Licky"), null, null, null],
|
|
dummyListener2,
|
|
);
|
|
const listeners = subscribableDatastet.listeners([
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
expect(listeners.length).toBe(1);
|
|
expect(listeners[0]).toBe(dummyListener1);
|
|
});
|
|
|
|
it("Unsubscribes from a listener", () => {
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFunc,
|
|
);
|
|
subscribableDatastet.off(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFunc,
|
|
);
|
|
subscribableDatastet.add(tomColorQuad);
|
|
expect(callbackFunc).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it("Unsubscribes from all events for a particular listener", () => {
|
|
const callbackFunc = jest.fn();
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
callbackFunc,
|
|
);
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Licky"), null, null, null],
|
|
callbackFunc,
|
|
);
|
|
subscribableDatastet.removeListenerFromAllEvents(callbackFunc);
|
|
subscribableDatastet.add(tomColorQuad);
|
|
subscribableDatastet.add(lickyNameQuad);
|
|
expect(callbackFunc).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it("Runs 'once' without erroring", () => {
|
|
expect(
|
|
subscribableDatastet.once(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
() => {
|
|
/* Do Nothing */
|
|
},
|
|
),
|
|
).toBe(subscribableDatastet);
|
|
});
|
|
|
|
it("Runs 'prependListener' without erroring", () => {
|
|
expect(
|
|
subscribableDatastet.prependListener(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
() => {
|
|
/* Do Nothing */
|
|
},
|
|
),
|
|
).toBe(subscribableDatastet);
|
|
});
|
|
|
|
it("Runs the 'prependOnceListener' without erroring", () => {
|
|
expect(
|
|
subscribableDatastet.prependOnceListener(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
() => {
|
|
/* Do Nothing */
|
|
},
|
|
),
|
|
).toBe(subscribableDatastet);
|
|
});
|
|
|
|
it("Removes all listeners", () => {
|
|
const dummyListener1 = () => {
|
|
/* Do Nothing */
|
|
};
|
|
const dummyListener2 = () => {
|
|
/* Do Nothing */
|
|
};
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
dummyListener1,
|
|
);
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Licky"), null, null, null],
|
|
dummyListener2,
|
|
);
|
|
subscribableDatastet.removeAllListeners([
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
expect(
|
|
subscribableDatastet.listenerCount([
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
null,
|
|
null,
|
|
null,
|
|
]),
|
|
).toBe(0);
|
|
expect(
|
|
subscribableDatastet.listenerCount([
|
|
namedNode("http://example.org/cartoons#Licky"),
|
|
null,
|
|
null,
|
|
null,
|
|
]),
|
|
).toBe(1);
|
|
});
|
|
|
|
it("Sets max listeners", () => {
|
|
subscribableDatastet.setMaxListeners(20);
|
|
expect(subscribableDatastet.getMaxListeners()).toBe(20);
|
|
});
|
|
|
|
it("Returns raw listeners", () => {
|
|
const dummyListener1 = () => {
|
|
/* Do Nothing */
|
|
};
|
|
subscribableDatastet.on(
|
|
[namedNode("http://example.org/cartoons#Tom"), null, null, null],
|
|
dummyListener1,
|
|
);
|
|
const rawListeners = subscribableDatastet.rawListeners([
|
|
namedNode("http://example.org/cartoons#Tom"),
|
|
null,
|
|
null,
|
|
null,
|
|
]);
|
|
expect(rawListeners.length).toBe(1);
|
|
expect(rawListeners[0]).toBe(dummyListener1);
|
|
});
|
|
|
|
it("Returns a transaction", () => {
|
|
expect(
|
|
subscribableDatastet.startTransaction() instanceof TransactionDataset,
|
|
).toBe(true);
|
|
});
|
|
});
|
|
|