Skip to content
This repository has been archived by the owner on Jun 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #207 from trompamusic/feat/jsonld-output
Browse files Browse the repository at this point in the history
Improve JSON-LD output for itemlists
  • Loading branch information
ChristiaanScheermeijer authored Jul 13, 2021
2 parents f02a3cb + 09a2ca1 commit ec54f6b
Show file tree
Hide file tree
Showing 14 changed files with 422 additions and 23 deletions.
67 changes: 67 additions & 0 deletions src/routes/helpers/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { driver } from '../../driver'
import GetTypeQuery from '../../queries/GetTypeQuery'
import GetFullNodeQuery from '../../queries/GetFullNodeQuery'
import SchemaHelper from '../../helpers/SchemaHelper'
import fs from 'fs'
import path from 'path'

export const getDocument = (identifier, host) => {
const session = driver.session()
Expand Down Expand Up @@ -30,6 +32,15 @@ export const getDocument = (identifier, host) => {
return Promise.reject(new Error('Node not found'))
}

// Special-case some types to perform a custom query to get additional relations in a single query
// Unfortunately neo4j-graphql-js doesn't provide an easy way to do this, so we do the following:
// Start up the CE with DEBUG=neo4j-graphql-js
// Take the file ./queries/TYPE.query and run it in the web interface
// Copy the query which is written to the console to ./queries/TYPE.cypher
if (type === "ItemList") {
return getItemList(session, identifier).then(data => ({data, type}));
}

return getNodeProperties(session, type, identifier, host)
.then(data => ({ data, type }))
}, reason => {
Expand All @@ -41,6 +52,62 @@ export const getDocument = (identifier, host) => {
})
}

const getItemList = (session, identifier) => {
const query = fs.readFileSync(path.resolve(__dirname, './queries/ItemList.cypher'), {encoding:'utf8', flag:'r'});
return session.run(query, {identifier: identifier, ThingInterface_derivedTypes: [
"Action",
"AddAction",
"Annotation",
"Article",
"Audience",
"AudioObject",
"ControlAction",
"DataDownload",
"Dataset",
"DefinedTerm",
"DefinedTermSet",
"DeleteAction",
"DigitalDocument",
"DigitalDocumentPermission",
"EntryPoint",
"Event",
"ImageObject",
"Intangible",
"ItemList",
"ListItem",
"MediaObject",
"MusicAlbum",
"MusicComposition",
"MusicGroup",
"MusicPlaylist",
"MusicRecording",
"Occupation",
"Organization",
"Person",
"Place",
"Product",
"Property",
"PropertyValue",
"PropertyValueSpecification",
"Rating",
"ReplaceAction",
"Review",
"SoftwareApplication",
"VideoObject"
]})
.then(fullResult => {
if (fullResult.records.length) {
return fullResult.records[0].get('itemList')
} else {
return undefined;
}
})
.catch(function (error) {
info('_getItemList caught error: ' + error.message)
throw error
})
}

