@platformatic/sql-graphql 0.9.1 → 0.10.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/lib/entity-to-type.js +1 -0
- package/lib/relationship.js +13 -8
- package/lib/utils.js +3 -1
- package/package.json +3 -3
- package/test/datatypes.test.js +79 -0
- package/test/fix-428.test.js +172 -0
- package/test/nested.test.js +252 -0
package/lib/entity-to-type.js
CHANGED
package/lib/relationship.js
CHANGED
|
@@ -20,19 +20,20 @@ module.exports = function establishRelations (app, relations, resolvers, loaders
|
|
|
20
20
|
|
|
21
21
|
assert(table_name, `table_name is required ${enhanceAssertLogMsg}`)
|
|
22
22
|
assert(foreign_table_name, `foreign_table_name is required ${enhanceAssertLogMsg}`)
|
|
23
|
-
assert(column_name.toLowerCase().endsWith('id'), `The column with id reference must be ended with "id" postfix ${enhanceAssertLogMsg}`)
|
|
24
23
|
|
|
25
24
|
const current = tablesTypeMap[table_name]
|
|
26
25
|
const foreign = tablesTypeMap[foreign_table_name]
|
|
27
26
|
assert(foreign !== undefined, `No foreign table named "${foreign_table_name}" was found ${enhanceAssertLogMsg}`)
|
|
28
27
|
|
|
29
|
-
// current to foreign
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
// current to foreign, we skip this if the foreign table has a composite primary key
|
|
29
|
+
// TODO implement support for this case
|
|
30
|
+
/* istanbul ignore else */
|
|
31
|
+
if (foreign.entity.primaryKeys.size === 1) {
|
|
32
|
+
const lowered = generateRelationshipName(column_name, foreign)
|
|
32
33
|
if (!relationships[current.type] || relationships[current.type][lowered] !== false) {
|
|
33
|
-
current.fields[lowered] = { type: foreign.type }
|
|
34
34
|
const originalField = camelcase(column_name)
|
|
35
35
|
delete current.fields[originalField]
|
|
36
|
+
current.fields[lowered] = { type: foreign.type }
|
|
36
37
|
loaders[current.type] = loaders[current.type] || resolvers[current.type] || {}
|
|
37
38
|
const key = camelcase(foreign_column_name)
|
|
38
39
|
loaders[current.type][lowered] = {
|
|
@@ -59,7 +60,7 @@ module.exports = function establishRelations (app, relations, resolvers, loaders
|
|
|
59
60
|
resolvers[foreign.type] = resolvers[foreign.type] || {}
|
|
60
61
|
const resolveRelation = async function (obj, args, ctx, info) {
|
|
61
62
|
const fields = fromSelectionSet(info.fieldNodes[0].selectionSet, new Set())
|
|
62
|
-
const toSearch = { ...args, fields: [...fields, column_name], ctx }
|
|
63
|
+
const toSearch = { ...args, fields: [...fields, column_name, ...current.relationalFields], ctx }
|
|
63
64
|
toSearch.where = toSearch.where || {}
|
|
64
65
|
toSearch.where[camelcase(column_name)] = { eq: obj.id }
|
|
65
66
|
return current.entity.find(toSearch)
|
|
@@ -84,9 +85,13 @@ function lowerCaseFirst (str) {
|
|
|
84
85
|
return str.charAt(0).toLowerCase() + str.slice(1)
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
function
|
|
88
|
+
function generateRelationshipName (str, foreign) {
|
|
89
|
+
const primaryKey = foreign.entity.primaryKeys.values().next().value
|
|
88
90
|
str = str.toString()
|
|
89
|
-
|
|
91
|
+
if (str.endsWith('_' + primaryKey)) {
|
|
92
|
+
str = str.slice(0, -2)
|
|
93
|
+
}
|
|
94
|
+
return lowerCaseFirst(camelcase(str))
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
function findPrimaryColumnName (camelCasedFields) {
|
package/lib/utils.js
CHANGED
|
@@ -21,11 +21,13 @@ function sqlTypeToGraphQL (sqlType) {
|
|
|
21
21
|
case 'decimal':
|
|
22
22
|
return graphql.GraphQLInt
|
|
23
23
|
case 'bigint':
|
|
24
|
-
return graphql.
|
|
24
|
+
return graphql.GraphQLString
|
|
25
25
|
case 'int2':
|
|
26
26
|
return graphql.GraphQLInt
|
|
27
27
|
case 'int4':
|
|
28
28
|
return graphql.GraphQLInt
|
|
29
|
+
case 'int8':
|
|
30
|
+
return graphql.GraphQLString
|
|
29
31
|
case 'varchar':
|
|
30
32
|
return graphql.GraphQLString
|
|
31
33
|
case 'text':
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/sql-graphql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Map SQL dbs to GraphQL",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"homepage": "https://github.com/platformatic/platformatic#readme",
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@platformatic/sql-events": "0.
|
|
18
|
-
"@platformatic/sql-mapper": "0.
|
|
17
|
+
"@platformatic/sql-events": "0.10.0",
|
|
18
|
+
"@platformatic/sql-mapper": "0.10.0",
|
|
19
19
|
"fastify": "^4.6.0",
|
|
20
20
|
"snazzy": "^9.0.0",
|
|
21
21
|
"standard": "^17.0.0",
|
package/test/datatypes.test.js
CHANGED
|
@@ -722,3 +722,82 @@ test('[SQLite] - UUID', { skip: !isSQLite }, async ({ pass, teardown, same, equa
|
|
|
722
722
|
}, 'savePage response')
|
|
723
723
|
}
|
|
724
724
|
})
|
|
725
|
+
|
|
726
|
+
test('BIGINT!', { skip: isSQLite, only: true }, async ({ pass, teardown, same, equal }) => {
|
|
727
|
+
const app = fastify()
|
|
728
|
+
app.register(sqlMapper, {
|
|
729
|
+
...connInfo,
|
|
730
|
+
async onDatabaseLoad (db, sql) {
|
|
731
|
+
pass('onDatabaseLoad called')
|
|
732
|
+
|
|
733
|
+
await clear(db, sql)
|
|
734
|
+
|
|
735
|
+
await db.query(sql`
|
|
736
|
+
CREATE TABLE simple_types (
|
|
737
|
+
id SERIAL PRIMARY KEY,
|
|
738
|
+
counter BIGINT
|
|
739
|
+
);`)
|
|
740
|
+
}
|
|
741
|
+
})
|
|
742
|
+
teardown(app.close.bind(app))
|
|
743
|
+
|
|
744
|
+
app.register(sqlGraphQL)
|
|
745
|
+
|
|
746
|
+
await app.ready()
|
|
747
|
+
|
|
748
|
+
const counter = BigInt(Number.MAX_SAFE_INTEGER) + 1000n
|
|
749
|
+
|
|
750
|
+
{
|
|
751
|
+
const res = await app.inject({
|
|
752
|
+
method: 'POST',
|
|
753
|
+
url: '/graphql',
|
|
754
|
+
body: {
|
|
755
|
+
query: `
|
|
756
|
+
mutation {
|
|
757
|
+
saveSimpleType(input: {
|
|
758
|
+
counter: "${counter}"
|
|
759
|
+
}) {
|
|
760
|
+
id
|
|
761
|
+
counter
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
`
|
|
765
|
+
}
|
|
766
|
+
})
|
|
767
|
+
equal(res.statusCode, 200, 'saveSimpleType status code')
|
|
768
|
+
same(res.json(), {
|
|
769
|
+
data: {
|
|
770
|
+
saveSimpleType: {
|
|
771
|
+
id: '1',
|
|
772
|
+
counter
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}, 'saveSimpleType response')
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
{
|
|
779
|
+
const res = await app.inject({
|
|
780
|
+
method: 'POST',
|
|
781
|
+
url: '/graphql',
|
|
782
|
+
body: {
|
|
783
|
+
query: `
|
|
784
|
+
query {
|
|
785
|
+
getSimpleTypeById(id: 1) {
|
|
786
|
+
id
|
|
787
|
+
counter
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
`
|
|
791
|
+
}
|
|
792
|
+
})
|
|
793
|
+
equal(res.statusCode, 200, 'getSimpleTypeById status code')
|
|
794
|
+
same(res.json(), {
|
|
795
|
+
data: {
|
|
796
|
+
getSimpleTypeById: {
|
|
797
|
+
id: 1,
|
|
798
|
+
counter
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}, 'getSimpleTypeById response')
|
|
802
|
+
}
|
|
803
|
+
})
|
|
@@ -0,0 +1,172 @@
|
|
|
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 { connInfo, isPg } = require('./helper')
|
|
8
|
+
|
|
9
|
+
async function runMigrations (db, sql) {
|
|
10
|
+
await db.query(sql`
|
|
11
|
+
create table company (
|
|
12
|
+
id SERIAL primary key,
|
|
13
|
+
name varchar(60)
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
create table social_medias (
|
|
17
|
+
id SERIAL primary key,
|
|
18
|
+
name varchar(60)
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
create table company_social_medias (
|
|
22
|
+
id SERIAL primary key,
|
|
23
|
+
username varchar not null,
|
|
24
|
+
social_medias_id integer not null,
|
|
25
|
+
company_id integer not null,
|
|
26
|
+
constraint "fk_company_id" foreign key ("company_id") references company,
|
|
27
|
+
constraint "fk_social_medias_id" foreign key ("social_medias_id") references social_medias
|
|
28
|
+
);
|
|
29
|
+
`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function clean (db, sql) {
|
|
33
|
+
await db.query(sql`
|
|
34
|
+
drop table if exists company_social_medias;
|
|
35
|
+
drop table if exists company;
|
|
36
|
+
drop table if exists social_medias;
|
|
37
|
+
`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test('do not crash', { skip: !isPg }, async ({ pass, teardown, same, equal }) => {
|
|
41
|
+
const app = fastify()
|
|
42
|
+
app.register(sqlMapper, {
|
|
43
|
+
...connInfo,
|
|
44
|
+
async onDatabaseLoad (db, sql) {
|
|
45
|
+
pass('onDatabaseLoad called')
|
|
46
|
+
await clean(db, sql)
|
|
47
|
+
|
|
48
|
+
await runMigrations(db, sql)
|
|
49
|
+
teardown(async () => {
|
|
50
|
+
await clean(db, sql)
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
await app.register(sqlGraphQL)
|
|
55
|
+
teardown(app.close.bind(app))
|
|
56
|
+
|
|
57
|
+
await app.ready()
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
const res = await app.inject({
|
|
61
|
+
method: 'POST',
|
|
62
|
+
url: '/graphql',
|
|
63
|
+
body: {
|
|
64
|
+
query: `
|
|
65
|
+
mutation {
|
|
66
|
+
saveCompany(input: { name: "Platformatic" }) {
|
|
67
|
+
id
|
|
68
|
+
name
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
`
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
equal(res.statusCode, 200, 'saveCompany status code')
|
|
75
|
+
same(res.json(), {
|
|
76
|
+
data: {
|
|
77
|
+
saveCompany: {
|
|
78
|
+
id: 1,
|
|
79
|
+
name: 'Platformatic'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, 'saveCompany response')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
{
|
|
86
|
+
const res = await app.inject({
|
|
87
|
+
method: 'POST',
|
|
88
|
+
url: '/graphql',
|
|
89
|
+
body: {
|
|
90
|
+
query: `
|
|
91
|
+
mutation {
|
|
92
|
+
saveSocialMedia(input: { name: "Twitter" }) {
|
|
93
|
+
id
|
|
94
|
+
name
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
equal(res.statusCode, 200, 'saveSocialMedia status code')
|
|
101
|
+
same(res.json(), {
|
|
102
|
+
data: {
|
|
103
|
+
saveSocialMedia: {
|
|
104
|
+
id: 1,
|
|
105
|
+
name: 'Twitter'
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, 'saveSocialMedia response')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
{
|
|
112
|
+
const res = await app.inject({
|
|
113
|
+
method: 'POST',
|
|
114
|
+
url: '/graphql',
|
|
115
|
+
body: {
|
|
116
|
+
query: `
|
|
117
|
+
mutation {
|
|
118
|
+
saveCompanySocialMedia(input: { companyId: 1, socialMediasId: 1, username: "platformatic" }) {
|
|
119
|
+
id
|
|
120
|
+
username
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
`
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
equal(res.statusCode, 200, 'saveCompanySocialMedia status code')
|
|
127
|
+
same(res.json(), {
|
|
128
|
+
data: {
|
|
129
|
+
saveCompanySocialMedia: {
|
|
130
|
+
id: 1,
|
|
131
|
+
username: 'platformatic'
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}, 'saveCompanySocialMedia response')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
{
|
|
138
|
+
const res = await app.inject({
|
|
139
|
+
method: 'POST',
|
|
140
|
+
url: '/graphql',
|
|
141
|
+
body: {
|
|
142
|
+
query: `
|
|
143
|
+
query {
|
|
144
|
+
company {
|
|
145
|
+
name
|
|
146
|
+
companySocialMedias {
|
|
147
|
+
username
|
|
148
|
+
socialMedias {
|
|
149
|
+
name
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
`
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
equal(res.statusCode, 200, 'complex status code')
|
|
158
|
+
same(res.json(), {
|
|
159
|
+
data: {
|
|
160
|
+
company: [{
|
|
161
|
+
name: 'Platformatic',
|
|
162
|
+
companySocialMedias: [{
|
|
163
|
+
username: 'platformatic',
|
|
164
|
+
socialMedias: {
|
|
165
|
+
name: 'Twitter'
|
|
166
|
+
}
|
|
167
|
+
}]
|
|
168
|
+
}]
|
|
169
|
+
}
|
|
170
|
+
}, 'complex response')
|
|
171
|
+
}
|
|
172
|
+
})
|
package/test/nested.test.js
CHANGED
|
@@ -860,3 +860,255 @@ test('nested update', async ({ pass, teardown, same, equal }) => {
|
|
|
860
860
|
}, 'savePage response')
|
|
861
861
|
}
|
|
862
862
|
})
|
|
863
|
+
|
|
864
|
+
test('nested resolver without `id` suffix', async ({ pass, teardown, same, equal }) => {
|
|
865
|
+
const app = fastify()
|
|
866
|
+
app.register(sqlMapper, {
|
|
867
|
+
...connInfo,
|
|
868
|
+
async onDatabaseLoad (db, sql) {
|
|
869
|
+
pass('onDatabaseLoad called')
|
|
870
|
+
|
|
871
|
+
await clear(db, sql)
|
|
872
|
+
|
|
873
|
+
if (isMysql) {
|
|
874
|
+
await db.query(sql`
|
|
875
|
+
CREATE TABLE categories (
|
|
876
|
+
id SERIAL PRIMARY KEY,
|
|
877
|
+
name VARCHAR(255)
|
|
878
|
+
);
|
|
879
|
+
CREATE TABLE pages (
|
|
880
|
+
id SERIAL PRIMARY KEY,
|
|
881
|
+
title VARCHAR(42),
|
|
882
|
+
category BIGINT UNSIGNED,
|
|
883
|
+
FOREIGN KEY (category) REFERENCES categories(id) ON DELETE CASCADE
|
|
884
|
+
);
|
|
885
|
+
`)
|
|
886
|
+
} else if (isSQLite) {
|
|
887
|
+
await db.query(sql`
|
|
888
|
+
CREATE TABLE categories (
|
|
889
|
+
id INTEGER PRIMARY KEY,
|
|
890
|
+
name VARCHAR(42)
|
|
891
|
+
);
|
|
892
|
+
`)
|
|
893
|
+
await db.query(sql`
|
|
894
|
+
CREATE TABLE pages (
|
|
895
|
+
id INTEGER PRIMARY KEY,
|
|
896
|
+
title VARCHAR(42),
|
|
897
|
+
category INTEGER REFERENCES categories(id)
|
|
898
|
+
);
|
|
899
|
+
`)
|
|
900
|
+
} else {
|
|
901
|
+
await db.query(sql`
|
|
902
|
+
CREATE TABLE categories (
|
|
903
|
+
id SERIAL PRIMARY KEY,
|
|
904
|
+
name VARCHAR(42)
|
|
905
|
+
);
|
|
906
|
+
CREATE TABLE pages (
|
|
907
|
+
id SERIAL PRIMARY KEY,
|
|
908
|
+
title VARCHAR(42),
|
|
909
|
+
category INTEGER REFERENCES categories(id)
|
|
910
|
+
);
|
|
911
|
+
`)
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
})
|
|
915
|
+
app.register(sqlGraphQL)
|
|
916
|
+
teardown(app.close.bind(app))
|
|
917
|
+
|
|
918
|
+
const categories = [{
|
|
919
|
+
name: 'Pets'
|
|
920
|
+
}, {
|
|
921
|
+
name: 'Food'
|
|
922
|
+
}]
|
|
923
|
+
|
|
924
|
+
await app.inject({
|
|
925
|
+
method: 'POST',
|
|
926
|
+
url: '/graphql',
|
|
927
|
+
body: {
|
|
928
|
+
query: `
|
|
929
|
+
mutation batch($inputs: [CategoryInput]!) {
|
|
930
|
+
insertCategories(inputs: $inputs) {
|
|
931
|
+
id
|
|
932
|
+
name
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
`,
|
|
936
|
+
variables: {
|
|
937
|
+
inputs: categories
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
})
|
|
941
|
+
|
|
942
|
+
{
|
|
943
|
+
const res = await app.inject({
|
|
944
|
+
method: 'POST',
|
|
945
|
+
url: '/graphql',
|
|
946
|
+
body: {
|
|
947
|
+
query: `
|
|
948
|
+
mutation {
|
|
949
|
+
savePage(input: { title: "Hello", category: 1 }) {
|
|
950
|
+
id
|
|
951
|
+
title
|
|
952
|
+
category {
|
|
953
|
+
id
|
|
954
|
+
name
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
`
|
|
959
|
+
}
|
|
960
|
+
})
|
|
961
|
+
equal(res.statusCode, 200, 'savePage status code')
|
|
962
|
+
same(res.json(), {
|
|
963
|
+
data: {
|
|
964
|
+
savePage: {
|
|
965
|
+
id: 1,
|
|
966
|
+
title: 'Hello',
|
|
967
|
+
category: {
|
|
968
|
+
id: 1,
|
|
969
|
+
name: 'Pets'
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}, 'savePage response')
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
{
|
|
977
|
+
const res = await app.inject({
|
|
978
|
+
method: 'POST',
|
|
979
|
+
url: '/graphql',
|
|
980
|
+
body: {
|
|
981
|
+
query: `
|
|
982
|
+
query {
|
|
983
|
+
getPageById(id: 1) {
|
|
984
|
+
id
|
|
985
|
+
title
|
|
986
|
+
category {
|
|
987
|
+
id
|
|
988
|
+
name
|
|
989
|
+
pages {
|
|
990
|
+
id
|
|
991
|
+
title
|
|
992
|
+
category {
|
|
993
|
+
id
|
|
994
|
+
name
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
`
|
|
1001
|
+
}
|
|
1002
|
+
})
|
|
1003
|
+
equal(res.statusCode, 200, 'pages status code')
|
|
1004
|
+
same(res.json(), {
|
|
1005
|
+
data: {
|
|
1006
|
+
getPageById: {
|
|
1007
|
+
id: 1,
|
|
1008
|
+
title: 'Hello',
|
|
1009
|
+
category: {
|
|
1010
|
+
id: 1,
|
|
1011
|
+
name: 'Pets',
|
|
1012
|
+
pages: [{
|
|
1013
|
+
id: 1,
|
|
1014
|
+
title: 'Hello',
|
|
1015
|
+
category: {
|
|
1016
|
+
id: 1,
|
|
1017
|
+
name: 'Pets'
|
|
1018
|
+
}
|
|
1019
|
+
}]
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}, 'pages response')
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
// Without ids
|
|
1027
|
+
{
|
|
1028
|
+
const res = await app.inject({
|
|
1029
|
+
method: 'POST',
|
|
1030
|
+
url: '/graphql',
|
|
1031
|
+
body: {
|
|
1032
|
+
query: `
|
|
1033
|
+
query {
|
|
1034
|
+
getPageById(id: 1) {
|
|
1035
|
+
title
|
|
1036
|
+
category {
|
|
1037
|
+
name
|
|
1038
|
+
pages {
|
|
1039
|
+
title
|
|
1040
|
+
category {
|
|
1041
|
+
name
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
`
|
|
1048
|
+
}
|
|
1049
|
+
})
|
|
1050
|
+
equal(res.statusCode, 200, 'pages status code')
|
|
1051
|
+
same(res.json(), {
|
|
1052
|
+
data: {
|
|
1053
|
+
getPageById: {
|
|
1054
|
+
title: 'Hello',
|
|
1055
|
+
category: {
|
|
1056
|
+
name: 'Pets',
|
|
1057
|
+
pages: [{
|
|
1058
|
+
title: 'Hello',
|
|
1059
|
+
category: {
|
|
1060
|
+
name: 'Pets'
|
|
1061
|
+
}
|
|
1062
|
+
}]
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}, 'pages response')
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
{
|
|
1070
|
+
const res = await app.inject({
|
|
1071
|
+
method: 'POST',
|
|
1072
|
+
url: '/graphql',
|
|
1073
|
+
body: {
|
|
1074
|
+
query: `
|
|
1075
|
+
query {
|
|
1076
|
+
categories {
|
|
1077
|
+
id
|
|
1078
|
+
name
|
|
1079
|
+
pages {
|
|
1080
|
+
id
|
|
1081
|
+
title
|
|
1082
|
+
category {
|
|
1083
|
+
id
|
|
1084
|
+
name
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
`
|
|
1090
|
+
}
|
|
1091
|
+
})
|
|
1092
|
+
equal(res.statusCode, 200, 'categories.posts status code')
|
|
1093
|
+
same(res.json(), {
|
|
1094
|
+
data: {
|
|
1095
|
+
categories: [{
|
|
1096
|
+
id: 1,
|
|
1097
|
+
name: 'Pets',
|
|
1098
|
+
pages: [{
|
|
1099
|
+
id: 1,
|
|
1100
|
+
title: 'Hello',
|
|
1101
|
+
category: {
|
|
1102
|
+
id: 1,
|
|
1103
|
+
name: 'Pets'
|
|
1104
|
+
}
|
|
1105
|
+
}]
|
|
1106
|
+
}, {
|
|
1107
|
+
id: 2,
|
|
1108
|
+
name: 'Food',
|
|
1109
|
+
pages: []
|
|
1110
|
+
}]
|
|
1111
|
+
}
|
|
1112
|
+
}, 'categories.posts response')
|
|
1113
|
+
}
|
|
1114
|
+
})
|