@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
1,684 lines (1,503 loc) • 58.1 kB
text/typescript
/**
* Copyright 2020 Inrupt Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { describe, it, expect } from "@jest/globals";
import { Quad } from "rdf-js";
import { dataset } from "@rdfjs/dataset";
import { DataFactory } from "n3";
import { IriString, ThingLocal, LocalNode, Thing } from "../interfaces";
import {
setUrl,
setBoolean,
setDatetime,
setDecimal,
setInteger,
setStringWithLocale,
setStringNoLocale,
setNamedNode,
setLiteral,
setTerm,
} from "./set";
import { mockThingFrom } from "./mock";
import {
ValidPropertyUrlExpectedError,
ValidValueUrlExpectedError,
} from "./thing";
import { getMatchingQuads } from "../rdfjs.test";
function getMockQuad(
subject: IriString,
predicate: IriString,
object: IriString
): Quad {
return DataFactory.quad(
DataFactory.namedNode(subject),
DataFactory.namedNode(predicate),
DataFactory.namedNode(object)
);
}
function getMockThing(quad: Quad) {
const thing = dataset();
thing.add(quad);
return Object.assign(thing, { internal_url: quad.subject.value });
}
function literalOfType(
literalType: "string" | "integer" | "decimal" | "boolean" | "dateTime",
literalValue: string
) {
return DataFactory.literal(
literalValue,
DataFactory.namedNode("http://www.w3.org/2001/XMLSchema#" + literalType)
);
}
describe("setIri", () => {
it("replaces existing values with the given IRI for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setUrl(
thing,
"https://some.vocab/predicate",
"https://some.pod/other-resource#object"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
})
).toHaveLength(1);
});
it("accepts values as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setUrl(
thing,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/other-resource#object")
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
})
).toHaveLength(1);
});
it("accepts values as ThingPersisteds", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const targetThing = Object.assign(dataset(), {
internal_url: "https://some.pod/other-resource#object",
});
const updatedThing = setUrl(
thing,
"https://some.vocab/predicate",
targetThing
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
})
).toHaveLength(1);
});
it("accepts values as ThingLocals", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const datasetWithThingLocal = dataset();
const localSubject: LocalNode = Object.assign(DataFactory.blankNode(), {
internal_name: "localObject",
});
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setUrl(
thing,
"https://some.vocab/predicate",
thingLocal
);
expect(updatedThing.size).toBe(1);
const matchedQuads = getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
});
expect((matchedQuads[0].object as LocalNode).internal_name).toBe(
"localObject"
);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setUrl(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"https://some.pod/other-resource#object"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setUrl(
thing,
"https://arbitrary.vocab/predicate",
"https://arbitrary.pod/other-resource#object"
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const datasetWithThingLocal = dataset();
const localSubject: LocalNode = Object.assign(DataFactory.blankNode(), {
internal_name: "localSubject",
});
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setUrl(
thingLocal,
"https://some.vocab/predicate",
"https://some.pod/other-resource#object"
);
expect(updatedThing.size).toBe(1);
const matchingQuads = getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
});
expect((matchingQuads[0].subject as LocalNode).internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setUrl(
thing,
"https://some.vocab/other-predicate",
"https://some.pod/resource#object"
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setUrl(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
"https://arbitrary.url"
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"https://arbitrary.url"
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"https://arbitrary.url"
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
it("throws an error when passed an invalid URL value", () => {
expect(() =>
setUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"https://arbitrary.vocab/predicate",
"not-a-url"
)
).toThrow("Expected a valid URL value, but received: [not-a-url].");
});
it("throws an instance of ValidValueUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"https://arbitrary.vocab/predicate",
"not-a-url"
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidValueUrlExpectedError);
});
});
describe("setBoolean", () => {
it("replaces existing values with the given boolean for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setBoolean(
thing,
"https://some.vocab/predicate",
true
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("boolean", "true"),
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setBoolean(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
false
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("boolean", "false"),
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setBoolean(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
true
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const datasetWithThingLocal = dataset();
datasetWithThingLocal.add(
DataFactory.quad(
localSubject,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setBoolean(
thingLocal,
"https://some.vocab/predicate",
true
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: literalOfType("boolean", "true"),
})
).toHaveLength(1);
expect(updatedThing.internal_localSubject.internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setBoolean(
thing,
"https://some.vocab/other-predicate",
true
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: literalOfType("boolean", "true"),
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setBoolean(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
true
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setBoolean(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
true
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setBoolean(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
true
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("setDatetime", () => {
it("replaces existing values with the given datetime for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setDatetime(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("dateTime", "1990-11-12T13:37:42.000Z"),
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setDatetime(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("dateTime", "1990-11-12T13:37:42.000Z"),
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setDatetime(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const datasetWithThingLocal = dataset();
datasetWithThingLocal.add(
DataFactory.quad(
localSubject,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setDatetime(
thingLocal,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: literalOfType("dateTime", "1990-11-12T13:37:42.000Z"),
})
).toHaveLength(1);
expect(updatedThing.internal_localSubject.internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setDatetime(
thing,
"https://some.vocab/other-predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: literalOfType("dateTime", "1990-11-12T13:37:42.000Z"),
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setDatetime(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setDatetime(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setDatetime(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0))
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("setDecimal", () => {
it("replaces existing values with the given decimal for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setDecimal(
thing,
"https://some.vocab/predicate",
13.37
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("decimal", "13.37"),
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setDecimal(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
13.37
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("decimal", "13.37"),
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setDecimal(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
13.37
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const datasetWithThingLocal = dataset();
datasetWithThingLocal.add(
DataFactory.quad(
localSubject,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setDecimal(
thingLocal,
"https://some.vocab/predicate",
13.37
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: literalOfType("decimal", "13.37"),
})
).toHaveLength(1);
expect(updatedThing.internal_localSubject.internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setDecimal(
thing,
"https://some.vocab/other-predicate",
13.37
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: literalOfType("decimal", "13.37"),
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setDecimal(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
13.37
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setDecimal(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
13.37
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setDecimal(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
13.37
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("setInteger", () => {
it("replaces existing values with the given integer for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setInteger(thing, "https://some.vocab/predicate", 42);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("integer", "42"),
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setInteger(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
42
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("integer", "42"),
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setInteger(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
42
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const datasetWithThingLocal = dataset();
datasetWithThingLocal.add(
DataFactory.quad(
localSubject,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setInteger(
thingLocal,
"https://some.vocab/predicate",
42
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: literalOfType("integer", "42"),
})
).toHaveLength(1);
expect(updatedThing.internal_localSubject.internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setInteger(
thing,
"https://some.vocab/other-predicate",
42
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: literalOfType("integer", "42"),
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setInteger(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
42
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setInteger(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
42
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setInteger(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
42
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("setStringWithLocale", () => {
it("replaces existing values with the given localised string for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setStringWithLocale(
thing,
"https://some.vocab/predicate",
"Some string value",
"en-GB"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: DataFactory.literal("Some string value", "en-gb"),
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setStringWithLocale(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string value",
"en-GB"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: DataFactory.literal("Some string value", "en-gb"),
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setStringWithLocale(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string value",
"en-GB"
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const datasetWithThingLocal = dataset();
datasetWithThingLocal.add(
DataFactory.quad(
localSubject,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setStringWithLocale(
thingLocal,
"https://some.vocab/predicate",
"Some string value",
"en-GB"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: DataFactory.literal("Some string value", "en-gb"),
})
).toHaveLength(1);
expect(updatedThing.internal_localSubject.internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setStringWithLocale(
thing,
"https://some.vocab/other-predicate",
"Some string value",
"en-GB"
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: DataFactory.literal("Some string value", "en-gb"),
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setStringWithLocale(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
"Arbitrary string",
"nl-NL"
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setStringWithLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string",
"nl-NL"
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setStringWithLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string",
"nl-NL"
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("setStringNoLocale", () => {
it("replaces existing values with the given unlocalised string for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setStringNoLocale(
thing,
"https://some.vocab/predicate",
"Some string value"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("string", "Some string value"),
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setStringNoLocale(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string value"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: literalOfType("string", "Some string value"),
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setStringNoLocale(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string value"
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const datasetWithThingLocal = dataset();
datasetWithThingLocal.add(
DataFactory.quad(
localSubject,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setStringNoLocale(
thingLocal,
"https://some.vocab/predicate",
"Some string value"
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: literalOfType("string", "Some string value"),
})
).toHaveLength(1);
expect(updatedThing.internal_localSubject.internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setStringNoLocale(
thing,
"https://some.vocab/other-predicate",
"Some string value"
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: literalOfType("string", "Some string value"),
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setStringNoLocale(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
"Arbitrary string"
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setStringNoLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string"
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setStringNoLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string"
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("setNamedNode", () => {
it("replaces existing values with the given Named Node for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setNamedNode(
thing,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/other-resource#object")
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setNamedNode(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://some.pod/other-resource#object")
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setNamedNode(
thing,
"https://arbitrary.vocab/predicate",
DataFactory.namedNode("https://arbitrary.pod/other-resource#object")
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const datasetWithThingLocal = dataset();
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setNamedNode(
thingLocal,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/other-resource#object")
);
expect(updatedThing.size).toBe(1);
const matchingQuads = getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: "https://some.pod/other-resource#object",
});
expect((matchingQuads[0].subject as LocalNode).internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setNamedNode(
thing,
"https://some.vocab/other-predicate",
DataFactory.namedNode("https://some.pod/resource#object")
);
expect(updatedThing.size).toBe(2);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/other-predicate",
object: "https://some.pod/resource#object",
})
).toHaveLength(1);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
setNamedNode(
(null as unknown) as Thing,
"https://arbitrary.vocab/predicate",
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
setNamedNode(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
DataFactory.namedNode("https://arbitrary.vocab/object")
)
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url]."
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
setNamedNode(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
DataFactory.namedNode("https://arbitrary.vocab/object")
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("setLiteral", () => {
it("replaces existing values with the given Literal for the given Predicate", () => {
const existingQuad1 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object1"
);
const existingQuad2 = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object2"
);
const thing = getMockThing(existingQuad1);
thing.add(existingQuad2);
const updatedThing = setLiteral(
thing,
"https://some.vocab/predicate",
DataFactory.literal("Some string value")
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: DataFactory.literal("Some string value"),
})
).toHaveLength(1);
});
it("accepts Properties as Named Nodes", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://arbitrary.pod/resource#object"
);
const thing = getMockThing(existingQuad);
const updatedThing = setLiteral(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.literal("Some string value")
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
subject: "https://some.pod/resource#subject",
predicate: "https://some.vocab/predicate",
object: DataFactory.literal("Some string value"),
})
).toHaveLength(1);
});
it("does not modify the input Thing", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/predicate",
"https://some.pod/resource#object"
);
const thing = getMockThing(existingQuad);
setLiteral(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.literal("Arbitrary string value")
);
expect(Array.from(thing)).toEqual([existingQuad]);
});
it("also works on ThingLocals", () => {
const localSubject = Object.assign(
DataFactory.blankNode("Arbitrary blank node"),
{ internal_name: "localSubject" }
);
const datasetWithThingLocal = dataset();
datasetWithThingLocal.add(
DataFactory.quad(
localSubject,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://arbitrary.pod/resource#object")
)
);
const thingLocal: ThingLocal = Object.assign(datasetWithThingLocal, {
internal_localSubject: localSubject,
});
const updatedThing = setLiteral(
thingLocal,
"https://some.vocab/predicate",
DataFactory.literal("Some string value")
);
expect(updatedThing.size).toBe(1);
expect(
getMatchingQuads(updatedThing, {
predicate: "https://some.vocab/predicate",
object: DataFactory.literal("Some string value"),
})
).toHaveLength(1);
expect(updatedThing.internal_localSubject.internal_name).toBe(
"localSubject"
);
});
it("preserves existing Quads with different Predicates", () => {
const existingQuad = getMockQuad(
"https://some.pod/resource#subject",
"https://some.vocab/