Completed tests other than language

main
Jackson Morgan 6 months ago
parent 94dae83c4a
commit 503e69687a
  1. 2
      packages/jsonld-dataset-proxy/package.json
  2. 8
      packages/jsonld-dataset-proxy/src/graphOf.ts
  3. 22
      packages/jsonld-dataset-proxy/src/setProxy/ObjectSetProxy.ts
  4. 42
      packages/jsonld-dataset-proxy/src/setProxy/SetProxy.ts
  5. 54
      packages/jsonld-dataset-proxy/src/setProxy/SubjectSetProxy.ts
  6. 39
      packages/jsonld-dataset-proxy/src/setProxy/WildcardObjectSetProxy.ts
  7. 11
      packages/jsonld-dataset-proxy/src/setProxy/WildcardSubjectSetProxy.ts
  8. 16
      packages/jsonld-dataset-proxy/src/setProxy/ldSet/BasicLdSet.ts
  9. 3
      packages/jsonld-dataset-proxy/src/util/addObjectToDataset.ts
  10. 235
      packages/jsonld-dataset-proxy/test/jsonldDatasetProxy.test.ts

@ -6,7 +6,7 @@
"scripts": {
"build": "tsc --project tsconfig.build.json",
"build:watch": "tsc-watch",
"test": "jest --coverage",
"test": "NODE_NO_WARNINGS=1 jest --coverage",
"prepublishOnly": "npm run test && npm run build",
"start": "ts-node ./example/example.ts",
"start:lang": "ts-node ./example/languageExample.ts",

@ -9,6 +9,7 @@ import {
_proxyContext,
} from "./types";
import type { LdSet } from "./setProxy/ldSet/LdSet";
import { getNodeFromRawValue } from "./util/getNodeFromRaw";
/**
* Returns the graph for which a defined triple is a member
@ -36,8 +37,11 @@ export function graphOf<Subject extends ObjectLike, Key extends keyof Subject>(
if (object == null) {
objectNode = null;
} else {
const objectProxy = getSubjectProxyFromObject(object);
objectNode = objectProxy[_getUnderlyingNode];
const datatype = proxyContext.contextUtil.getDataType(
predicate as string,
proxyContext.getRdfType(subjectNode),
);
objectNode = getNodeFromRawValue(object, proxyContext, datatype) ?? null;
}
const quads = subjectProxy[_getUnderlyingDataset].match(
subjectNode,

@ -38,4 +38,26 @@ export class ObjectSetProxy<
);
return this;
}
/**
* Clears the set of all values
*/
clear(): void {
for (const value of this) {
this.delete(value);
}
}
/**
* Deletes an item for the set
* @param value the item to delete
* @returns true if the item was present before deletion
*/
delete(value: T): boolean {
const { dataset } = this.context;
const { subject, predicate, object, graph } = this.getSPOG(value);
const didDelete = dataset.match(subject, predicate, object, graph).size > 0;
dataset.deleteMatches(subject, predicate, object, graph);
return didDelete;
}
}

