@platformatic/sql-graphql 0.0.23
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/0681b2b7-587a-40f2-8242-257bc4c72456.json +1 -0
- package/.nyc_output/191054d4-6a1e-4a1b-87bb-f801ed78a223.json +1 -0
- package/.nyc_output/22ead0f6-e5a6-4647-a2ea-db2f42498081.json +1 -0
- package/.nyc_output/4e847e26-05cd-4063-9277-48aff86d6822.json +1 -0
- package/.nyc_output/5acfd416-02d1-497b-8dbd-69c0af167c62.json +1 -0
- package/.nyc_output/5ec04f76-9bcb-475d-b79e-f9304cc0026c.json +1 -0
- package/.nyc_output/5f3bb47a-0d2d-440a-a466-8ffa9ab3efaa.json +1 -0
- package/.nyc_output/71c2bd84-9a72-4e86-83c6-d587ce525fe4.json +1 -0
- package/.nyc_output/74cc1dab-7479-48e7-80b0-c97351d8856e.json +1 -0
- package/.nyc_output/9f5d12ba-bc3d-461c-a0e2-2a95d2020c19.json +1 -0
- package/.nyc_output/ac343b71-6f76-421c-a287-46d19bb48f89.json +1 -0
- package/.nyc_output/c1c0eecb-63a0-4258-81b6-50e7488bd67c.json +1 -0
- package/.nyc_output/c201a1cd-3105-4d18-bbbb-8d7fa674d439.json +1 -0
- package/.nyc_output/d6da0270-e9ed-41e2-bbf3-9262d1df683c.json +1 -0
- package/.nyc_output/processinfo/0681b2b7-587a-40f2-8242-257bc4c72456.json +1 -0
- package/.nyc_output/processinfo/191054d4-6a1e-4a1b-87bb-f801ed78a223.json +1 -0
- package/.nyc_output/processinfo/22ead0f6-e5a6-4647-a2ea-db2f42498081.json +1 -0
- package/.nyc_output/processinfo/4e847e26-05cd-4063-9277-48aff86d6822.json +1 -0
- package/.nyc_output/processinfo/5acfd416-02d1-497b-8dbd-69c0af167c62.json +1 -0
- package/.nyc_output/processinfo/5ec04f76-9bcb-475d-b79e-f9304cc0026c.json +1 -0
- package/.nyc_output/processinfo/5f3bb47a-0d2d-440a-a466-8ffa9ab3efaa.json +1 -0
- package/.nyc_output/processinfo/71c2bd84-9a72-4e86-83c6-d587ce525fe4.json +1 -0
- package/.nyc_output/processinfo/74cc1dab-7479-48e7-80b0-c97351d8856e.json +1 -0
- package/.nyc_output/processinfo/9f5d12ba-bc3d-461c-a0e2-2a95d2020c19.json +1 -0
- package/.nyc_output/processinfo/ac343b71-6f76-421c-a287-46d19bb48f89.json +1 -0
- package/.nyc_output/processinfo/c1c0eecb-63a0-4258-81b6-50e7488bd67c.json +1 -0
- package/.nyc_output/processinfo/c201a1cd-3105-4d18-bbbb-8d7fa674d439.json +1 -0
- package/.nyc_output/processinfo/d6da0270-e9ed-41e2-bbf3-9262d1df683c.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/.taprc +1 -0
- package/LICENSE +201 -0
- package/NOTICE +13 -0
- package/README.md +13 -0
- package/index.d.ts +40 -0
- package/index.js +117 -0
- package/lib/entity-to-type.js +248 -0
- package/lib/relationship.js +67 -0
- package/lib/utils.js +77 -0
- package/package.json +44 -0
- package/test/datatypes.test.js +708 -0
- package/test/federation.test.js +312 -0
- package/test/helper.js +70 -0
- package/test/hooks.test.js +660 -0
- package/test/ignore.test.js +117 -0
- package/test/insert.test.js +181 -0
- package/test/inserted_updated_at.test.js +517 -0
- package/test/nested.test.js +862 -0
- package/test/no-modification-of-entity.test.js +113 -0
- package/test/order_by.test.js +397 -0
- package/test/relations.test.js +60 -0
- package/test/simple.test.js +708 -0
- package/test/sqlite.test.js +276 -0
- package/test/types/index.test-d.ts +33 -0
- package/test/where.test.js +814 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const Fastify = require('fastify')
|
|
5
|
+
const mercurius = require('mercurius')
|
|
6
|
+
const sqlGraphQL = require('..')
|
|
7
|
+
const sqlMapper = require('@platformatic/sql-mapper')
|
|
8
|
+
const { clear, connInfo, isSQLite } = require('./helper')
|
|
9
|
+
|
|
10
|
+
async function createTestService (t, schema, resolvers = {}) {
|
|
11
|
+
const service = Fastify({ logger: { level: 'error' } })
|
|
12
|
+
service.register(mercurius, {
|
|
13
|
+
schema,
|
|
14
|
+
resolvers,
|
|
15
|
+
federationMetadata: true
|
|
16
|
+
})
|
|
17
|
+
await service.listen({ port: 0 })
|
|
18
|
+
return [service, service.server.address().port]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const categories = {
|
|
22
|
+
c1: {
|
|
23
|
+
id: 'c1',
|
|
24
|
+
name: 'Food'
|
|
25
|
+
},
|
|
26
|
+
c2: {
|
|
27
|
+
id: 'c2',
|
|
28
|
+
name: 'Places'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// This works because the database is reset between tests
|
|
33
|
+
const postCategory = {
|
|
34
|
+
1: 'c1',
|
|
35
|
+
2: 'c2',
|
|
36
|
+
3: 'c1',
|
|
37
|
+
4: 'c1'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const categoryPost = Object.keys(postCategory).reduce((acc, key) => {
|
|
41
|
+
acc[postCategory[key]] = acc[postCategory[key]] || []
|
|
42
|
+
acc[postCategory[key]].push(key)
|
|
43
|
+
return acc
|
|
44
|
+
}, {})
|
|
45
|
+
|
|
46
|
+
const posts = [{
|
|
47
|
+
title: 'Post 1',
|
|
48
|
+
longText: 'This is a long text 1'
|
|
49
|
+
}, {
|
|
50
|
+
title: 'Post 2',
|
|
51
|
+
longText: 'This is a long text 2'
|
|
52
|
+
}, {
|
|
53
|
+
title: 'Post 3',
|
|
54
|
+
longText: 'This is a long text 3'
|
|
55
|
+
}, {
|
|
56
|
+
title: 'Post 4',
|
|
57
|
+
longText: 'This is a long text 4'
|
|
58
|
+
}]
|
|
59
|
+
|
|
60
|
+
async function createTestGatewayServer (t, cacheOpts) {
|
|
61
|
+
const categoryServiceSchema = `
|
|
62
|
+
type Query @extends {
|
|
63
|
+
categories: [Category]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type Category @key(fields: "id") {
|
|
67
|
+
id: ID!
|
|
68
|
+
name: String
|
|
69
|
+
posts: [Post]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type Post @key(fields: "id") @extends {
|
|
73
|
+
id: ID! @external
|
|
74
|
+
category: Category
|
|
75
|
+
}
|
|
76
|
+
`
|
|
77
|
+
const categoryServiceResolvers = {
|
|
78
|
+
Query: {
|
|
79
|
+
categories: (root, args, context, info) => {
|
|
80
|
+
t.pass('Query.categories resolved')
|
|
81
|
+
return Object.values(categories)
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
Category: {
|
|
85
|
+
posts: (root, args, context, info) => {
|
|
86
|
+
t.pass('Category.posts resolved')
|
|
87
|
+
return categoryPost[root.id]
|
|
88
|
+
? categoryPost[root.id].map(id => ({ id }))
|
|
89
|
+
: []
|
|
90
|
+
},
|
|
91
|
+
__resolveReference: (category, args, context, info) => {
|
|
92
|
+
t.pass('Category.__resolveReference')
|
|
93
|
+
return categories[category.id]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
Post: {
|
|
97
|
+
category: (root, args, context, info) => {
|
|
98
|
+
t.pass('Post.category resolved')
|
|
99
|
+
return categories[postCategory[root.id]]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const [categoryService, categoryServicePort] = await createTestService(t, categoryServiceSchema, categoryServiceResolvers)
|
|
104
|
+
|
|
105
|
+
const postService = Fastify()
|
|
106
|
+
postService.register(sqlMapper, {
|
|
107
|
+
...connInfo,
|
|
108
|
+
async onDatabaseLoad (db, sql) {
|
|
109
|
+
t.pass('onDatabaseLoad called')
|
|
110
|
+
|
|
111
|
+
await clear(db, sql)
|
|
112
|
+
|
|
113
|
+
if (isSQLite) {
|
|
114
|
+
await db.query(sql`CREATE TABLE posts (
|
|
115
|
+
id INTEGER PRIMARY KEY,
|
|
116
|
+
title VARCHAR(42),
|
|
117
|
+
long_text TEXT
|
|
118
|
+
);`)
|
|
119
|
+
} else {
|
|
120
|
+
await db.query(sql`CREATE TABLE posts (
|
|
121
|
+
id SERIAL PRIMARY KEY,
|
|
122
|
+
title VARCHAR(42),
|
|
123
|
+
long_text TEXT
|
|
124
|
+
);`)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
postService.register(sqlGraphQL, {
|
|
129
|
+
federationMetadata: true
|
|
130
|
+
})
|
|
131
|
+
await postService.listen({ port: 0 })
|
|
132
|
+
const postServicePort = postService.server.address().port
|
|
133
|
+
|
|
134
|
+
await postService.inject({
|
|
135
|
+
method: 'POST',
|
|
136
|
+
url: '/graphql',
|
|
137
|
+
body: {
|
|
138
|
+
query: `
|
|
139
|
+
mutation batch($inputs : [PostInput]!) {
|
|
140
|
+
insertPosts(inputs: $inputs) {
|
|
141
|
+
id
|
|
142
|
+
title
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
`,
|
|
146
|
+
variables: {
|
|
147
|
+
inputs: posts
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
const gateway = Fastify()
|
|
153
|
+
t.teardown(async () => {
|
|
154
|
+
await gateway.close()
|
|
155
|
+
await categoryService.close()
|
|
156
|
+
await postService.close()
|
|
157
|
+
})
|
|
158
|
+
gateway.register(mercurius, {
|
|
159
|
+
gateway: {
|
|
160
|
+
services: [{
|
|
161
|
+
name: 'category',
|
|
162
|
+
url: `http://localhost:${categoryServicePort}/graphql`
|
|
163
|
+
}, {
|
|
164
|
+
name: 'post',
|
|
165
|
+
url: `http://localhost:${postServicePort}/graphql`
|
|
166
|
+
}]
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
return gateway
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
test('extendable', async (t) => {
|
|
174
|
+
const app = await createTestGatewayServer(t)
|
|
175
|
+
|
|
176
|
+
const query = `query {
|
|
177
|
+
categories {
|
|
178
|
+
id
|
|
179
|
+
name
|
|
180
|
+
posts {
|
|
181
|
+
id
|
|
182
|
+
title
|
|
183
|
+
longText
|
|
184
|
+
category {
|
|
185
|
+
id
|
|
186
|
+
name
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
posts {
|
|
191
|
+
id
|
|
192
|
+
title
|
|
193
|
+
category {
|
|
194
|
+
id
|
|
195
|
+
name
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}`
|
|
199
|
+
|
|
200
|
+
const expected = {
|
|
201
|
+
data: {
|
|
202
|
+
categories: [
|
|
203
|
+
{
|
|
204
|
+
id: 'c1',
|
|
205
|
+
name: 'Food',
|
|
206
|
+
posts: [
|
|
207
|
+
{
|
|
208
|
+
id: '1',
|
|
209
|
+
title: 'Post 1',
|
|
210
|
+
longText: 'This is a long text 1',
|
|
211
|
+
category: {
|
|
212
|
+
id: 'c1',
|
|
213
|
+
name: 'Food'
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: '3',
|
|
218
|
+
title: 'Post 3',
|
|
219
|
+
longText: 'This is a long text 3',
|
|
220
|
+
category: {
|
|
221
|
+
id: 'c1',
|
|
222
|
+
name: 'Food'
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
id: '4',
|
|
227
|
+
title: 'Post 4',
|
|
228
|
+
longText: 'This is a long text 4',
|
|
229
|
+
category: {
|
|
230
|
+
id: 'c1',
|
|
231
|
+
name: 'Food'
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
id: 'c2',
|
|
238
|
+
name: 'Places',
|
|
239
|
+
posts: [
|
|
240
|
+
{
|
|
241
|
+
id: '2',
|
|
242
|
+
title: 'Post 2',
|
|
243
|
+
longText: 'This is a long text 2',
|
|
244
|
+
category: {
|
|
245
|
+
id: 'c2',
|
|
246
|
+
name: 'Places'
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
],
|
|
252
|
+
posts: [
|
|
253
|
+
{
|
|
254
|
+
id: '1',
|
|
255
|
+
title: 'Post 1',
|
|
256
|
+
category: {
|
|
257
|
+
id: 'c1',
|
|
258
|
+
name: 'Food'
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
id: '2',
|
|
263
|
+
title: 'Post 2',
|
|
264
|
+
category: {
|
|
265
|
+
id: 'c2',
|
|
266
|
+
name: 'Places'
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: '3',
|
|
271
|
+
title: 'Post 3',
|
|
272
|
+
category: {
|
|
273
|
+
id: 'c1',
|
|
274
|
+
name: 'Food'
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: '4',
|
|
279
|
+
title: 'Post 4',
|
|
280
|
+
category: {
|
|
281
|
+
id: 'c1',
|
|
282
|
+
name: 'Food'
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
t.comment('first request')
|
|
290
|
+
|
|
291
|
+
{
|
|
292
|
+
const res = await app.inject({
|
|
293
|
+
method: 'POST',
|
|
294
|
+
url: '/graphql',
|
|
295
|
+
body: { query }
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
t.same(res.json(), expected)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
t.comment('second request')
|
|
302
|
+
|
|
303
|
+
{
|
|
304
|
+
const res = await app.inject({
|
|
305
|
+
method: 'POST',
|
|
306
|
+
url: '/graphql',
|
|
307
|
+
body: { query }
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
t.same(res.json(), expected)
|
|
311
|
+
}
|
|
312
|
+
})
|
package/test/helper.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Needed to work with dates & postgresql
|
|
4
|
+
// See https://node-postgres.com/features/types/
|
|
5
|
+
process.env.TZ = 'UTC'
|
|
6
|
+
|
|
7
|
+
const connInfo = {}
|
|
8
|
+
|
|
9
|
+
if (!process.env.DB || process.env.DB === 'postgresql') {
|
|
10
|
+
connInfo.connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'
|
|
11
|
+
module.exports.isPg = true
|
|
12
|
+
} else if (process.env.DB === 'mariadb') {
|
|
13
|
+
connInfo.connectionString = 'mysql://root@127.0.0.1:3307/graph'
|
|
14
|
+
connInfo.poolSize = 10
|
|
15
|
+
module.exports.isMysql = true
|
|
16
|
+
} else if (process.env.DB === 'mysql') {
|
|
17
|
+
connInfo.connectionString = 'mysql://root@127.0.0.1/graph'
|
|
18
|
+
connInfo.poolSize = 10
|
|
19
|
+
module.exports.isMysql = true
|
|
20
|
+
} else if (process.env.DB === 'mysql8') {
|
|
21
|
+
connInfo.connectionString = 'mysql://root@127.0.0.1:3308/graph'
|
|
22
|
+
connInfo.poolSize = 10
|
|
23
|
+
module.exports.isMysql = true
|
|
24
|
+
} else if (process.env.DB === 'sqlite') {
|
|
25
|
+
connInfo.connectionString = 'sqlite://:memory:'
|
|
26
|
+
module.exports.isSQLite = true
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports.connInfo = connInfo
|
|
30
|
+
|
|
31
|
+
module.exports.clear = async function (db, sql) {
|
|
32
|
+
try {
|
|
33
|
+
await db.query(sql`DROP TABLE pages`)
|
|
34
|
+
} catch (err) {
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
await db.query(sql`DROP TABLE categories`)
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
await db.query(sql`DROP TABLE posts`)
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await db.query(sql`DROP TABLE simple_types`)
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
await db.query(sql`DROP TABLE owners`)
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await db.query(sql`DROP TABLE users`)
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
await db.query(sql`DROP TABLE versions`)
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
await db.query(sql`DROP TABLE graphs`)
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
}
|