Skip to content

Commit d80342e

Browse files
committed
Continue implementation on Skohub provider (#29)
1 parent cf2cfb5 commit d80342e

File tree

4 files changed

+227
-160
lines changed

4 files changed

+227
-160
lines changed

src/providers/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ReconciliationApiProvider from "./reconciliation-api-provider.js"
77
import LabelSearchSuggestionProvider from "./label-search-suggestion-provider.js"
88
import SkosmosApiProvider from "./skosmos-api-provider.js"
99
import LocApiProvider from "./loc-api-provider.js"
10+
import SkohubProvider from "./skohub-provider.js"
1011

1112
export {
1213
BaseProvider,
@@ -18,4 +19,5 @@ export {
1819
LabelSearchSuggestionProvider,
1920
SkosmosApiProvider,
2021
LocApiProvider,
22+
SkohubProvider,
2123
}

src/providers/skohub-provider.js

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import BaseProvider from "./base-provider.js"
2+
import * as _ from "../utils/lodash.js"
3+
import * as errors from "../errors/index.js"
4+
import { listOfCapabilities } from "../utils/index.js"
5+
6+
/**
7+
* ```json
8+
* {
9+
* "uri": "http://coli-conc.gbv.de/registry/skohub.io",
10+
* "provider": "Skohub",
11+
* "schemes": [
12+
* {
13+
* "uri": "https://w3id.org/class/esc/scheme",
14+
* }
15+
* ]
16+
* }
17+
*/
18+
export default class SkohubProvider extends BaseProvider {
19+
20+
_prepare() {
21+
this.has.schemes = true
22+
this.has.top = true
23+
this.has.data = true
24+
this.has.concepts = true
25+
this.has.narrower = true
26+
this.has.ancestors = true
27+
this.has.suggest = false
28+
this.has.search = false
29+
// Explicitly set other capabilities to false
30+
listOfCapabilities.filter(c => !this.has[c]).forEach(c => {
31+
this.has[c] = false
32+
})
33+
}
34+
35+
_setup() {
36+
this._jskos.schemes = this.schemes || []
37+
}
38+
39+
async getSchemes({ ...config }) {
40+
const { schemes } = this._jskos
41+
42+
for (let i=0; i<schemes.length; i++) {
43+
schemes[i] = await this._loadScheme(schemes[i], config)
44+
}
45+
46+
return schemes
47+
}
48+
49+
async _loadScheme(scheme, config) {
50+
const { uri, topConcepts } = scheme
51+
52+
if (!uri || topConcepts) {
53+
return scheme
54+
}
55+
56+
const data = await this.axios({ ...config, url: `${uri}.json` })
57+
58+
// TODO: if not found
59+
60+
if (data.id !== uri) {
61+
throw new errors.InvalidRequestError({ message: "Skohub URL did not return expected concept scheme" })
62+
}
63+
64+
const { title, preferredNamespaceUri, hasTopConcept, description } = data //, issued, created, modified, creator, publisher } = data
65+
66+
scheme.prefLabel = title
67+
scheme.namespace = preferredNamespaceUri
68+
scheme.topConcepts = (hasTopConcept || []).map(c => this._mapConcept(c))
69+
70+
// const hasNarrower = scheme.topConcepts.find(c => c.narrower && c.narrower.length)
71+
72+
scheme.concepts = [null]
73+
// scheme.concepts = [...scheme.topConcepts]
74+
// if (hasNarrower) {
75+
// scheme.concepts.push(null)
76+
// }
77+
78+
// TODO: map remaining fields
79+
80+
if (description) {
81+
scheme.definition = description
82+
// scopeNote values in JSKOS are arrays
83+
Object.keys(scheme.definition).forEach(key => {
84+
scheme.definition[key] = [scheme.definition[key]]
85+
})
86+
}
87+
88+
// remove fields without value
89+
for (let key of Object.keys(scheme).filter(key => !scheme[key])) {
90+
delete scheme[key]
91+
}
92+
93+
return scheme
94+
}
95+
96+
async getTop({ scheme, ...config }) {
97+
if (!scheme || !scheme.uri) {
98+
throw new errors.InvalidOrMissingParameterError({ parameter: "scheme", message: "Missing scheme URI" })
99+
}
100+
101+
scheme = this._jskos.schemes.find(s => s.uri === scheme.uri)
102+
if (scheme) {
103+
scheme = await this._loadScheme(scheme, config)
104+
return scheme.topConcepts
105+
} else {
106+
return []
107+
}
108+
}
109+
110+
async getConcepts({ concepts, ...config }) {
111+
if (!_.isArray(concepts)) {
112+
concepts = [concepts]
113+
}
114+
concepts = concepts.map(c => ({ uri: c.uri, inScheme: c.inScheme }))
115+
116+
const newConcepts = []
117+
for (let concept of concepts) {
118+
const { uri, inScheme } = concept
119+
120+
if (!(inScheme && inScheme[0] && inScheme[0].uri)) {
121+
throw new errors.InvalidOrMissingParameterError({ parameter: "inScheme", message: "Missing inScheme URI" })
122+
}
123+
124+
var scheme = this._jskos.schemes.find(s => s.uri === inScheme[0].uri)
125+
if (scheme) {
126+
scheme = await this._loadScheme(scheme, config)
127+
}
128+
if (!scheme) {
129+
continue
130+
}
131+
132+
const found = scheme.concepts.find(c => (c && c.uri === uri))
133+
134+
if (found) {
135+
newConcepts.push(found)
136+
} else if (_.last(scheme.concepts) === null) {
137+
try {
138+
const loaded = await this._loadConcept(uri)
139+
if (loaded) {
140+
newConcepts.push(loaded)
141+
scheme.concepts = [loaded].concat(scheme.concepts)
142+
}
143+
} catch (error) {
144+
// Ignore error
145+
}
146+
}
147+
}
148+
149+
return newConcepts
150+
}
151+
152+
async getAncestors({ concept, ...config }) {
153+
if (!concept || !concept.uri) {
154+
throw new errors.InvalidOrMissingParameterError({ parameter: "concept" })
155+
}
156+
if (concept.ancestors && concept.ancestors[0] !== null) {
157+
return concept.ancestors
158+
}
159+
concept = (await this.getConcepts({ concepts: [concept], ...config }))[0]
160+
if (!concept || !concept.broader || !concept.broader.length) {
161+
return []
162+
}
163+
const broader = concept.broader[0]
164+
broader.inScheme = concept.inScheme
165+
return [broader].concat(await this.getAncestors({ concept: broader, ...config })).map(c => ({ uri: c.uri }))
166+
}
167+
168+
async getNarrower({ concept, ...config }) {
169+
if (!concept || !concept.uri) {
170+
throw new errors.InvalidOrMissingParameterError({ parameter: "concept" })
171+
}
172+
if (concept.narrower && concept.narrower[0] !== null) {
173+
return concept.narrower
174+
}
175+
concept = await this._loadConcept(concept.uri, config)
176+
return concept.narrower
177+
}
178+
179+
async _loadConcept(uri, config) {
180+
const data = await this.axios({ ...config, url: `${uri}.json` })
181+
182+
// TODO: if not found
183+
184+
if (data.id !== uri) {
185+
throw new errors.InvalidRequestError({ message: "Skohub URL did not return expected concept URI" })
186+
}
187+
188+
return this._mapConcept(data)
189+
}
190+
191+
_mapConcept(data) {
192+
const concept = { uri: data.id }
193+
194+
concept.prefLabel = data.prefLabel
195+
concept.narrower = (data.narrower || []).map(c => this._mapConcept(c))
196+
concept.notation = data.notation || []
197+
if (data.broader && data.broader.id) {
198+
concept.broader = [{ uri: data.broader.id }]
199+
}
200+
if (data.inScheme && data.inScheme.id) {
201+
concept.inScheme = [{ uri: data.inScheme.id }]
202+
}
203+
if (data.scopeNote) {
204+
concept.scopeNote = data.scopeNote
205+
// scopeNote values in JSKOS are arrays
206+
Object.keys(concept.scopeNote).forEach(key => {
207+
concept.scopeNote[key] = [concept.scopeNote[key]]
208+
})
209+
}
210+
211+
return concept
212+
}
213+
}
214+
215+
SkohubProvider.providerName = "Skohub"

src/providers/skohub.js

Lines changed: 0 additions & 151 deletions
This file was deleted.

0 commit comments

Comments
 (0)