@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.
Files changed (54) hide show
  1. package/.nyc_output/0681b2b7-587a-40f2-8242-257bc4c72456.json +1 -0
  2. package/.nyc_output/191054d4-6a1e-4a1b-87bb-f801ed78a223.json +1 -0
  3. package/.nyc_output/22ead0f6-e5a6-4647-a2ea-db2f42498081.json +1 -0
  4. package/.nyc_output/4e847e26-05cd-4063-9277-48aff86d6822.json +1 -0
  5. package/.nyc_output/5acfd416-02d1-497b-8dbd-69c0af167c62.json +1 -0
  6. package/.nyc_output/5ec04f76-9bcb-475d-b79e-f9304cc0026c.json +1 -0
  7. package/.nyc_output/5f3bb47a-0d2d-440a-a466-8ffa9ab3efaa.json +1 -0
  8. package/.nyc_output/71c2bd84-9a72-4e86-83c6-d587ce525fe4.json +1 -0
  9. package/.nyc_output/74cc1dab-7479-48e7-80b0-c97351d8856e.json +1 -0
  10. package/.nyc_output/9f5d12ba-bc3d-461c-a0e2-2a95d2020c19.json +1 -0
  11. package/.nyc_output/ac343b71-6f76-421c-a287-46d19bb48f89.json +1 -0
  12. package/.nyc_output/c1c0eecb-63a0-4258-81b6-50e7488bd67c.json +1 -0
  13. package/.nyc_output/c201a1cd-3105-4d18-bbbb-8d7fa674d439.json +1 -0
  14. package/.nyc_output/d6da0270-e9ed-41e2-bbf3-9262d1df683c.json +1 -0
  15. package/.nyc_output/processinfo/0681b2b7-587a-40f2-8242-257bc4c72456.json +1 -0
  16. package/.nyc_output/processinfo/191054d4-6a1e-4a1b-87bb-f801ed78a223.json +1 -0
  17. package/.nyc_output/processinfo/22ead0f6-e5a6-4647-a2ea-db2f42498081.json +1 -0
  18. package/.nyc_output/processinfo/4e847e26-05cd-4063-9277-48aff86d6822.json +1 -0
  19. package/.nyc_output/processinfo/5acfd416-02d1-497b-8dbd-69c0af167c62.json +1 -0
  20. package/.nyc_output/processinfo/5ec04f76-9bcb-475d-b79e-f9304cc0026c.json +1 -0
  21. package/.nyc_output/processinfo/5f3bb47a-0d2d-440a-a466-8ffa9ab3efaa.json +1 -0
  22. package/.nyc_output/processinfo/71c2bd84-9a72-4e86-83c6-d587ce525fe4.json +1 -0
  23. package/.nyc_output/processinfo/74cc1dab-7479-48e7-80b0-c97351d8856e.json +1 -0
  24. package/.nyc_output/processinfo/9f5d12ba-bc3d-461c-a0e2-2a95d2020c19.json +1 -0
  25. package/.nyc_output/processinfo/ac343b71-6f76-421c-a287-46d19bb48f89.json +1 -0
  26. package/.nyc_output/processinfo/c1c0eecb-63a0-4258-81b6-50e7488bd67c.json +1 -0
  27. package/.nyc_output/processinfo/c201a1cd-3105-4d18-bbbb-8d7fa674d439.json +1 -0
  28. package/.nyc_output/processinfo/d6da0270-e9ed-41e2-bbf3-9262d1df683c.json +1 -0
  29. package/.nyc_output/processinfo/index.json +1 -0
  30. package/.taprc +1 -0
  31. package/LICENSE +201 -0
  32. package/NOTICE +13 -0
  33. package/README.md +13 -0
  34. package/index.d.ts +40 -0
  35. package/index.js +117 -0
  36. package/lib/entity-to-type.js +248 -0
  37. package/lib/relationship.js +67 -0
  38. package/lib/utils.js +77 -0
  39. package/package.json +44 -0
  40. package/test/datatypes.test.js +708 -0
  41. package/test/federation.test.js +312 -0
  42. package/test/helper.js +70 -0
  43. package/test/hooks.test.js +660 -0
  44. package/test/ignore.test.js +117 -0
  45. package/test/insert.test.js +181 -0
  46. package/test/inserted_updated_at.test.js +517 -0
  47. package/test/nested.test.js +862 -0
  48. package/test/no-modification-of-entity.test.js +113 -0
  49. package/test/order_by.test.js +397 -0
  50. package/test/relations.test.js +60 -0
  51. package/test/simple.test.js +708 -0
  52. package/test/sqlite.test.js +276 -0
  53. package/test/types/index.test-d.ts +33 -0
  54. package/test/where.test.js +814 -0
