-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
query_engine.ts
152 lines (136 loc) · 4 KB
/
query_engine.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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import {
BindingsFactory,
type Context,
type IQueryEngine,
QuadFactory,
type RDF,
RDFJSON,
} from "../rdf.ts";
import {
ArrayIterator,
MappingIterator,
TreeIterator,
} from "../asynciterator.ts";
type QueryResponseFormat = {
"application/sparql-results+json": RDFJSON.SparqlResultsJsonFormat;
"application/rdf+json": RDFJSON.RdfJsonFormat;
};
export class QueryEngine implements IQueryEngine {
protected getSparqlEndpoint(context?: Context) {
if (!context) {
throw new Error(
"No context supplied to QueryEngine. You need to create a default context or pass one to a resource.",
);
}
if (!Array.isArray(context.sources) || context.sources.length < 1) {
throw new Error(
"Invalid context `sources` attribute defined. You need to provide a URL to a SPARQL endpoint to query.",
);
}
if (context.sources.length > 1) {
throw new Error(
"This query engine supports only one data source, multiple defined in `sources` property in context.",
);
}
const source = context.sources[0];
if (typeof source === "string") {
return source;
}
if ("value" in source && typeof source.value === "string") {
if ("type" in source) {
if (source.type === "sparql") {
return source.value;
}
} else {
return source.value;
}
}
throw new Error(
"Invalid SPARQL source defined - please provide URL to a SPARQL endpoint to query.",
);
}
protected getFetch(context?: Context) {
return context && context.fetch ? context.fetch : fetch;
}
async query<
ResponseType extends keyof QueryResponseFormat,
ResponseFormat = QueryResponseFormat[ResponseType],
>(
query: string,
responseType: ResponseType,
context?: Context,
) {
const endpoint = this.getSparqlEndpoint(context);
const fetchFn = this.getFetch(context);
const response = await fetchFn(endpoint, {
method: "POST",
headers: {
"accept": responseType,
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
body: new URLSearchParams({
query,
}),
});
const json = await response.json();
return json as ResponseFormat;
}
async queryBindings(
query: string,
context?: Context,
): Promise<RDF.ResultStream<RDF.Bindings>> {
const json = await this.query(
query,
"application/sparql-results+json",
context,
);
if (!Array.isArray(json.results?.bindings)) {
throw new Error("Bindings SPARQL query result not found");
}
const bindingsFactory = new BindingsFactory();
const bindingsIterator = new ArrayIterator<RDFJSON.Bindings>(
json.results!.bindings,
);
// TODO: review the unknown type cast
return new MappingIterator(
bindingsIterator,
(i) => bindingsFactory.fromJson(i),
) as unknown as RDF.ResultStream<RDF.Bindings>;
}
async queryBoolean(
query: string,
context?: Context,
): Promise<boolean> {
const json = await this.query(
query,
"application/sparql-results+json",
context,
);
if ("boolean" in json) {
return Boolean(json.boolean);
}
throw new Error("Boolean SPARQL query result not found");
}
async queryQuads(
query: string,
context?: Context,
): Promise<RDF.ResultStream<RDF.Quad>> {
const json = await this.query(query, "application/rdf+json", context);
if (!(json?.constructor === Object)) {
throw new Error("Quads SPARQL query result not found");
}
const quadFactory = new QuadFactory();
const treeIterator = new TreeIterator<RDFJSON.Term>(json);
// TODO: review the unknown type cast
return new MappingIterator(
treeIterator,
(i) => quadFactory.fromJson(i as [string, string, RDFJSON.Term]),
) as unknown as RDF.ResultStream<RDF.Quad>;
}
async queryVoid(
query: string,
context?: Context,
): Promise<void> {
await this.query(query, "application/sparql-results+json", context);
}
}