@platformatic/sql-graphql 0.3.0 → 0.5.0
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/.nyc_output/{475e591b-b773-4ada-87d0-db538511c660.json → 02e6172c-f2ba-40f1-9d5d-86451759372c.json} +0 -0
- package/.nyc_output/06e1b082-c272-4876-b72f-14a940fb4e16.json +1 -0
- package/.nyc_output/393706b4-dd23-4644-a301-1ae1b551d5a0.json +1 -0
- package/.nyc_output/49ebb061-4831-4245-aeb8-dea830e8513b.json +1 -0
- package/.nyc_output/4c84319f-8089-4a76-8f49-474d69c477e2.json +1 -0
- package/.nyc_output/64081cdd-16a1-4dac-959c-6bd9f98b458e.json +1 -0
- package/.nyc_output/6a1062ee-935e-4b4d-9dd7-cc70277e5916.json +1 -0
- package/.nyc_output/7d3bbc3d-1c87-46e8-93d7-372bb91a5784.json +1 -0
- package/.nyc_output/9b470ca8-a83d-4499-9830-fa4698aa8655.json +1 -0
- package/.nyc_output/d470f916-c2cc-4ace-9341-9893e631826b.json +1 -0
- package/.nyc_output/df3d5175-9faa-48e8-b218-b3b5e9709f08.json +1 -0
- package/.nyc_output/ee904462-d684-4118-aa0a-58d306f34e5e.json +1 -0
- package/.nyc_output/ef850e84-b27d-4a2f-838c-56312a338f26.json +1 -0
- package/.nyc_output/f699a0f3-0d25-4890-a6de-94d8cdedb7d6.json +1 -0
- package/.nyc_output/f782edc5-072d-48f2-9c74-f0bcd7b86010.json +1 -0
- package/.nyc_output/f818f3a6-33e4-4b4c-805d-69e3274bf1d1.json +1 -0
- package/.nyc_output/processinfo/02e6172c-f2ba-40f1-9d5d-86451759372c.json +1 -0
- package/.nyc_output/processinfo/06e1b082-c272-4876-b72f-14a940fb4e16.json +1 -0
- package/.nyc_output/processinfo/393706b4-dd23-4644-a301-1ae1b551d5a0.json +1 -0
- package/.nyc_output/processinfo/49ebb061-4831-4245-aeb8-dea830e8513b.json +1 -0
- package/.nyc_output/processinfo/4c84319f-8089-4a76-8f49-474d69c477e2.json +1 -0
- package/.nyc_output/processinfo/64081cdd-16a1-4dac-959c-6bd9f98b458e.json +1 -0
- package/.nyc_output/processinfo/6a1062ee-935e-4b4d-9dd7-cc70277e5916.json +1 -0
- package/.nyc_output/processinfo/7d3bbc3d-1c87-46e8-93d7-372bb91a5784.json +1 -0
- package/.nyc_output/processinfo/9b470ca8-a83d-4499-9830-fa4698aa8655.json +1 -0
- package/.nyc_output/processinfo/d470f916-c2cc-4ace-9341-9893e631826b.json +1 -0
- package/.nyc_output/processinfo/df3d5175-9faa-48e8-b218-b3b5e9709f08.json +1 -0
- package/.nyc_output/processinfo/ee904462-d684-4118-aa0a-58d306f34e5e.json +1 -0
- package/.nyc_output/processinfo/ef850e84-b27d-4a2f-838c-56312a338f26.json +1 -0
- package/.nyc_output/processinfo/f699a0f3-0d25-4890-a6de-94d8cdedb7d6.json +1 -0
- package/.nyc_output/processinfo/f782edc5-072d-48f2-9c74-f0bcd7b86010.json +1 -0
- package/.nyc_output/processinfo/f818f3a6-33e4-4b4c-805d-69e3274bf1d1.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -1
- package/index.js +19 -2
- package/lib/entity-to-type.js +1 -0
- package/lib/relationship.js +32 -3
- package/lib/subscriptions.js +89 -0
- package/package.json +6 -4
- package/test/helper.js +18 -0
- package/test/relations.test.js +332 -6
- package/test/subscription.test.js +336 -0
- package/.nyc_output/28567d89-45dc-4aa4-8d9d-4c8b713612e5.json +0 -1
- package/.nyc_output/4956602f-f6bd-4aef-bc4c-3d019bf6d754.json +0 -1
- package/.nyc_output/4c93feaa-384f-4a7c-b7bf-070cecebf72c.json +0 -1
- package/.nyc_output/6e295e9b-655e-43fd-a92a-75d058bed16d.json +0 -1
- package/.nyc_output/79fec06e-8965-498f-a023-624db14cdca7.json +0 -1
- package/.nyc_output/7f365fa0-3cdb-4303-ad17-59e3639745cc.json +0 -1
- package/.nyc_output/92f8aaa6-0c3d-4833-8544-93e0be94a868.json +0 -1
- package/.nyc_output/a4edd7d2-26a6-46ca-a79e-bc52a9308d76.json +0 -1
- package/.nyc_output/b152f368-1d63-4d9d-bd3a-97bb6b761ca8.json +0 -1
- package/.nyc_output/cc4af553-54c0-4a1e-9980-b7d8534e9010.json +0 -1
- package/.nyc_output/e0eb89e2-5c3c-4b39-8237-5827918c9774.json +0 -1
- package/.nyc_output/e640b1f5-34e9-4ac5-8691-3fc4b925739b.json +0 -1
- package/.nyc_output/f3e7d9f6-b598-48c5-9ebe-18071958a7d8.json +0 -1
- package/.nyc_output/fb0cb3f2-69da-49fa-bd3c-f13eceee0d3d.json +0 -1
- package/.nyc_output/processinfo/28567d89-45dc-4aa4-8d9d-4c8b713612e5.json +0 -1
- package/.nyc_output/processinfo/475e591b-b773-4ada-87d0-db538511c660.json +0 -1
- package/.nyc_output/processinfo/4956602f-f6bd-4aef-bc4c-3d019bf6d754.json +0 -1
- package/.nyc_output/processinfo/4c93feaa-384f-4a7c-b7bf-070cecebf72c.json +0 -1
- package/.nyc_output/processinfo/6e295e9b-655e-43fd-a92a-75d058bed16d.json +0 -1
- package/.nyc_output/processinfo/79fec06e-8965-498f-a023-624db14cdca7.json +0 -1
- package/.nyc_output/processinfo/7f365fa0-3cdb-4303-ad17-59e3639745cc.json +0 -1
- package/.nyc_output/processinfo/92f8aaa6-0c3d-4833-8544-93e0be94a868.json +0 -1
- package/.nyc_output/processinfo/a4edd7d2-26a6-46ca-a79e-bc52a9308d76.json +0 -1
- package/.nyc_output/processinfo/b152f368-1d63-4d9d-bd3a-97bb6b761ca8.json +0 -1
- package/.nyc_output/processinfo/cc4af553-54c0-4a1e-9980-b7d8534e9010.json +0 -1
- package/.nyc_output/processinfo/e0eb89e2-5c3c-4b39-8237-5827918c9774.json +0 -1
- package/.nyc_output/processinfo/e640b1f5-34e9-4ac5-8691-3fc4b925739b.json +0 -1
- package/.nyc_output/processinfo/f3e7d9f6-b598-48c5-9ebe-18071958a7d8.json +0 -1
- package/.nyc_output/processinfo/fb0cb3f2-69da-49fa-bd3c-f13eceee0d3d.json +0 -1
package/test/relations.test.js
CHANGED
|
@@ -7,14 +7,12 @@ const { join } = require('path')
|
|
|
7
7
|
const sqlGraphQL = require('..')
|
|
8
8
|
const sqlMapper = require('@platformatic/sql-mapper')
|
|
9
9
|
const fastify = require('fastify')
|
|
10
|
-
const { isSQLite } = require('./helper')
|
|
11
|
-
|
|
12
|
-
if (!isSQLite) {
|
|
13
|
-
skip('The db is not SQLite')
|
|
14
|
-
process.exit(0)
|
|
15
|
-
}
|
|
10
|
+
const { isSQLite, connInfo, isMysql, clear } = require('./helper')
|
|
16
11
|
|
|
17
12
|
test('should fail when an unknown foreign key relationship exists', async ({ pass, rejects, same, teardown }) => {
|
|
13
|
+
if (!isSQLite) {
|
|
14
|
+
skip('The db is not SQLite')
|
|
15
|
+
}
|
|
18
16
|
const file = join(tmpdir(), randomUUID())
|
|
19
17
|
const app = fastify()
|
|
20
18
|
app.register(sqlMapper, {
|
|
@@ -58,3 +56,331 @@ test('should fail when an unknown foreign key relationship exists', async ({ pas
|
|
|
58
56
|
}
|
|
59
57
|
}), new Error('No foreign table named "subcategories" was found'))
|
|
60
58
|
})
|
|
59
|
+
|
|
60
|
+
test('should handle multi references', async ({ pass, teardown, same, equal }) => {
|
|
61
|
+
const app = fastify()
|
|
62
|
+
app.register(sqlMapper, {
|
|
63
|
+
...connInfo,
|
|
64
|
+
async onDatabaseLoad (db, sql) {
|
|
65
|
+
pass('onDatabaseLoad called')
|
|
66
|
+
|
|
67
|
+
await clear(db, sql)
|
|
68
|
+
|
|
69
|
+
if (isMysql) {
|
|
70
|
+
await db.query(sql`
|
|
71
|
+
CREATE TABLE authors (
|
|
72
|
+
id SERIAL PRIMARY KEY,
|
|
73
|
+
name VARCHAR(255)
|
|
74
|
+
);
|
|
75
|
+
CREATE TABLE books (
|
|
76
|
+
id SERIAL PRIMARY KEY,
|
|
77
|
+
title VARCHAR(42),
|
|
78
|
+
author_id BIGINT UNSIGNED,
|
|
79
|
+
another_author_id BIGINT UNSIGNED,
|
|
80
|
+
FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE,
|
|
81
|
+
FOREIGN KEY (another_author_id) REFERENCES authors(id) ON DELETE CASCADE
|
|
82
|
+
);
|
|
83
|
+
`)
|
|
84
|
+
} else if (isSQLite) {
|
|
85
|
+
await db.query(sql`
|
|
86
|
+
CREATE TABLE authors (
|
|
87
|
+
id INTEGER PRIMARY KEY,
|
|
88
|
+
name VARCHAR(255)
|
|
89
|
+
);
|
|
90
|
+
`)
|
|
91
|
+
await db.query(sql`
|
|
92
|
+
CREATE TABLE books (
|
|
93
|
+
id INTEGER PRIMARY KEY,
|
|
94
|
+
title VARCHAR(42),
|
|
95
|
+
author_id BIGINT UNSIGNED,
|
|
96
|
+
another_author_id BIGINT UNSIGNED,
|
|
97
|
+
FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE,
|
|
98
|
+
FOREIGN KEY (another_author_id) REFERENCES authors(id) ON DELETE CASCADE
|
|
99
|
+
);
|
|
100
|
+
`)
|
|
101
|
+
} else {
|
|
102
|
+
await db.query(sql`
|
|
103
|
+
CREATE TABLE authors (
|
|
104
|
+
id SERIAL PRIMARY KEY,
|
|
105
|
+
name VARCHAR(42)
|
|
106
|
+
);
|
|
107
|
+
CREATE TABLE books (
|
|
108
|
+
id SERIAL PRIMARY KEY,
|
|
109
|
+
title VARCHAR(42),
|
|
110
|
+
author_id INTEGER REFERENCES authors(id),
|
|
111
|
+
another_author_id INTEGER REFERENCES authors(id)
|
|
112
|
+
);
|
|
113
|
+
`)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
app.register(sqlGraphQL)
|
|
118
|
+
teardown(app.close.bind(app))
|
|
119
|
+
|
|
120
|
+
await app.ready()
|
|
121
|
+
|
|
122
|
+
const authors = [{
|
|
123
|
+
id: 1,
|
|
124
|
+
name: 'Mark'
|
|
125
|
+
}]
|
|
126
|
+
|
|
127
|
+
const books = [{
|
|
128
|
+
id: 1,
|
|
129
|
+
title: 'Harry',
|
|
130
|
+
authorId: 1,
|
|
131
|
+
anotherAuthorId: 1
|
|
132
|
+
}]
|
|
133
|
+
|
|
134
|
+
{
|
|
135
|
+
const res = await app.inject({
|
|
136
|
+
method: 'POST',
|
|
137
|
+
url: '/graphql',
|
|
138
|
+
body: {
|
|
139
|
+
query: `
|
|
140
|
+
mutation batch($inputs : [AuthorInput]!) {
|
|
141
|
+
insertAuthors(inputs: $inputs) {
|
|
142
|
+
id
|
|
143
|
+
name
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
`,
|
|
147
|
+
variables: {
|
|
148
|
+
inputs: authors
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
equal(res.statusCode, 200, 'authors status code')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
{
|
|
156
|
+
const res = await app.inject({
|
|
157
|
+
method: 'POST',
|
|
158
|
+
url: '/graphql',
|
|
159
|
+
body: {
|
|
160
|
+
query: `
|
|
161
|
+
mutation batch($inputs : [BookInput]!) {
|
|
162
|
+
insertBooks(inputs: $inputs) {
|
|
163
|
+
id
|
|
164
|
+
title
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
`,
|
|
168
|
+
variables: {
|
|
169
|
+
inputs: books
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
equal(res.statusCode, 200, 'books status code')
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
{
|
|
177
|
+
const res = await app.inject({
|
|
178
|
+
method: 'POST',
|
|
179
|
+
url: '/graphql',
|
|
180
|
+
body: {
|
|
181
|
+
query: `
|
|
182
|
+
query {
|
|
183
|
+
books {
|
|
184
|
+
id
|
|
185
|
+
author {
|
|
186
|
+
id
|
|
187
|
+
}
|
|
188
|
+
anotherAuthor {
|
|
189
|
+
id
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
`
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
equal(res.statusCode, 200, 'query books')
|
|
197
|
+
same(res.json(), {
|
|
198
|
+
data: {
|
|
199
|
+
books: [{
|
|
200
|
+
id: 1,
|
|
201
|
+
author: {
|
|
202
|
+
id: 1
|
|
203
|
+
},
|
|
204
|
+
anotherAuthor: {
|
|
205
|
+
id: 1
|
|
206
|
+
}
|
|
207
|
+
}]
|
|
208
|
+
}
|
|
209
|
+
}, 'query book response')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
{
|
|
213
|
+
const res = await app.inject({
|
|
214
|
+
method: 'POST',
|
|
215
|
+
url: '/graphql',
|
|
216
|
+
body: {
|
|
217
|
+
query: `
|
|
218
|
+
query {
|
|
219
|
+
authors {
|
|
220
|
+
id
|
|
221
|
+
books {
|
|
222
|
+
id
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
`
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
equal(res.statusCode, 200, 'query authors')
|
|
230
|
+
same(res.json(), {
|
|
231
|
+
data: {
|
|
232
|
+
authors: [{
|
|
233
|
+
id: 1,
|
|
234
|
+
books: [{
|
|
235
|
+
id: 1
|
|
236
|
+
}]
|
|
237
|
+
}]
|
|
238
|
+
}
|
|
239
|
+
}, 'query authors response')
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
test('cut out id exactly from ending when forming a name of relation', async ({ pass, teardown, same, equal }) => {
|
|
244
|
+
const app = fastify()
|
|
245
|
+
app.register(sqlMapper, {
|
|
246
|
+
...connInfo,
|
|
247
|
+
async onDatabaseLoad (db, sql) {
|
|
248
|
+
pass('onDatabaseLoad called')
|
|
249
|
+
|
|
250
|
+
await clear(db, sql)
|
|
251
|
+
|
|
252
|
+
if (isMysql) {
|
|
253
|
+
await db.query(sql`
|
|
254
|
+
CREATE TABLE individuals (
|
|
255
|
+
id SERIAL PRIMARY KEY,
|
|
256
|
+
name VARCHAR(255)
|
|
257
|
+
);
|
|
258
|
+
CREATE TABLE organizations (
|
|
259
|
+
id SERIAL PRIMARY KEY,
|
|
260
|
+
name VARCHAR(42),
|
|
261
|
+
individual_id BIGINT UNSIGNED,
|
|
262
|
+
FOREIGN KEY (individual_id) REFERENCES individuals(id) ON DELETE CASCADE
|
|
263
|
+
);
|
|
264
|
+
`)
|
|
265
|
+
} else if (isSQLite) {
|
|
266
|
+
await db.query(sql`
|
|
267
|
+
CREATE TABLE individuals (
|
|
268
|
+
id INTEGER PRIMARY KEY,
|
|
269
|
+
name VARCHAR(255)
|
|
270
|
+
);
|
|
271
|
+
`)
|
|
272
|
+
await db.query(sql`
|
|
273
|
+
CREATE TABLE organizations (
|
|
274
|
+
id INTEGER PRIMARY KEY,
|
|
275
|
+
name VARCHAR(42),
|
|
276
|
+
individual_id BIGINT UNSIGNED,
|
|
277
|
+
FOREIGN KEY (individual_id) REFERENCES individuals(id) ON DELETE CASCADE
|
|
278
|
+
);
|
|
279
|
+
`)
|
|
280
|
+
} else {
|
|
281
|
+
await db.query(sql`
|
|
282
|
+
CREATE TABLE individuals (
|
|
283
|
+
id SERIAL PRIMARY KEY,
|
|
284
|
+
name VARCHAR(42)
|
|
285
|
+
);
|
|
286
|
+
CREATE TABLE organizations (
|
|
287
|
+
id SERIAL PRIMARY KEY,
|
|
288
|
+
name VARCHAR(42),
|
|
289
|
+
individual_id INTEGER REFERENCES individuals(id)
|
|
290
|
+
);
|
|
291
|
+
`)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
})
|
|
295
|
+
app.register(sqlGraphQL)
|
|
296
|
+
teardown(app.close.bind(app))
|
|
297
|
+
|
|
298
|
+
await app.ready()
|
|
299
|
+
|
|
300
|
+
const individuals = [{
|
|
301
|
+
id: 1,
|
|
302
|
+
name: 'Mark'
|
|
303
|
+
}]
|
|
304
|
+
|
|
305
|
+
const organization = [{
|
|
306
|
+
id: 1,
|
|
307
|
+
name: 'Platformatic',
|
|
308
|
+
individualId: 1
|
|
309
|
+
}]
|
|
310
|
+
|
|
311
|
+
{
|
|
312
|
+
const res = await app.inject({
|
|
313
|
+
method: 'POST',
|
|
314
|
+
url: '/graphql',
|
|
315
|
+
body: {
|
|
316
|
+
query: `
|
|
317
|
+
mutation batch($inputs : [IndividualInput]!) {
|
|
318
|
+
insertIndividuals(inputs: $inputs) {
|
|
319
|
+
id
|
|
320
|
+
name
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
`,
|
|
324
|
+
variables: {
|
|
325
|
+
inputs: individuals
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
equal(res.statusCode, 200, 'individuals status code')
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
{
|
|
333
|
+
const res = await app.inject({
|
|
334
|
+
method: 'POST',
|
|
335
|
+
url: '/graphql',
|
|
336
|
+
body: {
|
|
337
|
+
query: `
|
|
338
|
+
mutation batch($inputs : [OrganizationInput]!) {
|
|
339
|
+
insertOrganizations(inputs: $inputs) {
|
|
340
|
+
id
|
|
341
|
+
name
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
`,
|
|
345
|
+
variables: {
|
|
346
|
+
inputs: organization
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
})
|
|
350
|
+
equal(res.statusCode, 200, 'organization status code')
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
{
|
|
354
|
+
const res = await app.inject({
|
|
355
|
+
method: 'POST',
|
|
356
|
+
url: '/graphql',
|
|
357
|
+
body: {
|
|
358
|
+
query: `
|
|
359
|
+
query {
|
|
360
|
+
organizations {
|
|
361
|
+
id
|
|
362
|
+
name
|
|
363
|
+
individual {
|
|
364
|
+
id
|
|
365
|
+
name
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
`
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
equal(res.statusCode, 200, 'query organization')
|
|
373
|
+
same(res.json(), {
|
|
374
|
+
data: {
|
|
375
|
+
organizations: [{
|
|
376
|
+
id: 1,
|
|
377
|
+
name: 'Platformatic',
|
|
378
|
+
individual: {
|
|
379
|
+
id: 1,
|
|
380
|
+
name: 'Mark'
|
|
381
|
+
}
|
|
382
|
+
}]
|
|
383
|
+
}
|
|
384
|
+
}, 'query organization response')
|
|
385
|
+
}
|
|
386
|
+
})
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const WebSocket = require('ws')
|
|
6
|
+
const { once } = require('events')
|
|
7
|
+
const sqlGraphQL = require('..')
|
|
8
|
+
const sqlMapper = require('@platformatic/sql-mapper')
|
|
9
|
+
const sqlEvents = require('@platformatic/sql-events')
|
|
10
|
+
const { clear, connInfo, isSQLite } = require('./helper')
|
|
11
|
+
const stream = require('stream')
|
|
12
|
+
const graphql = require('graphql')
|
|
13
|
+
|
|
14
|
+
async function createBasicPages (db, sql) {
|
|
15
|
+
if (isSQLite) {
|
|
16
|
+
await db.query(sql`CREATE TABLE pages (
|
|
17
|
+
id INTEGER PRIMARY KEY,
|
|
18
|
+
title VARCHAR(42)
|
|
19
|
+
);`)
|
|
20
|
+
} else {
|
|
21
|
+
await db.query(sql`CREATE TABLE pages (
|
|
22
|
+
id SERIAL PRIMARY KEY,
|
|
23
|
+
title VARCHAR(42)
|
|
24
|
+
);`)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createWebSocketClient (t, app) {
|
|
29
|
+
const ws = new WebSocket('ws://localhost:' + (app.server.address()).port + '/graphql', 'graphql-ws')
|
|
30
|
+
const client = WebSocket.createWebSocketStream(ws, { encoding: 'utf8', objectMode: true })
|
|
31
|
+
t.teardown(client.destroy.bind(client))
|
|
32
|
+
client.setEncoding('utf8')
|
|
33
|
+
return { client, ws }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test('subscription - crud', { only: true }, async t => {
|
|
37
|
+
const app = Fastify()
|
|
38
|
+
t.teardown(() => app.close())
|
|
39
|
+
|
|
40
|
+
app.register(sqlMapper, {
|
|
41
|
+
...connInfo,
|
|
42
|
+
async onDatabaseLoad (db, sql) {
|
|
43
|
+
await clear(db, sql)
|
|
44
|
+
await createBasicPages(db, sql)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
app.register(sqlEvents)
|
|
48
|
+
app.register(sqlGraphQL)
|
|
49
|
+
|
|
50
|
+
await app.listen({ port: 0 })
|
|
51
|
+
|
|
52
|
+
const { client } = createWebSocketClient(t, app)
|
|
53
|
+
|
|
54
|
+
client.write(JSON.stringify({
|
|
55
|
+
type: 'connection_init'
|
|
56
|
+
}))
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
const query = `subscription {
|
|
60
|
+
pageSaved {
|
|
61
|
+
id
|
|
62
|
+
title
|
|
63
|
+
}
|
|
64
|
+
}`
|
|
65
|
+
client.write(JSON.stringify({
|
|
66
|
+
id: 1,
|
|
67
|
+
type: 'start',
|
|
68
|
+
payload: {
|
|
69
|
+
query
|
|
70
|
+
}
|
|
71
|
+
}))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
const query = `subscription {
|
|
76
|
+
pageDeleted {
|
|
77
|
+
id
|
|
78
|
+
}
|
|
79
|
+
}`
|
|
80
|
+
client.write(JSON.stringify({
|
|
81
|
+
id: 1,
|
|
82
|
+
type: 'start',
|
|
83
|
+
payload: {
|
|
84
|
+
query
|
|
85
|
+
}
|
|
86
|
+
}))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
{
|
|
90
|
+
const [chunk] = await once(client, 'data')
|
|
91
|
+
const data = JSON.parse(chunk)
|
|
92
|
+
t.equal(data.type, 'connection_ack')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
t.comment('sending mutation')
|
|
96
|
+
|
|
97
|
+
await app.inject({
|
|
98
|
+
method: 'POST',
|
|
99
|
+
url: '/graphql',
|
|
100
|
+
body: {
|
|
101
|
+
query: `
|
|
102
|
+
mutation {
|
|
103
|
+
savePage(input: { title: "Hello World" }) {
|
|
104
|
+
id
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
t.comment('mutation sent')
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
const [chunk] = await once(client, 'data')
|
|
115
|
+
const data = JSON.parse(chunk)
|
|
116
|
+
t.same(data, {
|
|
117
|
+
id: 1,
|
|
118
|
+
type: 'data',
|
|
119
|
+
payload: {
|
|
120
|
+
data: {
|
|
121
|
+
pageSaved: {
|
|
122
|
+
id: '1',
|
|
123
|
+
title: 'Hello World'
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
t.comment('updating entity')
|
|
131
|
+
|
|
132
|
+
await app.inject({
|
|
133
|
+
method: 'POST',
|
|
134
|
+
url: '/graphql',
|
|
135
|
+
body: {
|
|
136
|
+
query: `
|
|
137
|
+
mutation {
|
|
138
|
+
savePage(input: { id: 1, title: "Harry Potter" }) {
|
|
139
|
+
id
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
`
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
t.comment('entity updated')
|
|
147
|
+
|
|
148
|
+
{
|
|
149
|
+
const [chunk] = await once(client, 'data')
|
|
150
|
+
const data = JSON.parse(chunk)
|
|
151
|
+
t.same(data, {
|
|
152
|
+
id: 1,
|
|
153
|
+
type: 'data',
|
|
154
|
+
payload: {
|
|
155
|
+
data: {
|
|
156
|
+
pageSaved: {
|
|
157
|
+
id: '1',
|
|
158
|
+
title: 'Harry Potter'
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
t.comment('deleting entity')
|
|
166
|
+
|
|
167
|
+
await app.inject({
|
|
168
|
+
method: 'POST',
|
|
169
|
+
url: '/graphql',
|
|
170
|
+
body: {
|
|
171
|
+
query: `
|
|
172
|
+
mutation {
|
|
173
|
+
deletePages(where: { id: { eq: 1 } }) {
|
|
174
|
+
id
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
`
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
t.comment('entity deleted')
|
|
182
|
+
|
|
183
|
+
{
|
|
184
|
+
const [chunk] = await once(client, 'data')
|
|
185
|
+
const data = JSON.parse(chunk)
|
|
186
|
+
t.same(data, {
|
|
187
|
+
id: '1',
|
|
188
|
+
type: 'data',
|
|
189
|
+
payload: {
|
|
190
|
+
data: {
|
|
191
|
+
pageDeleted: {
|
|
192
|
+
id: '1'
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
t.comment('sending mutation')
|
|
200
|
+
|
|
201
|
+
{
|
|
202
|
+
const [
|
|
203
|
+
received,
|
|
204
|
+
stored
|
|
205
|
+
] = await Promise.all(([
|
|
206
|
+
(async function () {
|
|
207
|
+
const res = await app.inject({
|
|
208
|
+
method: 'POST',
|
|
209
|
+
url: '/graphql',
|
|
210
|
+
body: {
|
|
211
|
+
query: `
|
|
212
|
+
mutation batch($inputs : [PageInput]!) {
|
|
213
|
+
insertPages (inputs: $inputs) {
|
|
214
|
+
id
|
|
215
|
+
title
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
`,
|
|
219
|
+
variables: {
|
|
220
|
+
inputs: [
|
|
221
|
+
{ title: 'Page 1' },
|
|
222
|
+
{ title: 'Page 2' },
|
|
223
|
+
{ title: 'Page 3' }
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
t.comment('mutation sent')
|
|
229
|
+
const pages = res.json().data.insertPages
|
|
230
|
+
t.comment(JSON.stringify(pages, null, 2))
|
|
231
|
+
return pages
|
|
232
|
+
})(),
|
|
233
|
+
(async function () {
|
|
234
|
+
const pages = []
|
|
235
|
+
const second = new stream.PassThrough({ objectMode: true })
|
|
236
|
+
client.pipe(second)
|
|
237
|
+
for await (const chunk of second) {
|
|
238
|
+
const data = JSON.parse(chunk)
|
|
239
|
+
pages.push(data.payload.data.pageSaved)
|
|
240
|
+
if (pages.length === 3) {
|
|
241
|
+
break
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
t.comment('received all pages', JSON.stringify(pages, null, 2))
|
|
245
|
+
return pages
|
|
246
|
+
})()
|
|
247
|
+
]))
|
|
248
|
+
|
|
249
|
+
t.same(received, stored)
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
test('subscription - ignore', async t => {
|
|
254
|
+
const app = Fastify()
|
|
255
|
+
t.teardown(() => app.close())
|
|
256
|
+
|
|
257
|
+
app.register(sqlMapper, {
|
|
258
|
+
...connInfo,
|
|
259
|
+
async onDatabaseLoad (db, sql) {
|
|
260
|
+
await clear(db, sql)
|
|
261
|
+
await createBasicPages(db, sql)
|
|
262
|
+
}
|
|
263
|
+
})
|
|
264
|
+
app.register(sqlEvents)
|
|
265
|
+
app.register(sqlGraphQL, {
|
|
266
|
+
subscriptionIgnore: ['page']
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
await app.ready()
|
|
270
|
+
t.equal(graphql.printSchema(app.graphql.schema).indexOf('type Subscription'), -1)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
test('subscription - crud with two schemas and a ignore', async t => {
|
|
274
|
+
const app = Fastify()
|
|
275
|
+
t.teardown(() => app.close())
|
|
276
|
+
|
|
277
|
+
app.register(sqlMapper, {
|
|
278
|
+
...connInfo,
|
|
279
|
+
async onDatabaseLoad (db, sql) {
|
|
280
|
+
await clear(db, sql)
|
|
281
|
+
await createBasicPages(db, sql)
|
|
282
|
+
|
|
283
|
+
if (isSQLite) {
|
|
284
|
+
await db.query(sql`CREATE TABLE categories (
|
|
285
|
+
id INTEGER PRIMARY KEY,
|
|
286
|
+
name VARCHAR(42)
|
|
287
|
+
);`)
|
|
288
|
+
} else {
|
|
289
|
+
await db.query(sql`CREATE TABLE categories (
|
|
290
|
+
id SERIAL PRIMARY KEY,
|
|
291
|
+
name VARCHAR(42)
|
|
292
|
+
);`)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
app.register(sqlEvents)
|
|
297
|
+
app.register(sqlGraphQL, {
|
|
298
|
+
subscriptionIgnore: ['category']
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
await app.listen({ port: 0 })
|
|
302
|
+
|
|
303
|
+
const { client } = createWebSocketClient(t, app)
|
|
304
|
+
t.teardown(() => client.destroy())
|
|
305
|
+
|
|
306
|
+
client.write(JSON.stringify({
|
|
307
|
+
type: 'connection_init'
|
|
308
|
+
}))
|
|
309
|
+
|
|
310
|
+
{
|
|
311
|
+
const [chunk] = await once(client, 'data')
|
|
312
|
+
const data = JSON.parse(chunk)
|
|
313
|
+
t.equal(data.type, 'connection_ack')
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
{
|
|
317
|
+
const query = `subscription {
|
|
318
|
+
categorySaved {
|
|
319
|
+
id
|
|
320
|
+
}
|
|
321
|
+
}`
|
|
322
|
+
client.write(JSON.stringify({
|
|
323
|
+
id: 1,
|
|
324
|
+
type: 'start',
|
|
325
|
+
payload: {
|
|
326
|
+
query
|
|
327
|
+
}
|
|
328
|
+
}))
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
{
|
|
332
|
+
const [chunk] = await once(client, 'data')
|
|
333
|
+
const data = JSON.parse(chunk)
|
|
334
|
+
t.equal(data.payload, 'The subscription field "categorySaved" is not defined.')
|
|
335
|
+
}
|
|
336
|
+
})
|