@platformatic/sql-graphql 0.46.1 → 0.47.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.
@@ -1,959 +0,0 @@
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, isMariaDB, isPg } = 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('simple db simple graphql schema', async ({ pass, teardown, same, equal }) => {
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
- {
40
- const res = await app.inject({
41
- method: 'POST',
42
- url: '/graphql',
43
- body: {
44
- query: `
45
- mutation {
46
- savePage(input: { title: "Hello" }) {
47
- id
48
- title
49
- }
50
- }
51
- `
52
- }
53
- })
54
- equal(res.statusCode, 200, 'savePage status code')
55
- same(res.json(), {
56
- data: {
57
- savePage: {
58
- id: 1,
59
- title: 'Hello'
60
- }
61
- }
62
- }, 'savePage response')
63
- }
64
-
65
- {
66
- const res = await app.inject({
67
- method: 'POST',
68
- url: '/graphql',
69
- body: {
70
- query: `
71
- query {
72
- getPageById(id: 1) {
73
- id
74
- title
75
- }
76
- }
77
- `
78
- }
79
- })
80
- equal(res.statusCode, 200, 'pages status code')
81
- same(res.json(), {
82
- data: {
83
- getPageById: {
84
- id: 1,
85
- title: 'Hello'
86
- }
87
- }
88
- }, 'pages response')
89
- }
90
-
91
- {
92
- const res = await app.inject({
93
- method: 'POST',
94
- url: '/graphql',
95
- body: {
96
- query: `
97
- mutation {
98
- savePage(input: { id: 1, title: "Hello World" }) {
99
- id
100
- title
101
- }
102
- }
103
- `
104
- }
105
- })
106
- equal(res.statusCode, 200, 'savePage status code')
107
- same(res.json(), {
108
- data: {
109
- savePage: {
110
- id: 1,
111
- title: 'Hello World'
112
- }
113
- }
114
- }, 'savePage response')
115
- }
116
-
117
- {
118
- const res = await app.inject({
119
- method: 'POST',
120
- url: '/graphql',
121
- body: {
122
- query: `
123
- query {
124
- getPageById(id: 1) {
125
- id
126
- title
127
- }
128
- }
129
- `
130
- }
131
- })
132
- equal(res.statusCode, 200, 'pages status code')
133
- same(res.json(), {
134
- data: {
135
- getPageById: {
136
- id: 1,
137
- title: 'Hello World'
138
- }
139
- }
140
- }, 'pages response')
141
- }
142
- })
143
-
144
- test('with federationMetadata', async ({ pass, teardown, same, equal }) => {
145
- const app = fastify()
146
- app.register(sqlMapper, {
147
- ...connInfo,
148
- federationMetadata: true,
149
- async onDatabaseLoad (db, sql) {
150
- pass('onDatabaseLoad called')
151
-
152
- await clear(db, sql)
153
- await createBasicPages(db, sql)
154
- }
155
- })
156
- app.register(sqlGraphQL)
157
- teardown(app.close.bind(app))
158
-
159
- await app.ready()
160
-
161
- {
162
- const res = await app.inject({
163
- method: 'POST',
164
- url: '/graphql',
165
- body: {
166
- query: `
167
- mutation {
168
- savePage(input: { title: "Hello" }) {
169
- id
170
- title
171
- }
172
- }
173
- `
174
- }
175
- })
176
- equal(res.statusCode, 200, 'savePage status code')
177
- same(res.json(), {
178
- data: {
179
- savePage: {
180
- id: 1,
181
- title: 'Hello'
182
- }
183
- }
184
- }, 'savePage response')
185
- }
186
-
187
- {
188
- const res = await app.inject({
189
- method: 'POST',
190
- url: '/graphql',
191
- body: {
192
- query: `
193
- query {
194
- getPageById(id: 1) {
195
- id
196
- title
197
- }
198
- }
199
- `
200
- }
201
- })
202
- equal(res.statusCode, 200, 'pages status code')
203
- same(res.json(), {
204
- data: {
205
- getPageById: {
206
- id: 1,
207
- title: 'Hello'
208
- }
209
- }
210
- }, 'pages response')
211
- }
212
-
213
- {
214
- const res = await app.inject({
215
- method: 'POST',
216
- url: '/graphql',
217
- body: {
218
- query: `
219
- mutation {
220
- savePage(input: { id: 1, title: "Hello World" }) {
221
- id
222
- title
223
- }
224
- }
225
- `
226
- }
227
- })
228
- equal(res.statusCode, 200, 'savePage status code')
229
- same(res.json(), {
230
- data: {
231
- savePage: {
232
- id: 1,
233
- title: 'Hello World'
234
- }
235
- }
236
- }, 'savePage response')
237
- }
238
- })
239
-
240
- test('add resolver', async ({ pass, teardown, same, equal }) => {
241
- const app = fastify()
242
-
243
- const schema = `
244
- extend type Query {
245
- search(title: String!): [Page]
246
- }
247
- `
248
- const resolvers = {
249
- Query: {
250
- async search (root, args, context, info) {
251
- pass('search resolver called')
252
- const { db, sql } = context.app.platformatic
253
- const res = await db.query(sql`SELECT * FROM pages WHERE title LIKE ${'%' + args.title + '%'}`)
254
-
255
- return res
256
- }
257
- }
258
- }
259
-
260
- app.register(sqlMapper, {
261
- ...connInfo,
262
- async onDatabaseLoad (db, sql) {
263
- pass('onDatabaseLoad called')
264
-
265
- await clear(db, sql)
266
- await createBasicPages(db, sql)
267
- }
268
- })
269
- app.register(sqlGraphQL, {
270
- schema,
271
- resolvers
272
- })
273
- teardown(app.close.bind(app))
274
-
275
- await app.ready()
276
-
277
- {
278
- const res = await app.inject({
279
- method: 'POST',
280
- url: '/graphql',
281
- body: {
282
- query: `
283
- mutation {
284
- savePage(input: { title: "Hello World" }) {
285
- id
286
- title
287
- }
288
- }
289
- `
290
- }
291
- })
292
- equal(res.statusCode, 200, 'savePage status code')
293
- same(res.json(), {
294
- data: {
295
- savePage: {
296
- id: 1,
297
- title: 'Hello World'
298
- }
299
- }
300
- }, 'savePage response')
301
- }
302
-
303
- {
304
- const res = await app.inject({
305
- method: 'POST',
306
- url: '/graphql',
307
- body: {
308
- query: `
309
- mutation {
310
- savePage(input: { title: "ABC" }) {
311
- id
312
- title
313
- }
314
- }
315
- `
316
- }
317
- })
318
- equal(res.statusCode, 200, 'savePage status code')
319
- same(res.json(), {
320
- data: {
321
- savePage: {
322
- id: 2,
323
- title: 'ABC'
324
- }
325
- }
326
- }, 'savePage response')
327
- }
328
-
329
- {
330
- const res = await app.inject({
331
- method: 'POST',
332
- url: '/graphql',
333
- body: {
334
- query: `
335
- query {
336
- search(title: "Hello") {
337
- id
338
- title
339
- }
340
- }
341
- `
342
- }
343
- })
344
- equal(res.statusCode, 200, 'pages status code')
345
- same(res.json(), {
346
- data: {
347
- search: [{
348
- id: 1,
349
- title: 'Hello World'
350
- }]
351
- }
352
- }, 'pages response')
353
- }
354
- })
355
-
356
- test('override resolver', async ({ pass, teardown, same, equal, plan }) => {
357
- plan(3)
358
-
359
- const app = fastify()
360
- app.register(sqlMapper, {
361
- ...connInfo,
362
- async onDatabaseLoad (db, sql) {
363
- await clear(db, sql)
364
- await createBasicPages(db, sql)
365
- }
366
- })
367
- app.register(sqlGraphQL, {
368
- resolvers: {
369
- Mutation: {
370
- async savePage (root, args, context, info) {
371
- pass('savePage resolver called')
372
- const { db, sql } = context.app.platformatic
373
- if (isSQLite) {
374
- const insert = sql`
375
- INSERT INTO pages (title)
376
- VALUES (${args.input.title})
377
- `
378
-
379
- await db.query(insert)
380
-
381
- const res2 = await db.query(sql`
382
- SELECT last_insert_rowid()
383
- `)
384
-
385
- const id = res2[0]['last_insert_rowid()']
386
- return {
387
- ...args.input,
388
- id
389
- }
390
- } else if (isMysql && !db.isMariaDB) {
391
- const insert = sql`
392
- INSERT INTO pages (title)
393
- VALUES (${args.input.title})
394
- `
395
-
396
- await db.query(insert)
397
-
398
- const res2 = await db.query(sql`
399
- SELECT last_insert_id()
400
- `)
401
-
402
- const id = res2[0]['last_insert_id()']
403
- return {
404
- ...args.input,
405
- id
406
- }
407
- } else {
408
- const insert = sql`
409
- INSERT INTO pages (title)
410
- VALUES (${args.input.title})
411
- RETURNING *
412
- `
413
- const res = await db.query(insert)
414
- return res[0]
415
- }
416
- }
417
- }
418
- }
419
- })
420
- teardown(app.close.bind(app))
421
-
422
- const res = await app.inject({
423
- method: 'POST',
424
- url: '/graphql',
425
- body: {
426
- query: `
427
- mutation {
428
- savePage(input: { title: "Hello" }) {
429
- id
430
- title
431
- }
432
- }
433
- `
434
- }
435
- })
436
- equal(res.statusCode, 200, 'savePage status code')
437
- same(res.json(), {
438
- data: {
439
- savePage: {
440
- id: 1,
441
- title: 'Hello'
442
- }
443
- }
444
- }, 'savePage response')
445
- })
446
-
447
- test('add totally new type and resolver', async ({ pass, teardown, same, equal, plan }) => {
448
- plan(4)
449
-
450
- const app = fastify()
451
- app.register(sqlMapper, {
452
- ...connInfo,
453
- async onDatabaseLoad (db, sql) {
454
- await clear(db, sql)
455
- await createBasicPages(db, sql)
456
- }
457
- })
458
- app.register(sqlGraphQL, {
459
- schema: `
460
- type Category {
461
- id: ID!
462
- name: String
463
- upper: String
464
- }
465
-
466
- extend type Query {
467
- getCategory: Category
468
- }
469
- `,
470
- resolvers: {
471
- Query: {
472
- async getCategory (root, args, context, info) {
473
- pass('getCategory resolver called')
474
- return {
475
- id: 1,
476
- name: 'Hello'
477
- }
478
- }
479
- },
480
- Category: {
481
- upper (root, args, context, info) {
482
- pass('name resolver called')
483
- return root.name.toUpperCase()
484
- }
485
- }
486
- }
487
- })
488
- teardown(app.close.bind(app))
489
-
490
- const res = await app.inject({
491
- method: 'POST',
492
- url: '/graphql',
493
- body: {
494
- query: `
495
- query {
496
- getCategory {
497
- id
498
- name
499
- upper
500
- }
501
- }
502
- `
503
- }
504
- })
505
- equal(res.statusCode, 200, 'getCategory status code')
506
- same(res.json(), {
507
- data: {
508
- getCategory: {
509
- id: 1,
510
- name: 'Hello',
511
- upper: 'HELLO'
512
- }
513
- }
514
- }, 'getCategory response')
515
- })
516
-
517
- test('list', async ({ pass, teardown, same, equal }) => {
518
- const app = fastify()
519
- app.register(sqlMapper, {
520
- ...connInfo,
521
- async onDatabaseLoad (db, sql) {
522
- pass('onDatabaseLoad called')
523
-
524
- await clear(db, sql)
525
-
526
- if (isSQLite) {
527
- await db.query(sql`CREATE TABLE posts (
528
- id INTEGER PRIMARY KEY,
529
- title VARCHAR(42),
530
- long_text TEXT
531
- );`)
532
- } else {
533
- await db.query(sql`CREATE TABLE posts (
534
- id SERIAL PRIMARY KEY,
535
- title VARCHAR(42),
536
- long_text TEXT
537
- );`)
538
- }
539
- }
540
- })
541
- app.register(sqlGraphQL)
542
- teardown(app.close.bind(app))
543
-
544
- await app.ready()
545
-
546
- const posts = [{
547
- title: 'Post 1',
548
- longText: 'This is a long text 1'
549
- }, {
550
- title: 'Post 2',
551
- longText: 'This is a long text 2'
552
- }, {
553
- title: 'Post 3',
554
- longText: 'This is a long text 3'
555
- }, {
556
- title: 'Post 4',
557
- longText: 'This is a long text 4'
558
- }]
559
-
560
- for (const post of posts) {
561
- await app.inject({
562
- method: 'POST',
563
- url: '/graphql',
564
- body: {
565
- query: `
566
- mutation {
567
- savePost(input: { title: "${post.title}", longText: "${post.longText}" }) {
568
- id
569
- title,
570
- longText
571
- }
572
- }
573
- `
574
- }
575
- })
576
- }
577
-
578
- {
579
- const res = await app.inject({
580
- method: 'POST',
581
- url: '/graphql',
582
- body: {
583
- query: `
584
- query {
585
- posts {
586
- id
587
- title
588
- longText
589
- }
590
- }
591
- `
592
- }
593
- })
594
- equal(res.statusCode, 200, 'posts status code')
595
- same(res.json(), {
596
- data: {
597
- posts: posts.map((p, i) => {
598
- return { ...p, id: i + 1 + '' }
599
- })
600
- }
601
- }, 'posts response')
602
- }
603
-
604
- {
605
- const res = await app.inject({
606
- method: 'POST',
607
- url: '/graphql',
608
- body: {
609
- query: `
610
- query {
611
- posts (limit: 2, offset: 1) {
612
- id
613
- title
614
- longText
615
- }
616
- }
617
- `
618
- }
619
- })
620
- equal(res.statusCode, 200, 'posts status code')
621
- same(res.json(), {
622
- data: {
623
- posts: posts.map((p, i) => {
624
- return { ...p, id: i + 1 + '' }
625
- }).slice(1, 3)
626
- }
627
- }, 'posts response')
628
- }
629
- })
630
-
631
- test('not found', async ({ pass, teardown, same, equal }) => {
632
- const app = fastify()
633
- app.register(sqlMapper, {
634
- ...connInfo,
635
- async onDatabaseLoad (db, sql) {
636
- pass('onDatabaseLoad called')
637
-
638
- await clear(db, sql)
639
-
640
- await createBasicPages(db, sql)
641
- }
642
- })
643
- app.register(sqlGraphQL)
644
- teardown(app.close.bind(app))
645
-
646
- await app.ready()
647
-
648
- {
649
- const res = await app.inject({
650
- method: 'POST',
651
- url: '/graphql',
652
- body: {
653
- query: `
654
- query {
655
- getPageById(id: 1) {
656
- id
657
- title
658
- }
659
- }
660
- `
661
- }
662
- })
663
- equal(res.statusCode, 200, 'getPageById status code')
664
- same(res.json(), {
665
- data: {
666
- getPageById: null
667
- }
668
- }, 'getPageById response')
669
- }
670
- })
671
-
672
- test('graphiql is enabled by default', async ({ pass, teardown, same, equal }) => {
673
- const app = fastify()
674
- app.register(sqlMapper, {
675
- ...connInfo,
676
- async onDatabaseLoad (db, sql) {
677
- pass('onDatabaseLoad called')
678
-
679
- await clear(db, sql)
680
- await createBasicPages(db, sql)
681
- }
682
- })
683
- app.register(sqlGraphQL)
684
- teardown(app.close.bind(app))
685
-
686
- const res = await app.inject('/graphiql')
687
- equal(res.statusCode, 200)
688
- })
689
-
690
- test('graphiql can be disabled', async ({ pass, teardown, same, equal }) => {
691
- const app = fastify()
692
- app.register(sqlMapper, {
693
- ...connInfo,
694
- async onDatabaseLoad (db, sql) {
695
- pass('onDatabaseLoad called')
696
-
697
- await clear(db, sql)
698
- await createBasicPages(db, sql)
699
- }
700
- })
701
- app.register(sqlGraphQL, {
702
- graphiql: false
703
- })
704
- teardown(app.close.bind(app))
705
-
706
- const res = await app.inject('/graphiql')
707
- equal(res.statusCode, 404)
708
- })
709
-
710
- test('default query hello should be created when no entities are found', async ({ pass, teardown, same, equal }) => {
711
- const app = fastify()
712
- app.register(sqlMapper, {
713
- ...connInfo,
714
- async onDatabaseLoad (db, sql) {
715
- pass('onDatabaseLoad called')
716
- await clear(db, sql)
717
- }
718
- })
719
- app.register(sqlGraphQL)
720
- teardown(app.close.bind(app))
721
-
722
- const res = await app.inject({
723
- method: 'POST',
724
- url: '/graphql',
725
- body: {
726
- query: 'query { hello }'
727
- }
728
- })
729
- equal(res.statusCode, 200)
730
- same(res.json(), {
731
- data: {
732
- hello: 'Hello Platformatic!'
733
- }
734
- })
735
- })
736
-
737
- test('default query hello should not be created when entities are found', async ({ pass, teardown, same, equal }) => {
738
- const app = fastify()
739
- app.register(sqlMapper, {
740
- ...connInfo,
741
- async onDatabaseLoad (db, sql) {
742
- pass('onDatabaseLoad called')
743
- await clear(db, sql)
744
- await createBasicPages(db, sql)
745
- }
746
- })
747
- app.register(sqlGraphQL)
748
- teardown(app.close.bind(app))
749
-
750
- const res = await app.inject({
751
- method: 'POST',
752
- url: '/graphql',
753
- body: {
754
- query: 'query { hello }'
755
- }
756
- })
757
- equal(res.statusCode, 400)
758
- const json = res.json()
759
- same(json.data, null)
760
- same(json.errors[0].message, 'Cannot query field "hello" on type "Query".')
761
- })
762
-
763
- test('primary key snake_case', async ({ pass, teardown, same, equal }) => {
764
- async function createBasicPagesWithSnakeCasePK (db, sql) {
765
- if (isSQLite) {
766
- await db.query(sql`CREATE TABLE pages (
767
- page_id INTEGER PRIMARY KEY,
768
- title VARCHAR(42)
769
- );`)
770
- } else {
771
- await db.query(sql`CREATE TABLE pages (
772
- page_id SERIAL PRIMARY KEY,
773
- title VARCHAR(42)
774
- );`)
775
- }
776
- }
777
-
778
- const app = fastify()
779
- app.register(sqlMapper, {
780
- ...connInfo,
781
- async onDatabaseLoad (db, sql) {
782
- pass('onDatabaseLoad called')
783
-
784
- await clear(db, sql)
785
- await createBasicPagesWithSnakeCasePK(db, sql)
786
- }
787
- })
788
- app.register(sqlGraphQL, {
789
- graphiql: false
790
- })
791
- teardown(app.close.bind(app))
792
-
793
- const res = await app.inject('/graphiql')
794
- equal(res.statusCode, 404)
795
-
796
- {
797
- const res = await app.inject({
798
- method: 'POST',
799
- url: '/graphql',
800
- body: {
801
- query: `
802
- mutation {
803
- savePage(input: { title: "Hello" }) {
804
- pageId
805
- title
806
- }
807
- }
808
- `
809
- }
810
- })
811
- equal(res.statusCode, 200, 'savePage status code')
812
- same(res.json(), {
813
- data: {
814
- savePage: {
815
- pageId: 1,
816
- title: 'Hello'
817
- }
818
- }
819
- }, 'savePage response')
820
- }
821
-
822
- {
823
- const res = await app.inject({
824
- method: 'POST',
825
- url: '/graphql',
826
- body: {
827
- query: `
828
- query {
829
- getPageByPageId(pageId: 1) {
830
- pageId
831
- title
832
- }
833
- }
834
- `
835
- }
836
- })
837
- equal(res.statusCode, 200, 'pages status code')
838
- same(res.json(), {
839
- data: {
840
- getPageByPageId: {
841
- pageId: 1,
842
- title: 'Hello'
843
- }
844
- }
845
- }, 'pages response')
846
- }
847
- })
848
-
849
- test('deserialize JSON columns', { skip: isSQLite }, async (t) => {
850
- const { pass, teardown, same } = t
851
- const app = fastify()
852
- const jsonData = {
853
- foo: 'bar',
854
- baz: 42,
855
- items: ['foo', 'bar'],
856
- nested: {
857
- hello: 'world'
858
- }
859
- }
860
- app.register(sqlMapper, {
861
- ...connInfo,
862
- async onDatabaseLoad (db, sql) {
863
- pass('onDatabaseLoad called')
864
-
865
- await clear(db, sql)
866
-
867
- await db.query(sql`CREATE TABLE pages (
868
- id SERIAL PRIMARY KEY,
869
- title VARCHAR(255) NOT NULL,
870
- metadata JSON NOT NULL
871
- );`)
872
-
873
- await db.query(sql`INSERT INTO pages (id, title, metadata) VALUES (1, 'Hello World', ${JSON.stringify(jsonData)})`)
874
- }
875
- })
876
- app.register(sqlGraphQL, {
877
- graphiql: false
878
- })
879
- teardown(app.close.bind(app))
880
-
881
- await app.ready()
882
- const res = await app.inject({
883
- method: 'POST',
884
- url: '/graphql',
885
- body: {
886
- query: `
887
- query {
888
- getPageById(id: 1) {
889
- id
890
- title
891
- metadata
892
- }
893
- }
894
- `
895
- }
896
- })
897
- const json = res.json()
898
- if (isMariaDB) {
899
- same(json.data.getPageById.metadata, JSON.stringify(jsonData))
900
- } else {
901
- same(json.data.getPageById.metadata, jsonData)
902
- }
903
- })
904
-
905
- test('deserialize JSONB columns', { skip: !isPg }, async (t) => {
906
- const { pass, teardown, same } = t
907
- const app = fastify()
908
- const jsonData = {
909
- foo: 'bar',
910
- baz: 42,
911
- items: ['foo', 'bar'],
912
- nested: {
913
- hello: 'world'
914
- }
915
- }
916
- app.register(sqlMapper, {
917
- ...connInfo,
918
- async onDatabaseLoad (db, sql) {
919
- pass('onDatabaseLoad called')
920
-
921
- await clear(db, sql)
922
-
923
- await db.query(sql`CREATE TABLE pages (
924
- id SERIAL PRIMARY KEY,
925
- title VARCHAR(255) NOT NULL,
926
- metadata JSONB NOT NULL
927
- );`)
928
-
929
- await db.query(sql`INSERT INTO pages (id, title, metadata) VALUES (1, 'Hello World', ${JSON.stringify(jsonData)})`)
930
- }
931
- })
932
- app.register(sqlGraphQL, {
933
- graphiql: false
934
- })
935
- teardown(app.close.bind(app))
936
-
937
- await app.ready()
938
- const res = await app.inject({
939
- method: 'POST',
940
- url: '/graphql',
941
- body: {
942
- query: `
943
- query {
944
- getPageById(id: 1) {
945
- id
946
- title
947
- metadata
948
- }
949
- }
950
- `
951
- }
952
- })
953
- const json = res.json()
954
- if (isMariaDB) {
955
- same(json.data.getPageById.metadata, JSON.stringify(jsonData))
956
- } else {
957
- same(json.data.getPageById.metadata, jsonData)
958
- }
959
- })