@ -43,10 +43,11 @@ export abstract class SetProxy<
/**
* Gets the subject, predicate and object for this set
*/
protected abstract getSPO(value?: T): {
protected abstract getSPOG(value?: T): {
subject?: SubjectNode;
predicate?: PredicateNode;
object?: ObjectNode;
graph?: GraphNode;
};
protected abstract getNodeOfFocus(quad: Quad): SubjectNode | ObjectNode;
@ -62,29 +63,38 @@ export abstract class SetProxy<
return this;
}
/**
* The clear method on an abstract set does nothing.
* @deprecated You cannot clear data from an abstract set as it is simply a proxy to an underlying dataset
*/
clear(): void {
for (const value of this) {
this.delete(value);
}
console.warn(
'You\'ve attempted to call "clear" on an abstract set. You cannot clear data from an abstract set as it is simply a proxy to an underlying dataset',
);
return;
}
delete(value: T): boolean {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO(value);
dataset.deleteMatches(subject, predicate, object);
return true;
/**
* The delete method on an abstract set does nothing.
* @deprecated You cannot delete data from an abstract set as it is simply a proxy to an underlying dataset
*/
delete(_value: T): boolean {
console.warn(
'You\'ve attempted to call "clear" on an abstract set. You cannot delete data from an abstract set as it is simply a proxy to an underlying dataset',
);
return false;
}
has(value: T): boolean {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO(value);
return dataset.match(subject, predicate, object).size > 0;
const { subject, predicate, object, graph } = this.getSPOG(value);
return dataset.match(subject, predicate, object, graph).size > 0;
}
get size() {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO();
return dataset.match(subject, predicate, object).size;
const { subject, predicate, object, graph } = this.getSPOG();
return dataset.match(subject, predicate, object, graph).size;
}
entries(): IterableIterator<[T, T]> {
@ -105,8 +115,8 @@ export abstract class SetProxy<
[Symbol.iterator](): IterableIterator<T> {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO();
const quads = dataset.match(subject, predicate, object);
const { subject, predicate, object, graph } = this.getSPOG();
const quads = dataset.match(subject, predicate, object, graph);
const collection: T[] = quads.toArray().map((quad) => {
const quadSubject = this.getNodeOfFocus(quad);
return nodeToJsonldRepresentation(quadSubject, this.context) as T;
@ -138,4 +148,6 @@ export abstract class SetProxy<
get [_writeGraphs](): GraphNode[] {
return this.context.writeGraphs;
}
abstract get [_isSubjectOriented](): boolean;
}

@ -1,10 +1,21 @@
import type { GraphNode, ObjectNode, PredicateNode } from "@ldo/rdf-utils";
import {
type GraphNode,
type ObjectNode,
type PredicateNode,
} from "@ldo/rdf-utils";
import type { RawObject } from "../util/RawObject";
import { addObjectToDataset } from "../util/addObjectToDataset";
import type { ProxyContext } from "../ProxyContext";
import { WildcardSubjectSetProxy } from "./WildcardSubjectSetProxy";
import { _getUnderlyingNode } from "../types";
import { quad } from "@rdfjs/data-model";
import { defaultGraph, quad } from "@rdfjs/data-model";
import {
createTransactionDatasetFactory,
TransactionDataset,
} from "@ldo/subscribable-dataset";
import { createDatasetFactory } from "@ldo/dataset";
import { getNodeFromRawObject } from "../util/getNodeFromRaw";
import { nodeToString } from "../util/NodeSet";
export type SubjectSetProxyQuadMatch = [
undefined | null,
@ -27,6 +38,45 @@ export class SubjectSetProxy<
* Appends a new element with a specified value to the end of the Set.
*/
add(value: T): this {
// Undefined is fine no matter what
if (value === undefined) {
return this;
}
if (typeof value !== "object") {
throw new Error(
`Cannot add a literal "${value}"(${typeof value}) to a subject-oriented collection.`,
);
}
// Create a test dataset to see if the inputted data is valid
const testDataset = new TransactionDataset(
this.context.dataset,
createDatasetFactory(),
createTransactionDatasetFactory(),
);
addObjectToDataset(
value,
false,
this.context.duplicate({
writeGraphs: [defaultGraph()],
}),
);
const isValidAddition =
testDataset.match(
getNodeFromRawObject(value, this.context.contextUtil),
this.quadMatch[1],
this.quadMatch[2],
).size !== 0;
if (!isValidAddition) {
throw new Error(
`Cannot add value to collection. This must contain a quad that matches (${nodeToString(
this.quadMatch[0],
)}, ${nodeToString(this.quadMatch[1])}, ${nodeToString(
this.quadMatch[2],
)}, ${nodeToString(this.quadMatch[3])})`,
);
}
// Add the object if everything's okay
const added = addObjectToDataset(value as RawObject, false, this.context);
const addedNode = added[_getUnderlyingNode];
this.context.writeGraphs.forEach((graph) => {

@ -9,6 +9,7 @@ import type { RawValue } from "../util/RawObject";
import { SetProxy } from "./SetProxy";
import type { ProxyContext } from "../ProxyContext";
import { getNodeFromRawValue } from "../util/getNodeFromRaw";
import { _isSubjectOriented } from "../types";
export type WildcardObjectSetProxyQuadMatch = [
SubjectNode | undefined | null,
@ -35,14 +36,16 @@ export class WildcardObjectSetProxy<
this.quadMatch = quadMatch;
}
protected getSPO(value?: T | undefined): {
protected getSPOG(value?: T | undefined): {
subject?: SubjectNode;
predicate?: PredicateNode;
object?: ObjectNode;
graph?: GraphNode;
} {
// Get the RDF Node that represents the value, skip is no value
const subject = this.quadMatch[0] ?? undefined;
const predicate = this.quadMatch[1] ?? undefined;
const graph = this.quadMatch[3] ?? undefined;
if (value) {
// Get datatype if applicable
let datatype: string | undefined = undefined;
@ -56,6 +59,7 @@ export class WildcardObjectSetProxy<
subject,
predicate,
object: valueNode,
graph,
};
}
// SPO for no value
@ -63,6 +67,7 @@ export class WildcardObjectSetProxy<
subject,
predicate,
object: undefined,
graph,
};
}
@ -73,11 +78,17 @@ export class WildcardObjectSetProxy<
private manuallyMatchWithUnknownObjectNode(
subject: SubjectNode | undefined,
predicate: PredicateNode | undefined,
graph: GraphNode | undefined,
value: T,
): Dataset<Quad, Quad> {
// If there's not an object, that means that we don't know the object node
// and need to find it manually.
const matchingQuads = this.context.dataset.match(subject, predicate, null);
const matchingQuads = this.context.dataset.match(
subject,
predicate,
null,
graph,
);
return matchingQuads.filter(
(quad) =>
quad.object.termType === "Literal" && quad.object.value === value,
@ -86,32 +97,42 @@ export class WildcardObjectSetProxy<
delete(value: T): boolean {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO(value);
const { subject, predicate, object, graph } = this.getSPOG(value);
if (!object) {
const matchedQuads = this.manuallyMatchWithUnknownObjectNode(
subject,
predicate,
graph,
value,
);
matchedQuads.forEach((quad) => dataset.delete(quad));
return matchedQuads.size > 0;
} else {
const willDelete = dataset.match(subject, predicate, object).size > 0;
dataset.deleteMatches(subject, predicate, object);
const willDelete =
dataset.match(subject, predicate, object, graph).size > 0;
dataset.deleteMatches(subject, predicate, object, graph);
return willDelete;
}
}
has(value: T): boolean {
const { dataset } = this.context;
const { subject, predicate, object } = this.getSPO(value);
const { subject, predicate, object, graph } = this.getSPOG(value);
if (!object) {
return (
this.manuallyMatchWithUnknownObjectNode(subject, predicate, value)
.size > 0
this.manuallyMatchWithUnknownObjectNode(
subject,
predicate,
graph,
value,
).size > 0
);
} else {
return dataset.match(subject, predicate, object).size > 0;
return dataset.match(subject, predicate, object, graph).size > 0;
}
}
get [_isSubjectOriented](): false {
return false;
}
}

@ -9,6 +9,7 @@ import type { RawObject } from "../util/RawObject";
import { SetProxy } from "./SetProxy";
import type { ProxyContext } from "../ProxyContext";
import { getNodeFromRawObject } from "../util/getNodeFromRaw";
import { _isSubjectOriented } from "../types";
export type WildcardSubjectSetProxyQuadMatch = [
undefined | null,
@ -33,20 +34,23 @@ export class WildcardSubjectSetProxy<T extends RawObject> extends SetProxy<T> {
this.quadMatch = quadMatch;
}
protected getSPO(value?: T | undefined): {
protected getSPOG(value?: T | undefined): {
subject?: SubjectNode;
predicate?: PredicateNode;
object?: ObjectNode;
graph?: GraphNode;
} {
// Get the RDF Node that represents the value, skip is no value
const predicate = this.quadMatch[1] ?? undefined;
const object = this.quadMatch[2] ?? undefined;
const graph = this.quadMatch[3] ?? undefined;
if (value) {
const valueNode = getNodeFromRawObject(value, this.context.contextUtil);
return {
subject: valueNode,
predicate,
object,
graph,
};
}
// SPO for no value
@ -54,10 +58,15 @@ export class WildcardSubjectSetProxy<T extends RawObject> extends SetProxy<T> {
subject: undefined,
predicate,
object,
graph,
};
}
protected getNodeOfFocus(quad: Quad): SubjectNode {
return quad.subject as SubjectNode;
}
get [_isSubjectOriented](): true {
return true;
}
}

@ -9,20 +9,28 @@ export class BasicLdSet<T extends NonNullable<RawValue> = NonNullable<RawValue>>
extends Set<T>
implements LdSet<T>
{
private hashMap = new Map();
private hashMap: Map<string, T>;
constructor(values?: Iterable<T> | null) {
super(values);
super();
this.hashMap = new Map();
if (values) {
for (const value of values) {
this.add(value);
}
}
}
private hashFn(value: T) {
private hashFn(value: T): string {
if (typeof value !== "object") return value.toString();
if (value[_getUnderlyingNode]) {
return (value[_getUnderlyingNode] as NamedNode | BlankNode).value;
} else if (!value["@id"]) {
return blankNode().value;
} else {
} else if (typeof value["@id"] === "string") {
return value["@id"];
} else {
return value["@id"].value;
}
}

@ -12,6 +12,7 @@ import {
languageDeleteMatch,
languageKeyToLiteralLanguage,
} from "../language/languageUtils";
import { BasicLdSet } from "../setProxy/ldSet/BasicLdSet";
export function addRawValueToDatasetRecursive(
subject: NamedNode | BlankNode,
@ -110,7 +111,7 @@ export function addRawObjectToDatasetRecursive(
dataset.deleteMatches(subject, predicate);
}
}
if (Array.isArray(value)) {
if (value instanceof BasicLdSet) {
value.forEach((valueItem) => {
addRawValueToDatasetRecursive(
subject,

@ -37,6 +37,8 @@ import {
type Bender,
} from "./scopedExampleData";
global.console.warn = () => {};
const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
async function getLoadedDataset(): Promise<
[Dataset, ObservationShape, JsonldDatasetProxyBuilder]
@ -544,13 +546,9 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
it("Creates a blank node if the id is blank during set", async () => {
const [dataset, observation] = await getEmptyObservationDataset();
observation.type = { "@id": "Observation" };
console.log("1");
observation.subject = { type: { "@id": "Patient" }, name: set("Joe") };
console.log("2");
expect(observation.subject?.["@id"]).toBeUndefined();
console.log("here");
expect(observation.subject.name).toContain("Joe");
console.log("there");
expect(
dataset
.match(
@ -707,6 +705,10 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
);
});
// TODO changes to blank node when set undefined on ID
// TODO deletes the object if delete on an ID
it("Removes all adjoining triples when garbage collection is indicated via the delete operator on an object", async () => {
const [dataset, observation] = await getTinyLoadedDataset();
delete observation.subject;
@ -723,25 +725,33 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
);
});
it("Removes all adjoining triples when garbage collection is indicated via the delete operator on an array", async () => {
it("Removes connecting triples when the delete method is called on a set", async () => {
const [dataset, observation] = await getTinyLoadedDataset();
delete observation.subject?.roommate?.[0];
const firstRoommate = observation.subject!.roommate!.toArray()[0];
observation.subject!.roommate!.delete(firstRoommate);
expect(dataset.toString()).toBe(
'<http://example.com/Observation1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Observation> .\n<http://example.com/Observation1> <http://hl7.org/fhir/subject> <http://example.com/Patient1> .\n<http://example.com/Patient1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Patient> .\n<http://example.com/Patient1> <http://hl7.org/fhir/name> "Garrett" .\n',
'<http://example.com/Observation1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Observation> .\n<http://example.com/Observation1> <http://hl7.org/fhir/subject> <http://example.com/Patient1> .\n<http://example.com/Patient1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Patient> .\n<http://example.com/Patient1> <http://hl7.org/fhir/name> "Garrett" .\n<http://example.com/Patient2> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Patient> .\n<http://example.com/Patient2> <http://hl7.org/fhir/name> "Rob" .\n<http://example.com/Patient2> <http://hl7.org/fhir/roommate> <http://example.com/Patient1> .\n',
);
});
it("Removes all adjoining triples when garbage collection is indicated via the delete operator on an array with blank nodes", async () => {
it("Removes connecting triples when the delete method is called on a set with blank nodes", async () => {
const [dataset, observation] = await getTinyLoadedDatasetWithBlankNodes();
const deletedBlankNode =
observation.subject?.roommate?.[0][_getUnderlyingNode];
delete observation.subject?.roommate?.[0];
expect(dataset.match(deletedBlankNode).size).toBe(0);
const originalDatasetSize = dataset.size;
const roommate1 = observation.subject!.roommate!.toArray()[0];
observation.subject!.roommate!.delete(roommate1);
expect(dataset.size).toBe(originalDatasetSize - 1);
expect(
dataset.match(
observation.subject![_getUnderlyingNode],
null,
roommate1[_getUnderlyingNode],
).size,
).toBe(0);
});
it("Removes a literal in an array when using the delete operator", async () => {
it("Removes a literal in an array when using the delete method", async () => {
const [dataset, observation] = await getTinyLoadedDataset();
delete observation.subject?.name?.[0];
observation.subject!.name!.delete("Garrett");
expect(dataset.toString()).toBe(
'<http://example.com/Observation1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Observation> .\n<http://example.com/Observation1> <http://hl7.org/fhir/subject> <http://example.com/Patient1> .\n<http://example.com/Patient1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Patient> .\n<http://example.com/Patient1> <http://hl7.org/fhir/roommate> <http://example.com/Patient2> .\n<http://example.com/Patient2> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://hl7.org/fhir/Patient> .\n<http://example.com/Patient2> <http://hl7.org/fhir/name> "Rob" .\n<http://example.com/Patient2> <http://hl7.org/fhir/roommate> <http://example.com/Patient1> .\n',
);
@ -826,10 +836,13 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
literal("Tow"),
),
);
expect(patient.name).toEqual(["Joe", "Blow", "Tow"]);
expect(patient.name.size).toBe(3);
expect(patient.name).toContain("Joe");
expect(patient.name).toContain("Blow");
expect(patient.name).toContain("Tow");
});
it("Removes elements from the array even if they were modified by the datastore", async () => {
it("Removes elements from the set even if they were modified by the datastore", async () => {
const [dataset, patient] = await getEmptyPatientDataset();
patient.type = { "@id": "Patient" };
patient.name = set("Joe", "Blow");
@ -840,7 +853,8 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
literal("Blow"),
),
);
expect(patient.name).toEqual(["Joe"]);
expect(patient.name.size).toBe(1);
expect(patient.name).toContain("Joe");
});
it("Removes and adds from the array even if they were modified by the datastore", async () => {
@ -861,14 +875,19 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
literal("Tow"),
),
);
expect(patient.name).toEqual(["Joe", "Tow"]);
expect(patient.name.size).toBe(2);
expect(patient.name).toContain("Joe");
expect(patient.name).toContain("Tow");
});
it("Prevents duplicates from being added to the array", async () => {
const [, patient] = await getArrayLoadedDataset();
const arr = patient.name!;
arr.add("Garrett");
expect(arr).toEqual(["Garrett", "Bobby", "Ferguson"]);
expect(arr.size).toBe(3);
expect(arr).toContain("Garrett");
expect(arr).toContain("Bobby");
expect(arr).toContain("Ferguson");
});
// TODO: Check if can delete
@ -886,8 +905,12 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
"@id": "http://example.com/Patient3",
type: { "@id": "Patient" },
});
expect(roommates.size).toBe(1);
expect(roommates.map((obj) => obj.name)).toContain("Amy");
expect(roommates.size).toBe(2);
const roommateNames = roommates.reduce((s, obj) => {
obj.name?.forEach((n) => s.add(n));
return s;
}, set());
expect(roommateNames).toContain("Amy");
});
// TODO: check
@ -1143,18 +1166,8 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
const match = roommateArr[_getUnderlyingMatch];
expect(match[0].value).toBe("http://example.com/Patient1");
expect(match[1].value).toBe("http://hl7.org/fhir/roommate");
// TODO: Alt tests
// expect(roommateArr[_getNodeAtIndex](0).value).toBe(
// "http://example.com/Patient2",
// );
// expect(roommateArr[_getNodeAtIndex](10)).toBe(undefined);
// expect(observation.subject.name[_getNodeAtIndex](0).value).toBe(
// "Garrett",
// );
const underlyingArrayTarget = roommateArr[_getUnderlyingMatch];
expect(underlyingArrayTarget[0].value).toBe(
"http://example.com/Patient2",
);
expect(match[2]).toBe(null);
expect(match[3]).toBe(null);
});
});
@ -1172,9 +1185,9 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
});
it("creates a list of subjects that match a certain pattern", async () => {
expect(patients[0].name?.[0]).toBe("Garrett");
expect(patients[1].name?.[0]).toBe("Rob");
expect(patients[2].name?.[0]).toBe("Amy");
expect(patients.toArray()[0].name?.toArray()[0]).toBe("Garrett");
expect(patients.toArray()[1].name?.toArray()[0]).toBe("Rob");
expect(patients.toArray()[2].name?.toArray()[0]).toBe("Amy");
});
it("Successfully adds a node to the list", async () => {
@ -1195,7 +1208,7 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
return quad.subject.value === "http://example.com/Patient4";
}),
).toBe(true);
expect(patients[3].name?.[0]).toBe("Dippy");
expect(patients.toArray()[3].name?.toArray()[0]).toBe("Dippy");
});
it("will read a new object if something has been added to the dataset after object creation", async () => {
@ -1225,15 +1238,14 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
return quad.subject.value === "http://example.com/Patient4";
}),
).toBe(true);
expect(patients[3].name?.[0]).toBe("Dippy");
expect(patients.toArray()[3].name?.toArray()[0]).toBe("Dippy");
});
it("errors if an object is added without the correct parameters", async () => {
expect(() =>
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
patients.push({
patients.add({
"@id": "http://example.com/Patient4",
// @ts-expect-error This object is purposely wrong
name: ["Dippy"],
age: 2,
}),
@ -1244,66 +1256,15 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
it("errors if a literal is added to the collection", async () => {
// @ts-expect-error Purposely pushing an incorrect value to trigger an error
expect(() => patients.push("some string")).toThrowError(
expect(() => patients.add("some string")).toThrowError(
`Cannot add a literal "some string"(string) to a subject-oriented collection.`,
);
});
it("Removes all an object and replaces in upon set", async () => {
patients[0] = {
"@id": "http://example.com/Patient4",
type: { "@id": "Patient" },
name: ["Dippy"],
age: 2,
};
expect(dataset.match(namedNode("http://example.com/Patient1")).size).toBe(
0,
);
expect(patients[0].name?.[0]).toBe("Dippy");
});
it("Removes an object and replaces it upon splice", async () => {
// TODO adjust test
// patients.splice(
// 1,
// 1,
// {
// "@id": "http://example.com/Patient4",
// type: { "@id": "Patient" },
// name: ["Dippy"],
// age: 2,
// },
// {
// "@id": "http://example.com/Patient5",
// type: { "@id": "Patient" },
// name: ["Licky"],
// age: 3,
// },
// );
// expect(dataset.match(namedNode("http://example.com/Patient2")).size).toBe(
// 0,
// );
// expect(patients[1].name?.[0]).toBe("Dippy");
// expect(patients[2].name?.[0]).toBe("Licky");
});
it("Removes an object completely when assigning it to undefined", async () => {
// TODO adjust
// patients[0] = undefined;
// expect(dataset.match(namedNode("http://example.com/Patient1")).size).toBe(
// 0,
// );
// expect(patients[0].name?.[0]).toBe("Rob");
});
it("Removes an object completely when using the delete parameter", async () => {
delete patients[0];
expect(dataset.match(namedNode("http://example.com/Patient1")).size).toBe(
0,
);
expect(patients[0].name?.[0]).toBe("Rob");
it("Removes an object completely when using the delete method", async () => {
const firstPatient = patients.toArray()[0];
patients.delete(firstPatient);
expect(patients.has(firstPatient)).toBe(true);
});
it("creates a collection that matches only collections in a certain graph", async () => {
@ -1323,9 +1284,11 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
describe("matchObject", () => {
let patients: LdSet<PatientShape>;
let builder: JsonldDatasetProxyBuilder;
let dataset: Dataset;
beforeEach(async () => {
const [, , receivedBuilder] = await getLoadedDataset();
const [recievedDataset, , receivedBuilder] = await getLoadedDataset();
dataset = recievedDataset;
builder = receivedBuilder;
patients = builder.matchObject<PatientShape>(
null,
@ -1335,20 +1298,18 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
});
it("create a collection that matches the null, predicate, null pattern", async () => {
expect(patients[0].name?.[0]).toBe("Garrett");
expect(patients[1].name?.[0]).toBe("Amy");
expect(patients[2].name?.[0]).toBe("Rob");
expect(patients.toArray()[0].name?.toArray()[0]).toBe("Garrett");
expect(patients.toArray()[1].name?.toArray()[0]).toBe("Amy");
expect(patients.toArray()[2].name?.toArray()[0]).toBe("Rob");
});
it("cannot write to a collection that matches the null, predicate, null pattern", () => {
expect(
() =>
(patients[1] = {
"@id": "http://example.com/Patient4",
type: { "@id": "Patient" },
}),
).toThrow(
"A collection that does not specify a match for both a subject or predicate cannot be modified directly.",
patients.add({
"@id": "http://example.com/Patient4",
type: { "@id": "Patient" },
});
expect(dataset.match(namedNode("http://example.com/Patient4")).size).toBe(
0,
);
});
@ -1360,11 +1321,11 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
null,
);
expect(hodgePodge.size).toBe(5);
expect(hodgePodge[0]["@id"]).toBe("Patient");
expect(hodgePodge[1]).toBe("Amy");
expect(hodgePodge[2]).toBe("1988-01-01");
expect(hodgePodge[3]).toBe(33);
expect(hodgePodge[4]).toBe(true);
expect(hodgePodge.toArray()[0]["@id"]).toBe("Patient");
expect(hodgePodge.toArray()[1]).toBe("Amy");
expect(hodgePodge.toArray()[2]).toBe("1988-01-01");
expect(hodgePodge.toArray()[3]).toBe(33);
expect(hodgePodge.toArray()[4]).toBe(true);
});
});
@ -1381,12 +1342,12 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
name: set("Ethical", "Bug"),
}),
});
expect(patient.name?.[0]).toBe("Jack");
expect(patient.name?.[1]).toBe("Horner");
expect(patient.name).toContain("Jack");
expect(patient.name).toContain("Horner");
expect(patient.birthdate).toBe("1725/11/03");
expect(patient.age).toBe(298);
expect(patient.roommate?.[0].name?.[0]).toBe("Ethical");
expect(patient.roommate?.[0].name?.[1]).toBe("Bug");
expect(patient.roommate?.toArray()[0].name).toContain("Ethical");
expect(patient.roommate?.toArray()[0].name).toContain("Bug");
});
it("initializes a patient using the fromJSON method with a named node", async () => {
@ -1403,12 +1364,12 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
}),
});
expect(patient["@id"]).toBe("http://example.com/Patient13");
expect(patient.name?.[0]).toBe("Jack");
expect(patient.name?.[1]).toBe("Horner");
expect(patient.name).toContain("Jack");
expect(patient.name).toContain("Horner");
expect(patient.birthdate).toBe("1725/11/03");
expect(patient.age).toBe(298);
expect(patient.roommate?.[0].name?.[0]).toBe("Ethical");
expect(patient.roommate?.[0].name?.[1]).toBe("Bug");
expect(patient.roommate?.toArray()[0].name).toContain("Ethical");
expect(patient.roommate?.toArray()[0].name).toContain("Bug");
});
});
@ -1443,7 +1404,7 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
it("detects the graph of an array value", async () => {
const [, observation] = await getGraphLoadedDataset();
const patient1 = observation.subject as PatientShape;
const patient1 = observation.subject!;
expect(
graphOf(patient1, "name", "Garrett").map((n) => n.value),
).toContain("http://example.com/Patient1Doc");
@ -1471,14 +1432,6 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
"http://example.com/SomeOtherDoc",
);
});
it("throws an error if a number is provided as an object and the object is not an array", async () => {
const [, observation] = await getGraphLoadedDataset();
// @ts-expect-error this should not be allowed
expect(() => graphOf(observation, "subject", 0)).toThrowError(
`Key "subject" of [object Object] is not an array.`,
);
});
});
describe("write method", () => {
@ -1518,8 +1471,8 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
expect(graphOf(patient, "name", "1")[0].value).toBe(doc1.value);
expect(graphOf(patient, "name", "2")[0].value).toBe(doc2.value);
expect(graphOf(patient, "name", "3")[0].value).toBe(doc3.value);
expect(graphOf(patient, "name", "4")[0].value).toBe(doc2.value);
expect(graphOf(patient, "name", "5")[0].value).toBe(doc1.value);
expect(graphOf(patient, "name", "2 again")[0].value).toBe(doc2.value);
expect(graphOf(patient, "name", "1 again")[0].value).toBe(doc1.value);
expect(graphOf(patient, "name", "default again")[0].value).toBe(
defaultGraph().value,
);
@ -1539,18 +1492,16 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
expect(graphOf(patient, "name", "Doc1")[0].value).toBe(doc1.value);
});
it("works with array proxies", async () => {
it("works with set proxies", async () => {
const [, , builder] = await getTinyLoadedDataset();
const allRoommates = builder.matchObject<PatientShape>(
namedNode("http://example.com/Patient1"),
namedNode("http://hl7.org/fhir/roommate"),
);
write(namedNode("http://example.com/SomeGraph")).using(
allRoommates,
allRoommates,
);
allRoommates[0].age = 20;
expect(graphOf(allRoommates[0], "age")[0].value).toBe(
write(namedNode("http://example.com/SomeGraph")).using(allRoommates);
const firstRoommate = allRoommates.toArray()[0];
firstRoommate.age = 20;
expect(graphOf(firstRoommate, "age")[0].value).toBe(
"http://example.com/SomeGraph",
);
});
@ -1570,7 +1521,7 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
const patient = observation.subject as PatientShape;
expect(observation.langNotes).toBe("Notes Sympas");
expect(patient.langName?.[0]).toBe("Jean");
expect(patient.langName?.toArray()[0]).toBe("Jean");
setLanguagePreferences("ru", "zh").using(observation, patient);
@ -1579,7 +1530,7 @@ const testJsonldDatasetProxy = (patientContext: LdoJsonldContext) => () => {
setLanguagePreferences("@other", "fr").using(observation, patient);
expect(observation.langNotes).not.toBe("Notes Sympas");
expect(patient.langName?.[0]).not.toBe("Jean");
expect(patient.langName?.toArray()[0]).not.toBe("Jean");
setLanguagePreferences().using(observation, patient);
expect(observation.langNotes).toBe(undefined);

Loading…
Cancel
Save