From 266402883fcbdb47f7fbe61defe78cff7f43b6b7 Mon Sep 17 00:00:00 2001 From: Alastair Porter Date: Tue, 13 Jul 2021 11:16:21 +0200 Subject: [PATCH] feat(schema): Move skos:broader from DefinedTerm to DefinedTermSet After using the previous model we realised that it made more sense to have a DTS as the equivalent of an annotation "motivation", and use a related term as the annotation's body. This moves broaderUrl and broaderMotivation from DT to DTS, and changes supporting code --- src/routes/helpers/jsonld/DefinedTerm.json | 6 -- src/routes/helpers/jsonld/DefinedTermSet.json | 6 ++ src/routes/helpers/transformer.test.js | 56 +++++++++---------- src/routes/helpers/transformers.js | 10 ++-- src/schema/type/Annotation.graphql | 4 +- src/schema/type/DefinedTerm.graphql | 12 ---- src/schema/type/DefinedTermSet.graphql | 10 ++++ 7 files changed, 49 insertions(+), 55 deletions(-) diff --git a/src/routes/helpers/jsonld/DefinedTerm.json b/src/routes/helpers/jsonld/DefinedTerm.json index 2380af9..a2e1fb0 100644 --- a/src/routes/helpers/jsonld/DefinedTerm.json +++ b/src/routes/helpers/jsonld/DefinedTerm.json @@ -98,12 +98,6 @@ ], "inDefinedTermSet": [ "https://pending.schema.org/inDefinedTermSet" - ], - "broaderUrl": [ - "http://www.w3.org/2004/02/skos/core#broader" - ], - "broaderMotivation": [ - "http://www.w3.org/2004/02/skos/core#broader" ] } } \ No newline at end of file diff --git a/src/routes/helpers/jsonld/DefinedTermSet.json b/src/routes/helpers/jsonld/DefinedTermSet.json index 519e6b2..4e13fb1 100644 --- a/src/routes/helpers/jsonld/DefinedTermSet.json +++ b/src/routes/helpers/jsonld/DefinedTermSet.json @@ -248,6 +248,12 @@ ], "hasDefinedTerm": [ "https://pending.schema.org/hasDefinedTerm" + ], + "broaderUrl": [ + "http://www.w3.org/2004/02/skos/core#broader" + ], + "broaderMotivation": [ + "http://www.w3.org/2004/02/skos/core#broader" ] } } \ No newline at end of file diff --git a/src/routes/helpers/transformer.test.js b/src/routes/helpers/transformer.test.js index b811eb2..010b25a 100644 --- a/src/routes/helpers/transformer.test.js +++ b/src/routes/helpers/transformer.test.js @@ -1,78 +1,74 @@ -import {preprocessDefinedTerm, transformJsonLD} from "./transformers"; +import {preprocessDefinedTermSet, transformJsonLD} from "./transformers"; import { DateTime } from 'neo4j-driver/lib/temporal-types' -describe('definedTermTest', function () { +describe('definedTermSetTest', function () { const sampleDocument = { "broaderMotivation": "commenting", "modified": new DateTime(2021, 6, 22, 10, 50, 24, 292000000, 0, null), "broaderUrl": null, "identifier": "77c376dd-009b-4460-a94c-ade21b1aa772", "image": "https://alastair.trompa-solid.upf.edu/annotation-images/slur.png", - "additionalProperty": [], "creator": "https://alastair.trompa-solid.upf.edu/profile/card#me", "created": new DateTime(2021, 6, 22, 10, 50, 24, 292000000, 0, null), "additionalType": [ "https://vocab.trompamusic.eu/vocab#AnnotationMotivationCollectionElement", "http://www.w3.org/ns/oa#Motivation" ], - "potentialAction": [], - "inDefinedTermSet": [ + "hasDefinedTerm": [ "http://localhost:4000/7c0e9ac0-942a-422a-89b8-884444da6b5a" ], - "termCode": "Slur" + "name": "Performance Directions" } it('generates jsonld using broaderMotivation', function() { - const response = transformJsonLD("DefinedTerm", sampleDocument); + const response = transformJsonLD("DefinedTermSet", sampleDocument, "http://localhost:4000"); expect(response["skos:broader"]).toEqual("oa:commenting"); }) it('generates jsonld using broaderUrl', function() { sampleDocument["broaderMotivation"] = null; sampleDocument["broaderUrl"] = "https://example.com#motivation"; - const response = transformJsonLD("DefinedTerm", sampleDocument); + const response = transformJsonLD("DefinedTermSet", sampleDocument, "http://localhost:4000"); expect(response["skos:broader"]).toEqual("https://example.com#motivation"); }) it('Adds oa:Motivation additionalType if broader enum is present and type is not set', function () { - const definedTerm = { + const definedTermSet = { "broaderMotivation": "commenting", "broaderUrl": null, - "additionalProperty": [], "additionalType": [ "https://vocab.trompamusic.eu/vocab#AnnotationMotivationCollectionElement" ], - "inDefinedTermSet": [ + "hasDefinedTerm": [ "http://localhost:4000/7c0e9ac0-942a-422a-89b8-884444da6b5a" ], - "termCode": "Slur" + "name": "Performance Directions" } - const result = preprocessDefinedTerm(definedTerm); + const result = preprocessDefinedTermSet(definedTermSet); expect(result["additionalType"].includes("https://www.w3.org/ns/oa#Motivation")).toEqual(true); expect(result["additionalType"].length).toEqual(2); }); it('Adds oa:Motivation additionalType if broader url is present and type is not set', function () { - const definedTerm = { + const definedTermSet = { "broaderMotivation": null, "broaderUrl": "https://example.com#Motivation", - "additionalProperty": [], "additionalType": [ "https://vocab.trompamusic.eu/vocab#AnnotationMotivationCollectionElement" ], - "inDefinedTermSet": [ + "hasDefinedTerm": [ "http://localhost:4000/7c0e9ac0-942a-422a-89b8-884444da6b5a" ], - "termCode": "Slur" + "name": "Performance Directions" } - const result = preprocessDefinedTerm(definedTerm); + const result = preprocessDefinedTermSet(definedTermSet); expect(result["additionalType"].includes("https://www.w3.org/ns/oa#Motivation")).toEqual(true); expect(result["additionalType"].length).toEqual(2); }); it("Doesn't add oa:Motivation additionalType if it already exists", function () { - const definedTerm = { + const definedTermSet = { "broaderMotivation": null, "broaderUrl": "https://example.com#Motivation", "additionalProperty": [], @@ -80,44 +76,44 @@ describe('definedTermTest', function () { "https://vocab.trompamusic.eu/vocab#AnnotationMotivationCollectionElement", "http://www.w3.org/ns/oa#Motivation" ], - "inDefinedTermSet": [ + "hasDefinedTerm": [ "http://localhost:4000/7c0e9ac0-942a-422a-89b8-884444da6b5a" ], - "termCode": "Slur" + "name": "Performance Directions" } - const result = preprocessDefinedTerm(definedTerm); + const result = preprocessDefinedTermSet(definedTermSet); expect(result["additionalType"].includes("http://www.w3.org/ns/oa#Motivation")).toEqual(true); expect(result["additionalType"].includes("https://www.w3.org/ns/oa#Motivation")).toEqual(false); expect(result["additionalType"].length).toEqual(2); }); it("Doesn't add oa:Motivation additionalType if broader isn't set", function () { - const definedTerm = { + const definedTermSet = { "broaderMotivation": null, "broaderUrl": null, "additionalProperty": [], "additionalType": null, - "inDefinedTermSet": [ + "hasDefinedTerm": [ "http://localhost:4000/7c0e9ac0-942a-422a-89b8-884444da6b5a" ], - "termCode": "Slur" + "name": "Performance Directions" } - const result = preprocessDefinedTerm(definedTerm); + const result = preprocessDefinedTermSet(definedTermSet); expect(result["additionalType"]).toEqual(null); }); it('Prefixes motivation enums with oa: namespace', function () { - const definedTerm = { + const definedTermSet = { "broaderMotivation": "commenting", "broaderUrl": null, "additionalProperty": [], "additionalType": null, - "inDefinedTermSet": [ + "hasDefinedTerm": [ "http://localhost:4000/7c0e9ac0-942a-422a-89b8-884444da6b5a" ], - "termCode": "Slur" + "name": "Performance Directions" } - const result = preprocessDefinedTerm(definedTerm); + const result = preprocessDefinedTermSet(definedTermSet); expect(result["broaderMotivation"]).toEqual("oa:commenting"); }); }); diff --git a/src/routes/helpers/transformers.js b/src/routes/helpers/transformers.js index 30357b3..2e47cd0 100644 --- a/src/routes/helpers/transformers.js +++ b/src/routes/helpers/transformers.js @@ -62,8 +62,8 @@ export const transformJsonLD = (type, data, baseUrl) => { throw new Error(`JSON LD not supported for type "${type}"`) } - if (type === "DefinedTerm") { - data = preprocessDefinedTerm(data); + if (type === "DefinedTermSet") { + data = preprocessDefinedTermSet(data); } if (type === "ItemList") { @@ -222,14 +222,14 @@ export function preprocessItemList(data, baseUrl) { /** - * Preprocess data for a DefinedTerm before converting to JSON-LD. - * If a DefinedTerm has a motivation set (either broaderMotivation or + * Preprocess data for a DefinedTermSet before converting to JSON-LD. + * If a DefinedTermSet has a motivation set (either broaderMotivation or * broaderUrl), then add oa:Motivation to additionalTypes. * * If broaderMotivation is set (graphql enum), prefix it with the oa: namespace. * @param data the result from document.getDocument */ -export function preprocessDefinedTerm(data) { +export function preprocessDefinedTermSet(data) { const additionalType = data["additionalType"]; const hasMotivationAdditionalType = additionalType && (additionalType.includes("http://www.w3.org/ns/oa#Motivation") || additionalType.includes("https://www.w3.org/ns/oa#Motivation")) diff --git a/src/schema/type/Annotation.graphql b/src/schema/type/Annotation.graphql index 7cae0ae..8d740ae 100644 --- a/src/schema/type/Annotation.graphql +++ b/src/schema/type/Annotation.graphql @@ -80,10 +80,10 @@ type Annotation implements ThingInterface & ProvenanceEntityInterface { "An external resource that this annotation is about" targetUrl: [String] # An annotation should always have a motivation. If you want to use a more specific - # annotation from a toolkit (a DefinedTerm) then you can include it, but you should + # annotation from a toolkit (a DefinedTermSet) then you can include it, but you should # still add the base motivation. "http://www.w3.org/ns/oa#Motivation" - motivationDefinedTerm: DefinedTerm @relation(name: "ANNOTATON_MOTIVATION_DEFINED_TERM", direction: OUT) + motivationDefinedTermSet: DefinedTermSet @relation(name: "ANNOTATON_MOTIVATION_DEFINED_TERM_SET", direction: OUT) "http://www.w3.org/ns/oa#Motivation" motivation: AnnotationMotivation! motivationUrl: [String] diff --git a/src/schema/type/DefinedTerm.graphql b/src/schema/type/DefinedTerm.graphql index 39a0505..e858f01 100644 --- a/src/schema/type/DefinedTerm.graphql +++ b/src/schema/type/DefinedTerm.graphql @@ -69,16 +69,4 @@ type DefinedTerm implements ThingInterface { # TODO: This should only be a relation to one DefinedTermSet "https://pending.schema.org/inDefinedTermSet" inDefinedTermSet: [DefinedTermSet] @relation(name: "HAS_DEFINED_TERM", direction: IN) - - ####################### - ### SKOS properties ### - # When we use a DefinedTerm to refer to an annotation motivation, we have to add the motivation - # of which this term is a more specific version of to skos:broader. If you do this, you should - # also add http://www.w3.org/ns/oa#Motivation as an additionalType - # If this DefinedTerm has a standard motivations as its broader value, set an enum in - # broaderMotivation. If it's a third party URL, use broaderUrl. - "http://www.w3.org/2004/02/skos/core#broader" - broaderUrl: String - "http://www.w3.org/2004/02/skos/core#broader" - broaderMotivation: AnnotationMotivation } diff --git a/src/schema/type/DefinedTermSet.graphql b/src/schema/type/DefinedTermSet.graphql index e9f8019..657639b 100644 --- a/src/schema/type/DefinedTermSet.graphql +++ b/src/schema/type/DefinedTermSet.graphql @@ -74,6 +74,16 @@ type DefinedTermSet implements CreativeWorkInterface & ThingInterface { "http://www.w3.org/2004/02/skos/core#relatedMatch" relatedMatch: [ThingInterface] @relation(name: "RELATED_MATCH", direction: OUT) + # When we use a DefinedTermSet to refer to an annotation motivation, we have to add the motivation + # of which this term is a more specific version of to skos:broader. If you do this, you should + # also add http://www.w3.org/ns/oa#Motivation as an additionalType + # If this DefinedTerm has a standard motivations as its broader value, set an enum in + # broaderMotivation. If it's a third party URL, use broaderUrl. + "http://www.w3.org/2004/02/skos/core#broader" + broaderUrl: String + "http://www.w3.org/2004/02/skos/core#broader" + broaderMotivation: AnnotationMotivation + ############################################ ### ProvenanceEntityInterface properties ### "http://www.w3.org/ns/prov#wasGeneratedBy"