Introduce data field as the main property on which to get/set other properties #4

Merged
jsheunis merged 2 commits from events into main 2026-02-04 08:50:05 +00:00
9 changed files with 115 additions and 99 deletions

View file

@ -28,17 +28,17 @@ const fileUrl = 'https://concepts.datalad.org/s/things/v1.shacl.ttl';
// Listen for and act on the 'graphLoaded' event // Listen for and act on the 'graphLoaded' event
shapesDS.addEventListener('graphLoaded', (event) => { shapesDS.addEventListener('graphLoaded', (event) => {
console.log('Shapes graph fully loaded:', event.detail) console.log('Shapes graph fully loaded:', event.detail)
console.log(shapesDS.propertyGroups) console.log(shapesDS.data.propertyGroups)
console.log(shapesDS.nodeShapes) console.log(shapesDS.data.nodeShapes)
console.log(shapesDS.nodeShapeNames) console.log(shapesDS.data.nodeShapeNames)
console.log(shapesDS.nodeShapeNamesArray) console.log(shapesDS.data.nodeShapeNamesArray)
console.log(shapesDS.nodeShapeIRIs) console.log(shapesDS.data.nodeShapeIRIs)
console.log(shapesDS.prefixes) console.log(shapesDS.data.prefixes)
console.log(shapesDS.serializedGraph) console.log(shapesDS.data.serializedGraph)
console.log(shapesDS.graphLoaded) console.log(shapesDS.data.graphLoaded)
console.log(shapesDS.prefixesLoaded) console.log(shapesDS.data.prefixesLoaded)
console.log(shapesDS.graph) console.log(shapesDS.data.graph)
console.log(shapesDS.graph.size) console.log(shapesDS.data.graph.size)
}); });
// Load the RDF // Load the RDF
shapesDS.loadRDF(fileUrl); shapesDS.loadRDF(fileUrl);

View file