@@ -0,0 +1,113 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const sqlGraphQL = require('..')
5
+ const sqlMapper = require('@platformatic/sql-mapper')
6
+ const fastify = require('fastify')
7
+ const { clear, connInfo, isSQLite, isMysql } = require('./helper')
8
+
9
+ async function createBasicPages (db, sql) {
10
+ if (isSQLite) {
11
+ await db.query(sql`CREATE TABLE pages (
12
+ id INTEGER PRIMARY KEY,
13
+ title VARCHAR(42)
14
+ );`)
15
+ } else {
16
+ await db.query(sql`CREATE TABLE pages (
17
+ id SERIAL PRIMARY KEY,
18
+ title VARCHAR(42)
19
+ );`)
20
+ }
21
+ }
22
+
23
+ test('no modification of entity', async ({ teardown, equal, pass }) => {
24
+ const app = fastify()
25
+ app.register(sqlMapper, {
26
+ ...connInfo,
27
+ async onDatabaseLoad (db, sql) {
28
+ pass('onDatabaseLoad called')
29
+
30
+ await clear(db, sql)
31
+ await createBasicPages(db, sql)
32
+ }
33
+ })
34
+ app.register(sqlGraphQL)
35
+ teardown(app.close.bind(app))
36
+
37
+ await app.ready()
38
+
39
+ equal(app.platformatic.entities.page.type, undefined, 'no type in entity')
40
+
41
+ for (const field of Object.values(app.platformatic.entities.page.fields)) {
42
+ equal(field.type, undefined, `no type in field ${field.camelcase}`)
43
+ }
44
+ })
45
+
46
+ test('no modification of entity with nested data', async ({ pass, teardown, same, equal }) => {
47
+ const app = fastify()
48
+ app.register(sqlMapper, {
49
+ ...connInfo,
50
+ async onDatabaseLoad (db, sql) {
51
+ pass('onDatabaseLoad called')
52
+
53
+ await clear(db, sql)
54
+
55
+ if (isMysql) {
56
+ await db.query(sql`
57
+ CREATE TABLE categories (
58
+ id SERIAL PRIMARY KEY,
59
+ name VARCHAR(255)
60
+ );
61
+ CREATE TABLE pages (
62
+ id SERIAL PRIMARY KEY,
63
+ title VARCHAR(42),
64
+ category_id BIGINT UNSIGNED,
65
+ FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
66
+ );
67
+ `)
68
+ } else if (isSQLite) {
69
+ await db.query(sql`
70
+ CREATE TABLE categories (
71
+ id INTEGER PRIMARY KEY,
72
+ name VARCHAR(42)
73
+ );
74
+ `)
75
+ await db.query(sql`
76
+ CREATE TABLE pages (
77
+ id INTEGER PRIMARY KEY,
78
+ title VARCHAR(42),
79
+ category_id INTEGER REFERENCES categories(id)
80
+ );
81
+ `)
82
+ } else {
83
+ await db.query(sql`
84
+ CREATE TABLE categories (
85
+ id SERIAL PRIMARY KEY,
86
+ name VARCHAR(42)
87
+ );
88
+ CREATE TABLE pages (
89
+ id SERIAL PRIMARY KEY,
90
+ title VARCHAR(42),
91
+ category_id INTEGER REFERENCES categories(id)
92
+ );
93
+ `)
94
+ }
95
+ }
96
+ })
97
+ app.register(sqlGraphQL)
98
+ teardown(app.close.bind(app))
99
+
100
+ await app.ready()
101
+
102
+ equal(app.platformatic.entities.page.type, undefined, 'no type in entity')
103
+
104
+ for (const field of Object.values(app.platformatic.entities.page.fields)) {
105
+ equal(field.type, undefined, `no type in field ${field.camelcase}`)
106
+ }
107
+
108
+ equal(app.platformatic.entities.category.type, undefined, 'no type in entity')
109
+
110
+ for (const field of Object.values(app.platformatic.entities.category.fields)) {
111
+ equal(field.type, undefined, `no type in field ${field.camelcase}`)
112
+ }
113
+ })
@@ -0,0 +1,397 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const sqlGraphQL = require('..')
5
+ const sqlMapper = require('@platformatic/sql-mapper')
6
+ const fastify = require('fastify')
7
+ const { clear, connInfo, isSQLite, isMysql } = require('./helper')
8
+
9
+ test('one-level order by', async ({ pass, teardown, same, equal }) => {
10
+ const app = fastify()
11
+ app.register(sqlMapper, {
12
+ ...connInfo,
13
+ async onDatabaseLoad (db, sql) {
14
+ pass('onDatabaseLoad called')
15
+
16
+ await clear(db, sql)
17
+
18
+ if (isSQLite) {
19
+ await db.query(sql`CREATE TABLE pages (
20
+ id INTEGER PRIMARY KEY,
21
+ title VARCHAR(42),
22
+ counter INTEGER
23
+ );`)
24
+ } else {
25
+ await db.query(sql`CREATE TABLE pages (
26
+ id SERIAL PRIMARY KEY,
27
+ title VARCHAR(42),
28
+ counter INTEGER
29
+ );`)
30
+ }
31
+ }
32
+ })
33
+ app.register(sqlGraphQL)
34
+ teardown(app.close.bind(app))
35
+
36
+ await app.ready()
37
+
38
+ {
39
+ const res = await app.inject({
40
+ method: 'POST',
41
+ url: '/graphql',
42
+ body: {
43
+ query: `
44
+ mutation batch($inputs : [PageInput]!) {
45
+ insertPages (inputs: $inputs) {
46
+ id
47
+ title
48
+ counter
49
+ }
50
+ }
51
+ `,
52
+ variables: {
53
+ inputs: [
54
+ { title: 'Page 1', counter: 3 },
55
+ { title: 'Page 2', counter: 2 },
56
+ { title: 'Page 3', counter: 1 }
57
+ ]
58
+ }
59
+ }
60
+ })
61
+ equal(res.statusCode, 200, 'savePage status code')
62
+ same(res.json(), {
63
+ data: {
64
+ insertPages: [
65
+ { id: 1, title: 'Page 1', counter: 3 },
66
+ { id: 2, title: 'Page 2', counter: 2 },
67
+ { id: 3, title: 'Page 3', counter: 1 }
68
+ ]
69
+ }
70
+ }, 'savePage response')
71
+ }
72
+
73
+ {
74
+ const res = await app.inject({
75
+ method: 'POST',
76
+ url: '/graphql',
77
+ body: {
78
+ query: `
79
+ query {
80
+ pages (orderBy: { field: counter, direction: ASC }) {
81
+ id
82
+ title
83
+ counter
84
+ }
85
+ }
86
+ `
87
+ }
88
+ })
89
+ equal(res.statusCode, 200, 'pages status code')
90
+ same(res.json(), {
91
+ data: {
92
+ pages: [
93
+ { id: 3, title: 'Page 3', counter: 1 },
94
+ { id: 2, title: 'Page 2', counter: 2 },
95
+ { id: 1, title: 'Page 1', counter: 3 }
96
+ ]
97
+ }
98
+ }, 'pages response')
99
+ }
100
+
101
+ {
102
+ const res = await app.inject({
103
+ method: 'POST',
104
+ url: '/graphql',
105
+ body: {
106
+ query: `
107
+ query {
108
+ pages (orderBy: { field: counter, direction: DESC }) {
109
+ id
110
+ title
111
+ counter
112
+ }
113
+ }
114
+ `
115
+ }
116
+ })
117
+ equal(res.statusCode, 200, 'pages status code')
118
+ same(res.json(), {
119
+ data: {
120
+ pages: [
121
+ { id: 1, title: 'Page 1', counter: 3 },
122
+ { id: 2, title: 'Page 2', counter: 2 },
123
+ { id: 3, title: 'Page 3', counter: 1 }
124
+ ]
125
+ }
126
+ }, 'pages response')
127
+ }
128
+
129
+ {
130
+ const res = await app.inject({
131
+ method: 'POST',
132
+ url: '/graphql',
133
+ body: {
134
+ query: `
135
+ query {
136
+ pages (orderBy: { field: counter}) {
137
+ id
138
+ title
139
+ counter
140
+ }
141
+ }
142
+ `
143
+ }
144
+ })
145
+ equal(res.statusCode, 400, 'pages status code')
146
+ same(res.json(), {
147
+ data: null,
148
+ errors: [{
149
+ message: 'Field "PageOrderByArguments.direction" of required type "OrderByDirection!" was not provided.',
150
+ locations: [{
151
+ line: 3,
152
+ column: 29
153
+ }
154
+ ]
155
+ }]
156
+ })
157
+ }
158
+ })
159
+
160
+ test('list order by', async ({ pass, teardown, same, equal }) => {
161
+ const app = fastify()
162
+ app.register(sqlMapper, {
163
+ ...connInfo,
164
+ async onDatabaseLoad (db, sql) {
165
+ pass('onDatabaseLoad called')
166
+
167
+ await clear(db, sql)
168
+
169
+ if (isSQLite) {
170
+ await db.query(sql`CREATE TABLE pages (
171
+ id INTEGER PRIMARY KEY,
172
+ counter INTEGER,
173
+ counter2 INTEGER
174
+ );`)
175
+ } else {
176
+ await db.query(sql`CREATE TABLE pages (
177
+ id SERIAL PRIMARY KEY,
178
+ counter INTEGER,
179
+ counter2 INTEGER
180
+ );`)
181
+ }
182
+ }
183
+ })
184
+ app.register(sqlGraphQL)
185
+ teardown(app.close.bind(app))
186
+
187
+ await app.ready()
188
+
189
+ {
190
+ const res = await app.inject({
191
+ method: 'POST',
192
+ url: '/graphql',
193
+ body: {
194
+ query: `
195
+ mutation batch($inputs : [PageInput]!) {
196
+ insertPages (inputs: $inputs) {
197
+ id
198
+ counter
199
+ counter2
200
+ }
201
+ }
202
+ `,
203
+ variables: {
204
+ inputs: [
205
+ { counter: 3, counter2: 3 },
206
+ { counter: 3, counter2: 2 },
207
+ { counter: 1, counter2: 1 }
208
+ ]
209
+ }
210
+ }
211
+ })
212
+ equal(res.statusCode, 200, 'savePage status code')
213
+ same(res.json(), {
214
+ data: {
215
+ insertPages: [
216
+ { id: 1, counter: 3, counter2: 3 },
217
+ { id: 2, counter: 3, counter2: 2 },
218
+ { id: 3, counter: 1, counter2: 1 }
219
+ ]
220
+ }
221
+ }, 'savePage response')
222
+ }
223
+
224
+ {
225
+ const res = await app.inject({
226
+ method: 'POST',
227
+ url: '/graphql',
228
+ body: {
229
+ query: `
230
+ query {
231
+ pages (orderBy: [{ field: counter, direction: ASC }, { field: counter2, direction: DESC }]) {
232
+ id
233
+ counter,
234
+ counter2
235
+ }
236
+ }
237
+ `
238
+ }
239
+ })
240
+ equal(res.statusCode, 200, 'pages status code')
241
+ same(res.json(), {
242
+ data: {
243
+ pages: [
244
+ { id: 3, counter: 1, counter2: 1 },
245
+ { id: 1, counter: 3, counter2: 3 },
246
+ { id: 2, counter: 3, counter2: 2 }
247
+ ]
248
+ }
249
+ }, 'pages response')
250
+ }
251
+ })
252
+
253
+ test('nested order by', async ({ pass, teardown, same, equal }) => {
254
+ const app = fastify()
255
+ app.register(sqlMapper, {
256
+ ...connInfo,
257
+ async onDatabaseLoad (db, sql) {
258
+ pass('onDatabaseLoad called')
259
+
260
+ await clear(db, sql)
261
+
262
+ if (isMysql) {
263
+ await db.query(sql`
264
+ CREATE TABLE categories (
265
+ id SERIAL PRIMARY KEY,
266
+ name VARCHAR(255)
267
+ );
268
+ CREATE TABLE pages (
269
+ id SERIAL PRIMARY KEY,
270
+ title VARCHAR(42),
271
+ category_id BIGINT UNSIGNED,
272
+ FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
273
+ );
274
+ `)
275
+ } else if (isSQLite) {
276
+ await db.query(sql`
277
+ CREATE TABLE categories (
278
+ id INTEGER PRIMARY KEY,
279
+ name VARCHAR(42)
280
+ );
281
+ `)
282
+ await db.query(sql`
283
+ CREATE TABLE pages (
284
+ id INTEGER PRIMARY KEY,
285
+ title VARCHAR(42),
286
+ category_id INTEGER REFERENCES categories(id)
287
+ );
288
+ `)
289
+ } else {
290
+ await db.query(sql`
291
+ CREATE TABLE categories (
292
+ id SERIAL PRIMARY KEY,
293
+ name VARCHAR(42)
294
+ );
295
+ CREATE TABLE pages (
296
+ id SERIAL PRIMARY KEY,
297
+ title VARCHAR(42),
298
+ category_id INTEGER REFERENCES categories(id)
299
+ );
300
+ `)
301
+ }
302
+ }
303
+ })
304
+ app.register(sqlGraphQL)
305
+ teardown(app.close.bind(app))
306
+
307
+ const categories = [{
308
+ name: 'Pets'
309
+ }, {
310
+ name: 'Food'
311
+ }]
312
+
313
+ await app.inject({
314
+ method: 'POST',
315
+ url: '/graphql',
316
+ body: {
317
+ query: `
318
+ mutation batch($inputs: [CategoryInput]!) {
319
+ insertCategories(inputs: $inputs) {
320
+ id
321
+ name
322
+ }
323
+ }
324
+ `,
325
+ variables: {
326
+ inputs: categories
327
+ }
328
+ }
329
+ })
330
+
331
+ const pages = [{
332
+ title: 'foo',
333
+ categoryId: 1
334
+ }, {
335
+ title: 'bar',
336
+ categoryId: 1
337
+ }]
338
+
339
+ await app.inject({
340
+ method: 'POST',
341
+ url: '/graphql',
342
+ body: {
343
+ query: `
344
+ mutation batch($inputs: [PageInput]!) {
345
+ insertPages(inputs: $inputs) {
346
+ id
347
+ title
348
+ }
349
+ }
350
+ `,
351
+ variables: {
352
+ inputs: pages
353
+ }
354
+ }
355
+ })
356
+
357
+ {
358
+ const res = await app.inject({
359
+ method: 'POST',
360
+ url: '/graphql',
361
+ body: {
362
+ query: `
363
+ query {
364
+ categories {
365
+ id
366
+ name
367
+ pages(orderBy: { field: title, direction: ASC }) {
368
+ id
369
+ title
370
+ }
371
+ }
372
+ }
373
+ `
374
+ }
375
+ })
376
+ equal(res.statusCode, 200, 'categories.posts status code')
377
+ same(res.json(), {
378
+ data: {
379
+ categories: [{
380
+ id: 1,
381
+ name: 'Pets',
382
+ pages: [{
383
+ id: 2,
384
+ title: 'bar'
385
+ }, {
386
+ id: 1,
387
+ title: 'foo'
388
+ }]
389
+ }, {
390
+ id: 2,
391
+ name: 'Food',
392
+ pages: []
393
+ }]
394
+ }
395
+ }, 'categories.posts response')
396
+ }
397
+ })
@@ -0,0 +1,60 @@
1
+ 'use strict'
2
+
3
+ const { skip, test } = require('tap')
4
+ const { tmpdir } = require('os')
5
+ const { randomUUID } = require('crypto')
6
+ const { join } = require('path')
7
+ const sqlGraphQL = require('..')
8
+ const sqlMapper = require('@platformatic/sql-mapper')
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
+ }
16
+
17
+ test('should fail when an unknown foreign key relationship exists', async ({ pass, rejects, same, teardown }) => {
18
+ const file = join(tmpdir(), randomUUID())
19
+ const app = fastify()
20
+ app.register(sqlMapper, {
21
+ connectionString: `sqlite://${file}`,
22
+ async onDatabaseLoad (db, sql) {
23
+ pass('onDatabaseLoad called')
24
+
25
+ await db.query(sql`
26
+ CREATE TABLE categories (
27
+ id INTEGER PRIMARY KEY,
28
+ name TEXT NOT NULL
29
+ );
30
+ );`)
31
+
32
+ await db.query(sql`
33
+ CREATE TABLE pages (
34
+ id INTEGER PRIMARY KEY,
35
+ title TEXT,
36
+ body TEXT,
37
+ category_id INTEGER,
38
+ FOREIGN KEY (category_id) REFERENCES subcategories(id) ON DELETE CASCADE
39
+ );
40
+ );`)
41
+ }
42
+ })
43
+ app.register(sqlGraphQL)
44
+ teardown(app.close.bind(app))
45
+
46
+ await rejects(app.inject({
47
+ method: 'POST',
48
+ url: '/graphql',
49
+ body: {
50
+ query: `
51
+ mutation {
52
+ saveCategory(input: { name: "pets" }) {
53
+ id
54
+ name
55
+ }
56
+ }
57
+ `
58
+ }
59
+ }), new Error('No foreign table named "subcategories" was found'))
60
+ })