/
resources.ts
112 lines (98 loc) · 2.92 KB
/
resources.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { NamedNode, Term, DatasetCoreFactory } from 'rdf-js'
import type { GraphPointer } from 'clownface'
import { Describe, DESCRIBE, SELECT } from '@tpluscode/sparql-builder'
import { toSparql } from 'clownface-shacl-path'
import { StreamClient } from 'sparql-http-client'
import fromStream from 'rdf-dataset-ext/fromStream.js'
import rdf from '@zazuko/env'
import { bottomUp } from './lib/patterns.js'
import { requiredPath } from './lib/firstLevel.js'
/**
* Creates a query to find an example resource found at the given level in hierarchy
*
* @param {GraphPointer} hierarchyLevel it must be a pointer to the full hierarchy dataset
*/
export function example(hierarchyLevel: GraphPointer): Describe | null {
const patterns = bottomUp(hierarchyLevel, {
firstLevel: requiredPath,
})
if (!patterns) {
return null
}
return DESCRIBE`?this`.WHERE`
${patterns}
filter(isiri(?this))
`.LIMIT(1)
}
interface ChildrenOptions {
limit?: number
offset?: number
orderBy?: NamedNode[]
}
interface Children {
query: Describe
execute(
client: StreamClient,
rdf: DatasetCoreFactory
): Promise<{ children: GraphPointer[]; parent: GraphPointer }>
}
/**
* Creates a query to find a set of example resources found at the given level in hierarchy
*
* The results can be paged, ordered and sorted
*
* @param {GraphPointer} level it must be a pointer to the full hierarchy dataset
* @param {Term} parent
*/
export function children(
level: GraphPointer,
parent: Term,
{ limit = 1, offset = 0, orderBy = [] }: ChildrenOptions = {},
): Children | null {
const patterns = bottomUp(level, {
firstLevel: requiredPath,
})
if (!patterns) {
return null
}
const path = level.out(rdf.ns.sh.path)
const selectChildTerms = SELECT.DISTINCT`?this`.WHERE`
${parent} ${toSparql(path)} ?this .
${patterns}
filter(isiri(?this))`
.LIMIT(limit)
.OFFSET(offset)
const orderedQuery = orderBy.reduce((query, property, index) => {
const orderVar = rdf.variable(`order${index}`)
return query.WHERE`OPTIONAL { ?this ${property} ${orderVar} }`
.ORDER()
.BY(orderVar)
}, selectChildTerms)
const query = DESCRIBE`${parent} ?this`.WHERE`
{
${orderedQuery}
}
`
return {
query,
execute: async function (client: StreamClient, $rdf: DatasetCoreFactory) {
const stream = await query.execute(client.query)
const dataset = await fromStream($rdf.dataset(), stream)
const parentNode = rdf.clownface({ dataset, term: parent })
const inversePath = path.out(rdf.ns.sh.inversePath).term
if (inversePath) {
return {
parent: parentNode,
children: parentNode.in(inversePath).toArray(),
}
}
return {
parent: parentNode,
children: parentNode
.out(path.term)
.filter(child => child.out().values.length > 0)
.toArray(),
}
},
}
}