@ -7,8 +7,8 @@ import { RDFS } from '../modules/namespaces';
export class ClassDataset extends RdfDataset { export class ClassDataset extends RdfDataset {
constructor() { constructor(data = {}) {
super() super(data)
} }
onDataFn(quad) { onDataFn(quad) {

View file

@ -8,7 +8,7 @@ import { isEmptyObject, toIRI} from '../modules/utils';
export class FormBase { export class FormBase {
constructor(id_iri = null) { constructor(id_iri = null, content = {}) {
if (!id_iri) { if (!id_iri) {
var msg = "id_iri is a required argument" var msg = "id_iri is a required argument"
@ -16,7 +16,7 @@ export class FormBase {
throw new Error(msg) throw new Error(msg)
} }
this.ID_IRI = id_iri this.ID_IRI = id_iri
this.content = {} this.content = content
this.ignoredProperties = [ this.ignoredProperties = [
RDF.type.value, RDF.type.value,
] ]
@ -230,7 +230,7 @@ export class FormBase {
var quadArray = RdfDS.getSubjectTriples(subject_term) var quadArray = RdfDS.getSubjectTriples(subject_term)
var IdQuadExists = false var IdQuadExists = false
quadArray.forEach((quad) => { quadArray.forEach((quad) => {
var predicate_uri = toIRI(quad.predicate.value, RdfDS.prefixes) var predicate_uri = toIRI(quad.predicate.value, RdfDS.data.prefixes)
if (predicate_uri === this.ID_IRI) { if (predicate_uri === this.ID_IRI) {
IdQuadExists = true IdQuadExists = true
} }
@ -253,7 +253,7 @@ export class FormBase {
if (this.content[class_uri]) { if (this.content[class_uri]) {
// If we are in edit mode, the first step is to delete existing quads from graphData // If we are in edit mode, the first step is to delete existing quads from graphData
if (editMode) { if (editMode) {
RdfDS.graph.deleteMatches(rdf.namedNode(node_uri), null, null, null) RdfDS.data.graph.deleteMatches(rdf.namedNode(node_uri), null, null, null)
} }
// Then we generate the quads // Then we generate the quads
@ -261,7 +261,7 @@ export class FormBase {
var quads = this.formNodeToQuads(class_uri, node_uri, shapesDS) var quads = this.formNodeToQuads(class_uri, node_uri, shapesDS)
// and add them to the dataset // and add them to the dataset
quads.forEach(quad => { quads.forEach(quad => {
RdfDS.graph.add(quad) RdfDS.addQuad(quad)
}); });
// Some next steps depend on the type of the record's subject // Some next steps depend on the type of the record's subject
@ -283,8 +283,8 @@ export class FormBase {
var objectQuads = RdfDS.getObjectTriples(rdf.namedNode(node_uri)) var objectQuads = RdfDS.getObjectTriples(rdf.namedNode(node_uri))
objectQuads.forEach((quad) => { objectQuads.forEach((quad) => {
let new_quad = rdf.quad(quad.subject, quad.predicate, subject) let new_quad = rdf.quad(quad.subject, quad.predicate, subject)
RdfDS.graph.delete(quad) RdfDS.data.graph.delete(quad)
RdfDS.graph.add(new_quad) RdfDS.data.graph.add(new_quad)
}); });
} }
// Change formdata node_uri to the actual id, if this was present: // Change formdata node_uri to the actual id, if this was present:

View file

@ -7,19 +7,35 @@ import formatsPretty from '@rdfjs/formats/pretty.js'
/** /**
* A class wrapping an RDF dataset (quad-store) from the `rdf-ext` library. * A class wrapping an RDF dataset (quad-store) from the `rdf-ext` library.
*/ */
export class RdfDataset extends EventTarget { export class RdfDataset {
/** /**
* Create a wrapper object for an RDF dataset a.k.a. quad-store * Create a wrapper object for an RDF dataset a.k.a. quad-store
*/ */
constructor() { constructor(data = {}) {
super()
this.data = data;
this.rdfPretty = rdf.clone(); this.rdfPretty = rdf.clone();
this.rdfPretty.formats.import(formatsPretty); this.rdfPretty.formats.import(formatsPretty);
this.prefixes = {};
this.serializedGraph = ''; this.data.prefixes = {};
this.graphLoaded = false; this.data.serializedGraph = '';
this.prefixesLoaded = false; this.data.graphLoaded = false;
this.graph = this.createDataset(); this.data.prefixesLoaded = false;
this.data.graph = this.createDataset();
this._eventTarget = new EventTarget();
}
addEventListener(type, listener, options) {
this._eventTarget.addEventListener(type, listener, options);
}
removeEventListener(type, listener, options) {
this._eventTarget.removeEventListener(type, listener, options);
}
dispatchEvent(event) {
return this._eventTarget.dispatchEvent(event);
} }
/** /**
@ -61,7 +77,7 @@ export class RdfDataset extends EventTarget {
* Pre-load function to reset the graph loading state. * Pre-load function to reset the graph loading state.
*/ */
beforeLoadFn() { beforeLoadFn() {
this.graphLoaded = false this.data.graphLoaded = false
} }
/** /**
@ -70,12 +86,12 @@ export class RdfDataset extends EventTarget {
* @param {import("rdf-ext").NamedNode} ns - The namespace associated with the prefix. * @param {import("rdf-ext").NamedNode} ns - The namespace associated with the prefix.
*/ */
onPrefixFn(prefix, ns) { onPrefixFn(prefix, ns) {
this.prefixes[prefix] = ns.value; this.data.prefixes[prefix] = ns.value;
this.dispatchEvent(new CustomEvent('prefix', { detail: { prefix, ns } })); this.dispatchEvent(new CustomEvent('prefix', { detail: { prefix, ns } }));
} }
onPrefixEndFn() { onPrefixEndFn() {
this.prefixesLoaded = true this.data.prefixesLoaded = true
this.dispatchEvent(new CustomEvent('prefixesLoaded', { detail: this.prefixes })); this.dispatchEvent(new CustomEvent('prefixesLoaded', { detail: this.data.prefixes }));
} }
/** /**
@ -87,9 +103,9 @@ export class RdfDataset extends EventTarget {
this.dispatchEvent(new CustomEvent('quad', { detail: quad })); this.dispatchEvent(new CustomEvent('quad', { detail: quad }));
} }
async onDataEndFn() { async onDataEndFn() {
this.serializedGraph = await this.serializeGraph() this.data.serializedGraph = await this.serializeGraph()
this.graphLoaded = true this.data.graphLoaded = true
this.dispatchEvent(new CustomEvent('graphLoaded', { detail: this.graph })); this.dispatchEvent(new CustomEvent('graphLoaded', { detail: this.data.graph }));
} }
/** /**
@ -97,7 +113,7 @@ export class RdfDataset extends EventTarget {
* @param {import("rdf-ext").Quad} quad - The RDF quad to add. * @param {import("rdf-ext").Quad} quad - The RDF quad to add.
*/ */
addQuad(quad) { addQuad(quad) {
this.graph.add(quad) this.data.graph.add(quad)
} }
/** /**
@ -105,7 +121,7 @@ export class RdfDataset extends EventTarget {
* @returns {Promise<string>} The serialized RDF graph in Turtle format. * @returns {Promise<string>} The serialized RDF graph in Turtle format.
*/ */
async serializeGraph() { async serializeGraph() {
return (await this.rdfPretty.io.dataset.toText('text/turtle', this.graph)).trim() return (await this.rdfPretty.io.dataset.toText('text/turtle', this.data.graph)).trim()
} }
/** /**
@ -116,7 +132,7 @@ export class RdfDataset extends EventTarget {
isRdfList(node) { isRdfList(node) {
let hasFirst = false; let hasFirst = false;
let hasRest = false; let hasRest = false;
this.graph.forEach((quad) => { this.data.graph.forEach((quad) => {
if (quad.subject.equals(node)) { if (quad.subject.equals(node)) {
if (quad.predicate.value === RDF.first.value) hasFirst = true; if (quad.predicate.value === RDF.first.value) hasFirst = true;
if (quad.predicate.value === RDF.rest.value) hasRest = true; if (quad.predicate.value === RDF.rest.value) hasRest = true;
@ -136,11 +152,11 @@ export class RdfDataset extends EventTarget {
while (currentNode && currentNode.value !== RDF.nil.value) { while (currentNode && currentNode.value !== RDF.nil.value) {
let listItem = null; let listItem = null;
// Get the first element in the RDF list // Get the first element in the RDF list
this.graph.forEach((quad) => { this.data.graph.forEach((quad) => {
if (quad.subject.equals(currentNode) && quad.predicate.value === RDF.first.value) { if (quad.subject.equals(currentNode) && quad.predicate.value === RDF.first.value) {
// Resolve blank nodes recursively, but handle literals and IRIs separately // Resolve blank nodes recursively, but handle literals and IRIs separately
if (quad.object.termType === "BlankNode") { if (quad.object.termType === "BlankNode") {
listItem = this.resolveBlankNode(quad.object, this.graph); listItem = this.resolveBlankNode(quad.object, this.data.graph);
} else if (quad.object.termType === "Literal") { } else if (quad.object.termType === "Literal") {
listItem = quad.object.value; // Store literal value listItem = quad.object.value; // Store literal value
} else if (quad.object.termType === "NamedNode") { } else if (quad.object.termType === "NamedNode") {
@ -153,7 +169,7 @@ export class RdfDataset extends EventTarget {
} }
// Move to the next item in the list (rdf:rest) // Move to the next item in the list (rdf:rest)
let nextNode = null; let nextNode = null;
this.graph.forEach((quad) => { this.data.graph.forEach((quad) => {
if (quad.subject.equals(currentNode) && quad.predicate.value === RDF.rest.value) { if (quad.subject.equals(currentNode) && quad.predicate.value === RDF.rest.value) {
nextNode = quad.object; nextNode = quad.object;
} }
@ -165,7 +181,7 @@ export class RdfDataset extends EventTarget {
resolveBlankNode(blankNode) { resolveBlankNode(blankNode) {
let resolvedObject = {}; let resolvedObject = {};
this.graph.forEach((quad) => { this.data.graph.forEach((quad) => {
if (quad.subject.equals(blankNode)) { if (quad.subject.equals(blankNode)) {
const predicate = quad.predicate.value; const predicate = quad.predicate.value;
const object = quad.object; const object = quad.object;
@ -191,11 +207,11 @@ export class RdfDataset extends EventTarget {
getLiteralAndNamedNodes(predicate, propertyClass, prefixes) { getLiteralAndNamedNodes(predicate, propertyClass, prefixes) {
var propClassCurie = toCURIE(propertyClass, prefixes) var propClassCurie = toCURIE(propertyClass, prefixes)
// a) use the literal node with xsd data type // a) use the literal node with xsd data type
const literalNodes = rdf.grapoi({ dataset: this.graph }) const literalNodes = rdf.grapoi({ dataset: this.data.graph })
.hasOut(predicate, rdf.literal(String(propClassCurie), XSD.anyURI)) .hasOut(predicate, rdf.literal(String(propClassCurie), XSD.anyURI))
.quads(); .quads();
// b) and the named node // b) and the named node
const uriNodes = rdf.grapoi({ dataset: this.graph }) const uriNodes = rdf.grapoi({ dataset: this.data.graph })
.hasOut(predicate, rdf.namedNode(propertyClass)) .hasOut(predicate, rdf.namedNode(propertyClass))
.quads(); .quads();
// return as a concatenated array of quads // return as a concatenated array of quads
@ -203,12 +219,12 @@ export class RdfDataset extends EventTarget {
} }
getSubjectTriples(someTerm) { getSubjectTriples(someTerm) {
const quads = rdf.grapoi({ dataset: this.graph, term: someTerm }).out().quads(); const quads = rdf.grapoi({ dataset: this.data.graph, term: someTerm }).out().quads();
return Array.from(quads) return Array.from(quads)
} }
getObjectTriples(someTerm) { getObjectTriples(someTerm) {
const quads = rdf.grapoi({ dataset: this.graph, term: someTerm }).in().quads(); const quads = rdf.grapoi({ dataset: this.data.graph, term: someTerm }).in().quads();
return Array.from(quads) return Array.from(quads)
} }
} }

View file

@ -9,13 +9,13 @@ import { toIRI} from '../modules/utils';
export class ShapesDataset extends RdfDataset { export class ShapesDataset extends RdfDataset {
constructor() { constructor(data = {}) {
super() super(data)
this.propertyGroups = {} this.data.propertyGroups = {}
this.nodeShapes = {} this.data.nodeShapes = {}
this.nodeShapeNames = {} this.data.nodeShapeNames = {}
this.nodeShapeNamesArray = [] this.data.nodeShapeNamesArray = []
this.nodeShapeIRIs = null this.data.nodeShapeIRIs = null
} }
onDataFn(quad) { onDataFn(quad) {
@ -25,30 +25,30 @@ export class ShapesDataset extends RdfDataset {
const object = quad.object; const object = quad.object;
// Isolate sh:NodeShape instances // Isolate sh:NodeShape instances
if (predicate === RDF.type.value && object.value === SHACL.NodeShape.value) { if (predicate === RDF.type.value && object.value === SHACL.NodeShape.value) {
this.nodeShapes[subject] = {properties: []}; this.data.nodeShapes[subject] = {properties: []};
} }
// Get properties of node shapes // Get properties of node shapes
if (predicate === SHACL.property.value) { if (predicate === SHACL.property.value) {
this.nodeShapes[subject].properties.push(object); this.data.nodeShapes[subject].properties.push(object);
} }
// Get property groups, if any // Get property groups, if any
if (predicate === RDF.type.value && object.value === SHACL.PropertyGroup.value) { if (predicate === RDF.type.value && object.value === SHACL.PropertyGroup.value) {
this.propertyGroups[subject] = {}; this.data.propertyGroups[subject] = {};
} }
this.dispatchEvent(new CustomEvent('quad', { detail: quad })); this.dispatchEvent(new CustomEvent('quad', { detail: quad }));
} }
async onDataEndFn() { async onDataEndFn() {
// Loop through all nodeshapes to restructure them // Loop through all nodeshapes to restructure them
for (const [key, val] of Object.entries(this.nodeShapes)) { for (const [key, val] of Object.entries(this.data.nodeShapes)) {
// Get attributes (other than 'properties') of the nodeshape // Get attributes (other than 'properties') of the nodeshape
this.graph.forEach(quad => { this.data.graph.forEach(quad => {
if (quad.subject.value === key && quad.predicate.value != SHACL.property.value) { if (quad.subject.value === key && quad.predicate.value != SHACL.property.value) {
// Check if the object is a blank node and resolve it // Check if the object is a blank node and resolve it
if (quad.object.termType === 'BlankNode') { if (quad.object.termType === 'BlankNode') {
this.nodeShapes[key][quad.predicate.value] = this.resolveBlankNode(quad.object); this.data.nodeShapes[key][quad.predicate.value] = this.resolveBlankNode(quad.object);
} else { } else {
this.nodeShapes[key][quad.predicate.value] = quad.object.value; this.data.nodeShapes[key][quad.predicate.value] = quad.object.value;
} }
} }
}); });
@ -62,7 +62,7 @@ export class ShapesDataset extends RdfDataset {
} else { } else {
// Non-blank nodes are kept as they are, but eventually store only their `.value` // Non-blank nodes are kept as they are, but eventually store only their `.value`
var new_node = {}; var new_node = {};
this.graph.forEach((quad) => { this.data.graph.forEach((quad) => {
if (quad.subject.value === node.value) { if (quad.subject.value === node.value) {
new_node[quad.predicate.value] = quad.object.value; // Store only .value new_node[quad.predicate.value] = quad.object.value; // Store only .value
} }
@ -71,27 +71,27 @@ export class ShapesDataset extends RdfDataset {
} }
} }
} }
for (const iri of Object.keys(this.nodeShapes)) { for (const iri of Object.keys(this.data.nodeShapes)) {
var parts = iri.split('/') var parts = iri.split('/')
this.nodeShapeNames[parts[parts.length - 1]] = iri this.data.nodeShapeNames[parts[parts.length - 1]] = iri
} }
this.nodeShapeNamesArray = Object.keys(this.nodeShapeNames).sort() this.data.nodeShapeNamesArray = Object.keys(this.data.nodeShapeNames).sort()
this.nodeShapeIRIs = Object.keys(this.nodeShapes).sort() this.data.nodeShapeIRIs = Object.keys(this.data.nodeShapes).sort()
// Now handle the (possibility of) property groups // Now handle the (possibility of) property groups
for (const [key, value] of Object.entries(this.propertyGroups)) { for (const [key, value] of Object.entries(this.data.propertyGroups)) {
this.graph.forEach(quad => { this.data.graph.forEach(quad => {
if (quad.subject.value === key && quad.predicate.value != RDF.type.value ) { if (quad.subject.value === key && quad.predicate.value != RDF.type.value ) {
this.propertyGroups[key][quad.predicate.value] = quad.object.value this.data.propertyGroups[key][quad.predicate.value] = quad.object.value
} }
}); });
} }
this.serializedGraph = await this.serializeGraph() this.data.serializedGraph = await this.serializeGraph()
this.graphLoaded = true this.data.graphLoaded = true
this.dispatchEvent(new CustomEvent('graphLoaded', { detail: this.graph })); this.dispatchEvent(new CustomEvent('graphLoaded', { detail: this.data.graph }));
} }
getPropertyNodeKind(class_uri, property_uri, id_uri) { getPropertyNodeKind(class_uri, property_uri, id_uri) {
var nodeShape = this.nodeShapes[class_uri] var nodeShape = this.data.nodeShapes[class_uri]
var propertyShapes = nodeShape.properties var propertyShapes = nodeShape.properties
// Find associated property shape, for information about nodekind // Find associated property shape, for information about nodekind
var propertyShape = propertyShapes.find((prop) => prop[SHACL.path.value] == property_uri) var propertyShape = propertyShapes.find((prop) => prop[SHACL.path.value] == property_uri)
@ -125,7 +125,7 @@ export class ShapesDataset extends RdfDataset {
if (propertyShape.hasOwnProperty(SHACL.class.value)) { if (propertyShape.hasOwnProperty(SHACL.class.value)) {
var shClass = propertyShape[SHACL.class.value]; var shClass = propertyShape[SHACL.class.value];
// this now assumes that the class is part of the driving shacl shapes graph // this now assumes that the class is part of the driving shacl shapes graph
var associatedNodeShape = this.nodeShapes[toIRI(shClass, this.prefixes)] var associatedNodeShape = this.data.nodeShapes[toIRI(shClass, this.data.prefixes)]
var hasIdField = associatedNodeShape.properties.find((prop) => prop[SHACL.path.value] == id_uri) var hasIdField = associatedNodeShape.properties.find((prop) => prop[SHACL.path.value] == id_uri)
if (hasIdField) { if (hasIdField) {
nodeFunc = rdf.namedNode nodeFunc = rdf.namedNode

View file

@ -18,8 +18,8 @@ describe('ClassDataset', () => {
console.log("Running ClassDataset Test 1...") console.log("Running ClassDataset Test 1...")
expect(dataset.graphLoaded).toBe(false); expect(dataset.data.graphLoaded).toBe(false);
expect(dataset.prefixesLoaded).toBe(false); expect(dataset.data.prefixesLoaded).toBe(false);
server = httpServer.createServer({ }); server = httpServer.createServer({ });
server.listen(PORT, HOST, (err) => { server.listen(PORT, HOST, (err) => {
@ -29,9 +29,9 @@ describe('ClassDataset', () => {
const fileUrl = `http://${HOST}:${PORT}/tests/mockData.ttl` const fileUrl = `http://${HOST}:${PORT}/tests/mockData.ttl`
dataset.loadRDF(fileUrl); dataset.loadRDF(fileUrl);
await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve)); await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve));
expect(dataset.graph.size).toBe(1); expect(dataset.data.graph.size).toBe(1);
expect(dataset.graphLoaded).toBe(true); expect(dataset.data.graphLoaded).toBe(true);
expect(dataset.prefixesLoaded).toBe(true); expect(dataset.data.prefixesLoaded).toBe(true);
const serializedGraph = await dataset.serializeGraph(); const serializedGraph = await dataset.serializeGraph();
expect(serializedGraph).not.toContain('<http://example.com/subject>'); expect(serializedGraph).not.toContain('<http://example.com/subject>');
expect(serializedGraph).not.toContain('<http://example.com/predicate>'); expect(serializedGraph).not.toContain('<http://example.com/predicate>');

View file

@ -93,7 +93,7 @@ describe('FormBase', () => {
form.saveNode(class_uri, subject_uri, shapesDS, rdfDSnew, false) form.saveNode(class_uri, subject_uri, shapesDS, rdfDSnew, false)
// Even though formdata has 3 predicates for the record, // Even though formdata has 3 predicates for the record,
// the id_iri field should not be saved as a separate quad // the id_iri field should not be saved as a separate quad
expect(rdfDSnew.graph.size).toBe(2) expect(rdfDSnew.data.graph.size).toBe(2)
}); });

View file

@ -20,7 +20,7 @@ describe('RdfDataset', () => {
// test creation of class instance // test creation of class instance
it('should create an empty dataset', () => { it('should create an empty dataset', () => {
console.log(`Running RdfDataset Test ${i++}...`) console.log(`Running RdfDataset Test ${i++}...`)
expect(dataset.graph.size).toBe(0); expect(dataset.data.graph.size).toBe(0);
}); });
it('should add a quad to the dataset', () => { it('should add a quad to the dataset', () => {
@ -32,8 +32,8 @@ describe('RdfDataset', () => {
dataset.addQuad(quad); dataset.addQuad(quad);
expect(dataset.graph.size).toBe(1); expect(dataset.data.graph.size).toBe(1);
expect(dataset.graph.has(quad)).toBe(true); expect(dataset.data.graph.has(quad)).toBe(true);
}); });
it('should correctly detect an RDF list', () => { it('should correctly detect an RDF list', () => {
@ -88,18 +88,18 @@ describe('RdfDataset', () => {
if (err && err.code !== 'EADDRINUSE') throw err; if (err && err.code !== 'EADDRINUSE') throw err;
console.log(`Test server started on http://${HOST}:${PORT}`); console.log(`Test server started on http://${HOST}:${PORT}`);
}); });
expect(dataset.graphLoaded).toBe(false); expect(dataset.data.graphLoaded).toBe(false);
expect(dataset.prefixesLoaded).toBe(false); expect(dataset.data.prefixesLoaded).toBe(false);
const fileUrl = `http://${HOST}:${PORT}/tests/mockData.ttl` const fileUrl = `http://${HOST}:${PORT}/tests/mockData.ttl`
const graphLoadedHandler = vi.fn(); const graphLoadedHandler = vi.fn();
dataset.addEventListener('graphLoaded', graphLoadedHandler); dataset.addEventListener('graphLoaded', graphLoadedHandler);
dataset.loadRDF(fileUrl); dataset.loadRDF(fileUrl);
await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve)); await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve));
expect(graphLoadedHandler).toHaveBeenCalledTimes(1); expect(graphLoadedHandler).toHaveBeenCalledTimes(1);
expect(dataset.graph.size).toBe(2); expect(dataset.data.graph.size).toBe(2);
expect(dataset.prefixes['ex']).toBe('http://example.com/'); expect(dataset.data.prefixes['ex']).toBe('http://example.com/');
expect(dataset.graphLoaded).toBe(true); expect(dataset.data.graphLoaded).toBe(true);
expect(dataset.prefixesLoaded).toBe(true); expect(dataset.data.prefixesLoaded).toBe(true);
console.log(`Closing server on http://${HOST}:${PORT}`); console.log(`Closing server on http://${HOST}:${PORT}`);
server.close(); server.close();
@ -112,7 +112,7 @@ describe('RdfDataset', () => {
dataset.addEventListener('prefix', prefixHandler); dataset.addEventListener('prefix', prefixHandler);
dataset.onPrefixFn('ex', rdf.namedNode('http://example.com/')); dataset.onPrefixFn('ex', rdf.namedNode('http://example.com/'));
expect(prefixHandler).toHaveBeenCalledTimes(1); expect(prefixHandler).toHaveBeenCalledTimes(1);
expect(dataset.prefixes['ex']).toBe('http://example.com/'); expect(dataset.data.prefixes['ex']).toBe('http://example.com/');
}); });
it('should resolve blank nodes correctly', () => { it('should resolve blank nodes correctly', () => {

View file

@ -15,8 +15,8 @@ describe('ShapesDataset', () => {
}); });
it('should load RDF data from Turtle file and populate all shapes-related variables', async () => { it('should load RDF data from Turtle file and populate all shapes-related variables', async () => {
expect(dataset.graphLoaded).toBe(false); expect(dataset.data.graphLoaded).toBe(false);
expect(dataset.prefixesLoaded).toBe(false); expect(dataset.data.prefixesLoaded).toBe(false);
server = httpServer.createServer({ }); server = httpServer.createServer({ });
server.listen(PORT, HOST, (err) => { server.listen(PORT, HOST, (err) => {
if (err && err.code !== 'EADDRINUSE') throw err; if (err && err.code !== 'EADDRINUSE') throw err;
@ -25,26 +25,26 @@ describe('ShapesDataset', () => {
const fileUrl = `http://${HOST}:${PORT}/tests/mockShapes.ttl` const fileUrl = `http://${HOST}:${PORT}/tests/mockShapes.ttl`
dataset.loadRDF(fileUrl); dataset.loadRDF(fileUrl);
await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve)); await new Promise(resolve => dataset.addEventListener('graphLoaded', resolve));
expect(dataset.graphLoaded).toBe(true); expect(dataset.data.graphLoaded).toBe(true);
expect(dataset.prefixesLoaded).toBe(true); expect(dataset.data.prefixesLoaded).toBe(true);
expect(dataset.graph.size).toBe(318); // number of quads in the mockShapes.ttl file expect(dataset.data.graph.size).toBe(318); // number of quads in the mockShapes.ttl file
// Test content of all loaded variables // Test content of all loaded variables
expect(dataset.nodeShapeNames).toEqual( expect(dataset.data.nodeShapeNames).toEqual(
{ {
AttributeSpecification: 'https://concepts.datalad.org/s/things/v1/AttributeSpecification', AttributeSpecification: 'https://concepts.datalad.org/s/things/v1/AttributeSpecification',
Person: 'https://concepts.datalad.org/s/social/unreleased/Person', Person: 'https://concepts.datalad.org/s/social/unreleased/Person',
DOI: 'https://concepts.datalad.org/s/identifiers/unreleased/DOI' DOI: 'https://concepts.datalad.org/s/identifiers/unreleased/DOI'
} }
) )
expect(dataset.nodeShapeNamesArray).toEqual(['AttributeSpecification', 'DOI', 'Person']) expect(dataset.data.nodeShapeNamesArray).toEqual(['AttributeSpecification', 'DOI', 'Person'])
expect(dataset.nodeShapeIRIs).toEqual( expect(dataset.data.nodeShapeIRIs).toEqual(
[ [
'https://concepts.datalad.org/s/identifiers/unreleased/DOI', 'https://concepts.datalad.org/s/identifiers/unreleased/DOI',
'https://concepts.datalad.org/s/social/unreleased/Person', 'https://concepts.datalad.org/s/social/unreleased/Person',
'https://concepts.datalad.org/s/things/v1/AttributeSpecification' 'https://concepts.datalad.org/s/things/v1/AttributeSpecification'
] ]
) )
expect(dataset.propertyGroups).toEqual( expect(dataset.data.propertyGroups).toEqual(
{ {
'https://concepts.datalad.org/s/things/v1/BasicPropertyGroup': { 'https://concepts.datalad.org/s/things/v1/BasicPropertyGroup': {
'http://www.w3.org/ns/shacl#order': '0', 'http://www.w3.org/ns/shacl#order': '0',
@ -58,7 +58,7 @@ describe('ShapesDataset', () => {
} }
} }
) )
expect(dataset.prefixes).toEqual( expect(dataset.data.prefixes).toEqual(
{ {
'ex': 'http://example.com/', 'ex': 'http://example.com/',
'dlidentifiers': 'https://concepts.datalad.org/s/identifiers/unreleased/', 'dlidentifiers': 'https://concepts.datalad.org/s/identifiers/unreleased/',