javascript-solid-server 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +6 -1
- package/README.md +159 -11
- package/benchmark.js +145 -249
- package/bin/jss.js +208 -0
- package/package.json +21 -5
- package/src/config.js +185 -0
- package/src/handlers/resource.js +103 -34
- package/src/patch/sparql-update.js +401 -0
- package/src/server.js +21 -10
- package/src/utils/conditional.js +153 -0
- package/test/conditional.test.js +250 -0
- package/test/conformance.test.js +349 -0
- package/test/sparql-update.test.js +219 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPARQL Update Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests SPARQL Update support via PATCH method.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, before, after } from 'node:test';
|
|
8
|
+
import assert from 'node:assert';
|
|
9
|
+
import {
|
|
10
|
+
startTestServer,
|
|
11
|
+
stopTestServer,
|
|
12
|
+
request,
|
|
13
|
+
createTestPod,
|
|
14
|
+
assertStatus
|
|
15
|
+
} from './helpers.js';
|
|
16
|
+
|
|
17
|
+
describe('SPARQL Update', () => {
|
|
18
|
+
before(async () => {
|
|
19
|
+
await startTestServer();
|
|
20
|
+
await createTestPod('sparqltest');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
after(async () => {
|
|
24
|
+
await stopTestServer();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('INSERT DATA', () => {
|
|
28
|
+
it('should insert a triple into existing resource', async () => {
|
|
29
|
+
// Create a resource
|
|
30
|
+
await request('/sparqltest/public/insert-test.json', {
|
|
31
|
+
method: 'PUT',
|
|
32
|
+
headers: { 'Content-Type': 'application/ld+json' },
|
|
33
|
+
body: JSON.stringify({ '@id': '#item', 'http://example.org/name': 'Original' }),
|
|
34
|
+
auth: 'sparqltest'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Insert new data via SPARQL Update
|
|
38
|
+
const sparql = `
|
|
39
|
+
PREFIX ex: <http://example.org/>
|
|
40
|
+
INSERT DATA {
|
|
41
|
+
<#item> ex:status "active" .
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const res = await request('/sparqltest/public/insert-test.json', {
|
|
46
|
+
method: 'PATCH',
|
|
47
|
+
headers: { 'Content-Type': 'application/sparql-update' },
|
|
48
|
+
body: sparql,
|
|
49
|
+
auth: 'sparqltest'
|
|
50
|
+
});
|
|
51
|
+
assertStatus(res, 204);
|
|
52
|
+
|
|
53
|
+
// Verify the data was inserted
|
|
54
|
+
const getRes = await request('/sparqltest/public/insert-test.json');
|
|
55
|
+
const data = await getRes.json();
|
|
56
|
+
assert.strictEqual(data['http://example.org/status'], 'active');
|
|
57
|
+
assert.strictEqual(data['http://example.org/name'], 'Original');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should insert multiple triples', async () => {
|
|
61
|
+
await request('/sparqltest/public/multi-insert.json', {
|
|
62
|
+
method: 'PUT',
|
|
63
|
+
headers: { 'Content-Type': 'application/ld+json' },
|
|
64
|
+
body: JSON.stringify({ '@id': '#thing' }),
|
|
65
|
+
auth: 'sparqltest'
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const sparql = `
|
|
69
|
+
PREFIX ex: <http://example.org/>
|
|
70
|
+
INSERT DATA {
|
|
71
|
+
<#thing> ex:prop1 "value1" .
|
|
72
|
+
<#thing> ex:prop2 "value2" .
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
const res = await request('/sparqltest/public/multi-insert.json', {
|
|
77
|
+
method: 'PATCH',
|
|
78
|
+
headers: { 'Content-Type': 'application/sparql-update' },
|
|
79
|
+
body: sparql,
|
|
80
|
+
auth: 'sparqltest'
|
|
81
|
+
});
|
|
82
|
+
assertStatus(res, 204);
|
|
83
|
+
|
|
84
|
+
const getRes = await request('/sparqltest/public/multi-insert.json');
|
|
85
|
+
const data = await getRes.json();
|
|
86
|
+
assert.strictEqual(data['http://example.org/prop1'], 'value1');
|
|
87
|
+
assert.strictEqual(data['http://example.org/prop2'], 'value2');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('DELETE DATA', () => {
|
|
92
|
+
it('should delete a triple from existing resource', async () => {
|
|
93
|
+
await request('/sparqltest/public/delete-test.json', {
|
|
94
|
+
method: 'PUT',
|
|
95
|
+
headers: { 'Content-Type': 'application/ld+json' },
|
|
96
|
+
body: JSON.stringify({
|
|
97
|
+
'@id': '#item',
|
|
98
|
+
'http://example.org/keep': 'yes',
|
|
99
|
+
'http://example.org/remove': 'this'
|
|
100
|
+
}),
|
|
101
|
+
auth: 'sparqltest'
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const sparql = `
|
|
105
|
+
PREFIX ex: <http://example.org/>
|
|
106
|
+
DELETE DATA {
|
|
107
|
+
<#item> ex:remove "this" .
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
const res = await request('/sparqltest/public/delete-test.json', {
|
|
112
|
+
method: 'PATCH',
|
|
113
|
+
headers: { 'Content-Type': 'application/sparql-update' },
|
|
114
|
+
body: sparql,
|
|
115
|
+
auth: 'sparqltest'
|
|
116
|
+
});
|
|
117
|
+
assertStatus(res, 204);
|
|
118
|
+
|
|
119
|
+
const getRes = await request('/sparqltest/public/delete-test.json');
|
|
120
|
+
const data = await getRes.json();
|
|
121
|
+
assert.strictEqual(data['http://example.org/keep'], 'yes');
|
|
122
|
+
assert.strictEqual(data['http://example.org/remove'], undefined);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('DELETE/INSERT WHERE', () => {
|
|
127
|
+
it('should delete and insert in single operation', async () => {
|
|
128
|
+
await request('/sparqltest/public/update-test.json', {
|
|
129
|
+
method: 'PUT',
|
|
130
|
+
headers: { 'Content-Type': 'application/ld+json' },
|
|
131
|
+
body: JSON.stringify({
|
|
132
|
+
'@id': '#item',
|
|
133
|
+
'http://example.org/version': '1'
|
|
134
|
+
}),
|
|
135
|
+
auth: 'sparqltest'
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const sparql = `
|
|
139
|
+
PREFIX ex: <http://example.org/>
|
|
140
|
+
DELETE { <#item> ex:version "1" }
|
|
141
|
+
INSERT { <#item> ex:version "2" }
|
|
142
|
+
WHERE { <#item> ex:version "1" }
|
|
143
|
+
`;
|
|
144
|
+
|
|
145
|
+
const res = await request('/sparqltest/public/update-test.json', {
|
|
146
|
+
method: 'PATCH',
|
|
147
|
+
headers: { 'Content-Type': 'application/sparql-update' },
|
|
148
|
+
body: sparql,
|
|
149
|
+
auth: 'sparqltest'
|
|
150
|
+
});
|
|
151
|
+
assertStatus(res, 204);
|
|
152
|
+
|
|
153
|
+
const getRes = await request('/sparqltest/public/update-test.json');
|
|
154
|
+
const data = await getRes.json();
|
|
155
|
+
assert.strictEqual(data['http://example.org/version'], '2');
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('Error handling', () => {
|
|
160
|
+
it('should return 404 for non-existent resource', async () => {
|
|
161
|
+
const sparql = `INSERT DATA { <#x> <http://example.org/p> "v" }`;
|
|
162
|
+
const res = await request('/sparqltest/public/nonexistent.json', {
|
|
163
|
+
method: 'PATCH',
|
|
164
|
+
headers: { 'Content-Type': 'application/sparql-update' },
|
|
165
|
+
body: sparql,
|
|
166
|
+
auth: 'sparqltest'
|
|
167
|
+
});
|
|
168
|
+
assertStatus(res, 404);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should return 415 for unsupported content type', async () => {
|
|
172
|
+
await request('/sparqltest/public/content-type-test.json', {
|
|
173
|
+
method: 'PUT',
|
|
174
|
+
headers: { 'Content-Type': 'application/ld+json' },
|
|
175
|
+
body: JSON.stringify({ '@id': '#test' }),
|
|
176
|
+
auth: 'sparqltest'
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const res = await request('/sparqltest/public/content-type-test.json', {
|
|
180
|
+
method: 'PATCH',
|
|
181
|
+
headers: { 'Content-Type': 'text/plain' },
|
|
182
|
+
body: 'not a valid patch',
|
|
183
|
+
auth: 'sparqltest'
|
|
184
|
+
});
|
|
185
|
+
assertStatus(res, 415);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('Typed literals', () => {
|
|
190
|
+
it('should handle integer literals', async () => {
|
|
191
|
+
await request('/sparqltest/public/typed-test.json', {
|
|
192
|
+
method: 'PUT',
|
|
193
|
+
headers: { 'Content-Type': 'application/ld+json' },
|
|
194
|
+
body: JSON.stringify({ '@id': '#data' }),
|
|
195
|
+
auth: 'sparqltest'
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const sparql = `
|
|
199
|
+
PREFIX ex: <http://example.org/>
|
|
200
|
+
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
|
201
|
+
INSERT DATA {
|
|
202
|
+
<#data> ex:count "42"^^xsd:integer .
|
|
203
|
+
}
|
|
204
|
+
`;
|
|
205
|
+
|
|
206
|
+
const res = await request('/sparqltest/public/typed-test.json', {
|
|
207
|
+
method: 'PATCH',
|
|
208
|
+
headers: { 'Content-Type': 'application/sparql-update' },
|
|
209
|
+
body: sparql,
|
|
210
|
+
auth: 'sparqltest'
|
|
211
|
+
});
|
|
212
|
+
assertStatus(res, 204);
|
|
213
|
+
|
|
214
|
+
const getRes = await request('/sparqltest/public/typed-test.json');
|
|
215
|
+
const data = await getRes.json();
|
|
216
|
+
assert.ok(data['http://example.org/count']);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|