const getNodeProperties = (session, type, identifier, host) => {
const getFullNodeQuery = new GetFullNodeQuery(type, identifier, host, 2)
const query = getFullNodeQuery.query
Expand Down
3 changes: 0 additions & 3 deletions src/routes/helpers/jsonld/DefinedTerm.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,6 @@
],
"inDefinedTermSet": [
"https://pending.schema.org/inDefinedTermSet"
],
"broader": [
"http://www.w3.org/2004/02/skos/core#broader"
]
}
}
6 changes: 6 additions & 0 deletions src/routes/helpers/jsonld/DefinedTermSet.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
}
}
1 change: 1 addition & 0 deletions src/routes/helpers/jsonld/ItemList.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"http://www.w3.org/ns/ldp#BasicContainer"
]
},
"nonRelationalProperties": ["itemListElement"],
"properties": {
"identifier": [
"http://purl.org/dc/terms/identifier",
Expand Down
2 changes: 1 addition & 1 deletion src/routes/helpers/jsonld/ListItem.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"https://schema.org/ListItem"
]
},
"relationalProperties": ["itemUrl"],
"relationalProperties": ["itemUrl", "item"],
"properties": {
"identifier": [
"http://purl.org/dc/terms/identifier",
Expand Down
1 change: 1 addition & 0 deletions src/routes/helpers/queries/ItemList.cypher
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MATCH (`itemList`:`ItemList` {identifier:$identifier}) RETURN `itemList` { .identifier , .name , .creator ,created: { formatted: toString(`itemList`.created) },modified: { formatted: toString(`itemList`.modified) }, .additionalType , .itemListOrder ,itemListElement: [(`itemList`)-[:`ITEM_LIST_ELEMENT`]->(`itemList_itemListElement`:`ThingInterface`) WHERE ("Action" IN labels(`itemList_itemListElement`) OR "AddAction" IN labels(`itemList_itemListElement`) OR "Annotation" IN labels(`itemList_itemListElement`) OR "Article" IN labels(`itemList_itemListElement`) OR "Audience" IN labels(`itemList_itemListElement`) OR "AudioObject" IN labels(`itemList_itemListElement`) OR "ControlAction" IN labels(`itemList_itemListElement`) OR "DataDownload" IN labels(`itemList_itemListElement`) OR "Dataset" IN labels(`itemList_itemListElement`) OR "DefinedTerm" IN labels(`itemList_itemListElement`) OR "DefinedTermSet" IN labels(`itemList_itemListElement`) OR "DeleteAction" IN labels(`itemList_itemListElement`) OR "DigitalDocument" IN labels(`itemList_itemListElement`) OR "DigitalDocumentPermission" IN labels(`itemList_itemListElement`) OR "EntryPoint" IN labels(`itemList_itemListElement`) OR "Event" IN labels(`itemList_itemListElement`) OR "ImageObject" IN labels(`itemList_itemListElement`) OR "Intangible" IN labels(`itemList_itemListElement`) OR "ItemList" IN labels(`itemList_itemListElement`) OR "ListItem" IN labels(`itemList_itemListElement`) OR "MediaObject" IN labels(`itemList_itemListElement`) OR "MusicAlbum" IN labels(`itemList_itemListElement`) OR "MusicComposition" IN labels(`itemList_itemListElement`) OR "MusicGroup" IN labels(`itemList_itemListElement`) OR "MusicPlaylist" IN labels(`itemList_itemListElement`) OR "MusicRecording" IN labels(`itemList_itemListElement`) OR "Occupation" IN labels(`itemList_itemListElement`) OR "Organization" IN labels(`itemList_itemListElement`) OR "Person" IN labels(`itemList_itemListElement`) OR "Place" IN labels(`itemList_itemListElement`) OR "Product" IN labels(`itemList_itemListElement`) OR "Property" IN labels(`itemList_itemListElement`) OR "PropertyValue" IN labels(`itemList_itemListElement`) OR "PropertyValueSpecification" IN labels(`itemList_itemListElement`) OR "Rating" IN labels(`itemList_itemListElement`) OR "ReplaceAction" IN labels(`itemList_itemListElement`) OR "Review" IN labels(`itemList_itemListElement`) OR "SoftwareApplication" IN labels(`itemList_itemListElement`) OR "VideoObject" IN labels(`itemList_itemListElement`)) | head([`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Action" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Action", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "AddAction" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "AddAction", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Annotation" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Annotation", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Article" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Article", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Audience" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Audience", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "AudioObject" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "AudioObject", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "ControlAction" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "ControlAction", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "DataDownload" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "DataDownload", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Dataset" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Dataset", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "DefinedTerm" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "DefinedTerm", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "DefinedTermSet" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "DefinedTermSet", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "DeleteAction" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "DeleteAction", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "DigitalDocument" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "DigitalDocument", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "DigitalDocumentPermission" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "DigitalDocumentPermission", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "EntryPoint" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "EntryPoint", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Event" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Event", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "ImageObject" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "ImageObject", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Intangible" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Intangible", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "ItemList" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "ItemList", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "ListItem" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "ListItem", .itemUrl ,item: [(`itemList_itemListElement`)-[:`ITEM`]->(`itemList_itemListElement_item`:`ThingInterface`) | `itemList_itemListElement_item` {FRAGMENT_TYPE: head( [ label IN labels(`itemList_itemListElement_item`) WHERE label IN $ThingInterface_derivedTypes ] ), .identifier }] , .position , .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "MediaObject" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "MediaObject", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "MusicAlbum" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "MusicAlbum", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "MusicComposition" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "MusicComposition", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "MusicGroup" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "MusicGroup", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "MusicPlaylist" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "MusicPlaylist", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "MusicRecording" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "MusicRecording", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Occupation" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Occupation", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Organization" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Organization", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Person" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Person", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Place" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Place", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Product" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Product", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Property" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Property", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "PropertyValue" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "PropertyValue", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "PropertyValueSpecification" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "PropertyValueSpecification", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Rating" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Rating", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "ReplaceAction" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "ReplaceAction", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "Review" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "Review", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "SoftwareApplication" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "SoftwareApplication", .identifier , .name , .description , .image , .url }] + [`itemList_itemListElement` IN [`itemList_itemListElement`] WHERE "VideoObject" IN labels(`itemList_itemListElement`) | `itemList_itemListElement` { FRAGMENT_TYPE: "VideoObject", .identifier , .name , .description , .image , .url }])] } AS `itemList`
30 changes: 30 additions & 0 deletions src/routes/helpers/queries/ItemList.query
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
query {
ItemList(identifier:"a1a839c0-4b6b-49e3-ac11-384568ce0caf") {
identifier
name
creator
created {
formatted
}
modified {
formatted
}
itemListOrder
additionalType
itemListElement {
__typename
identifier
name
description
image
url
... on ListItem {
itemUrl
item {
identifier
}
position
}
}
}
}
46 changes: 46 additions & 0 deletions src/routes/helpers/testdata/itemlist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"identifier": "a1a839c0-4b6b-49e3-ac11-384568ce0caf",
"creator": "https://testuser.trompa-solid.upf.edu/profile/card#me",
"itemListElement": [
{
"identifier": "bb418c6b-7667-4559-96de-5716d9d52e2e",
"image": null,
"item": [
{
"FRAGMENT_TYPE": "Annotation",
"identifier": "e03dd66d-17ba-4d91-a409-d1eb2cb3d3bb"
}
],
"name": null,
"description": null,
"FRAGMENT_TYPE": "ListItem",
"position": null,
"url": null,
"itemUrl": null
},
{
"identifier": "551877a6-c61b-4fc7-8174-17247d460823",
"image": null,
"item": null,
"name": null,
"description": null,
"FRAGMENT_TYPE": "ListItem",
"position": null,
"url": null,
"itemUrl": "https://example.com/externalItem"
},
{
"identifier": "f3ed1b21-cc30-43be-805a-ce2b56b78e09",
"name": null,
"description": null,
"FRAGMENT_TYPE": "DigitalDocument",
"image": null,
"url": null
}
],
"additionalType": [ "https://vocab.trompamusic.eu/vocab#AnnotationSession" ],
"created": { "formatted": "2021-06-22T13:47:10.693Z" },
"name": "Some session",
"modified": { "formatted": "2021-06-22T13:47:10.693Z" },
"itemListOrder": "ItemListUnordered"
}
Loading

0 comments on commit ec54f6b

Please sign in to comment.