@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,248 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const graphql = require('graphql')
|
|
4
|
+
const camelcase = require('camelcase')
|
|
5
|
+
const {
|
|
6
|
+
sqlTypeToGraphQL,
|
|
7
|
+
fromSelectionSet
|
|
8
|
+
} = require('./utils')
|
|
9
|
+
|
|
10
|
+
const ascDesc = new graphql.GraphQLEnumType({
|
|
11
|
+
name: 'OrderByDirection',
|
|
12
|
+
values: {
|
|
13
|
+
ASC: { value: 'ASC' },
|
|
14
|
+
DESC: { value: 'DESC' }
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
function constructGraph (app, entity, opts) {
|
|
19
|
+
const primaryKey = entity.primaryKey
|
|
20
|
+
|
|
21
|
+
const entityName = entity.name
|
|
22
|
+
const singular = entity.singularName
|
|
23
|
+
const plural = entity.pluralName
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
queryTopFields,
|
|
27
|
+
mutationTopFields,
|
|
28
|
+
resolvers,
|
|
29
|
+
federationReplacements,
|
|
30
|
+
federationMetadata,
|
|
31
|
+
loaders
|
|
32
|
+
} = opts
|
|
33
|
+
|
|
34
|
+
const fields = {}
|
|
35
|
+
|
|
36
|
+
for (const key of Object.keys(entity.fields)) {
|
|
37
|
+
const field = entity.fields[key]
|
|
38
|
+
const meta = { field }
|
|
39
|
+
meta.type = sqlTypeToGraphQL(field.sqlType)
|
|
40
|
+
if (field.primaryKey) {
|
|
41
|
+
meta.primaryKeyType = field.type
|
|
42
|
+
meta.type = graphql.GraphQLID
|
|
43
|
+
} else if (field.foreignKey) {
|
|
44
|
+
meta.type = graphql.GraphQLID
|
|
45
|
+
}
|
|
46
|
+
fields[field.camelcase] = meta
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const type = new graphql.GraphQLObjectType({
|
|
50
|
+
name: entityName,
|
|
51
|
+
fields
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
resolvers.Query = resolvers.Query || {}
|
|
55
|
+
resolvers.Mutation = resolvers.Mutation || {}
|
|
56
|
+
loaders.Query = loaders.Query || {}
|
|
57
|
+
|
|
58
|
+
const getBy = camelcase(['get', singular, 'by', primaryKey])
|
|
59
|
+
|
|
60
|
+
const whereArgType = new graphql.GraphQLInputObjectType({
|
|
61
|
+
name: `${entityName}WhereArguments`,
|
|
62
|
+
fields: Object.keys(fields).reduce((acc, field) => {
|
|
63
|
+
acc[field] = {
|
|
64
|
+
type: new graphql.GraphQLInputObjectType({
|
|
65
|
+
name: `${entityName}WhereArguments${field}`,
|
|
66
|
+
fields: {
|
|
67
|
+
eq: { type: fields[field].type },
|
|
68
|
+
neq: { type: fields[field].type },
|
|
69
|
+
gt: { type: fields[field].type },
|
|
70
|
+
gte: { type: fields[field].type },
|
|
71
|
+
lt: { type: fields[field].type },
|
|
72
|
+
lte: { type: fields[field].type },
|
|
73
|
+
in: { type: new graphql.GraphQLList(fields[field].type) },
|
|
74
|
+
nin: { type: new graphql.GraphQLList(fields[field].type) }
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
return acc
|
|
79
|
+
}, {})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
queryTopFields[getBy] = {
|
|
83
|
+
type,
|
|
84
|
+
args: {
|
|
85
|
+
[primaryKey]: { type: new graphql.GraphQLNonNull(fields[primaryKey].type) }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
loaders.Query[getBy] = {
|
|
89
|
+
loader (queries, ctx) {
|
|
90
|
+
const keys = []
|
|
91
|
+
for (const query of queries) {
|
|
92
|
+
keys.push(query.params[primaryKey])
|
|
93
|
+
}
|
|
94
|
+
return loadMany(keys, queries, ctx)
|
|
95
|
+
},
|
|
96
|
+
opts: {
|
|
97
|
+
cache: false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const orderByFields = new graphql.GraphQLEnumType({
|
|
102
|
+
name: `${entityName}OrderByField`,
|
|
103
|
+
values: Object.keys(fields).reduce((acc, field) => {
|
|
104
|
+
acc[field] = {
|
|
105
|
+
value: field
|
|
106
|
+
}
|
|
107
|
+
return acc
|
|
108
|
+
}, {})
|
|
109
|
+
})
|
|
110
|
+
queryTopFields[plural] = {
|
|
111
|
+
type: new graphql.GraphQLList(type),
|
|
112
|
+
args: {
|
|
113
|
+
limit: { type: graphql.GraphQLInt },
|
|
114
|
+
offset: { type: graphql.GraphQLInt },
|
|
115
|
+
orderBy: {
|
|
116
|
+
type: new graphql.GraphQLList(new graphql.GraphQLInputObjectType({
|
|
117
|
+
name: `${entityName}OrderByArguments`,
|
|
118
|
+
fields: {
|
|
119
|
+
field: { type: orderByFields },
|
|
120
|
+
direction: { type: new graphql.GraphQLNonNull(ascDesc) }
|
|
121
|
+
}
|
|
122
|
+
}))
|
|
123
|
+
},
|
|
124
|
+
where: { type: whereArgType }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
resolvers.Query[plural] = (_, query, ctx, info) => {
|
|
129
|
+
const requestedFields = info.fieldNodes[0].selectionSet.selections.map((s) => s.name.value)
|
|
130
|
+
requestedFields.push(primaryKey)
|
|
131
|
+
return entity.find({ ...query, fields: requestedFields, ctx })
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const inputType = new graphql.GraphQLInputObjectType({
|
|
135
|
+
name: `${entityName}Input`,
|
|
136
|
+
fields: Object.keys(fields).reduce((acc, field) => {
|
|
137
|
+
const meta = fields[field]
|
|
138
|
+
const actualField = meta.field
|
|
139
|
+
if (!actualField.autoTimestamp) {
|
|
140
|
+
acc[field] = meta
|
|
141
|
+
}
|
|
142
|
+
return acc
|
|
143
|
+
}, {})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const save = camelcase(['save', singular])
|
|
147
|
+
|
|
148
|
+
mutationTopFields[save] = {
|
|
149
|
+
type,
|
|
150
|
+
args: {
|
|
151
|
+
input: { type: new graphql.GraphQLNonNull(inputType) }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
resolvers.Mutation[save] = async (_, { input }, ctx, info) => {
|
|
156
|
+
const fields = fromSelectionSet(info.fieldNodes[0].selectionSet)
|
|
157
|
+
return entity.save({ input, ctx, fields: [...fields] })
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const insert = camelcase(['insert', plural])
|
|
161
|
+
|
|
162
|
+
mutationTopFields[insert] = {
|
|
163
|
+
type: new graphql.GraphQLList(type),
|
|
164
|
+
args: {
|
|
165
|
+
inputs: { type: new graphql.GraphQLNonNull(new graphql.GraphQLList(inputType)) }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
resolvers.Mutation[insert] = (_, { inputs }, ctx, info) => {
|
|
170
|
+
const fields = fromSelectionSet(info.fieldNodes[0].selectionSet)
|
|
171
|
+
return entity.insert({ inputs, ctx, fields: [...fields] })
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const deleteKey = camelcase(['delete', plural])
|
|
175
|
+
mutationTopFields[deleteKey] = {
|
|
176
|
+
type: new graphql.GraphQLList(type),
|
|
177
|
+
args: {
|
|
178
|
+
where: { type: whereArgType }
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
resolvers.Mutation[deleteKey] = (_, args, ctx, info) => {
|
|
183
|
+
const fields = info.fieldNodes[0].selectionSet.selections.map((s) => s.name.value)
|
|
184
|
+
return entity.delete({ ...args, fields, ctx })
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
federationReplacements.push({
|
|
188
|
+
find: new RegExp(`type ${entityName}`),
|
|
189
|
+
replace: `type ${entityName} @key(fields: "${primaryKey}")`
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
if (federationMetadata) {
|
|
193
|
+
loaders[entityName] = loaders[entityName] || {}
|
|
194
|
+
loaders[entityName].__resolveReference = {
|
|
195
|
+
loader (queries, ctx) {
|
|
196
|
+
const keys = queries.map(({ obj }) => obj[primaryKey])
|
|
197
|
+
return loadMany(keys, queries, ctx)
|
|
198
|
+
},
|
|
199
|
+
opts: {
|
|
200
|
+
cache: false
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
type,
|
|
207
|
+
entity,
|
|
208
|
+
loadMany,
|
|
209
|
+
fields
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function loadMany (keys, queries, ctx) {
|
|
213
|
+
const fields = getFields(queries)
|
|
214
|
+
const res = await entity.find({
|
|
215
|
+
where: {
|
|
216
|
+
[primaryKey]: {
|
|
217
|
+
in: keys
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
fields,
|
|
221
|
+
ctx
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
const map = {}
|
|
225
|
+
|
|
226
|
+
for (const row of res) {
|
|
227
|
+
map[row[primaryKey]] = row
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const output = []
|
|
231
|
+
for (const key of keys) {
|
|
232
|
+
output.push(map[key])
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return output
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function getFields (queries) {
|
|
239
|
+
const fields = new Set()
|
|
240
|
+
fields.add(primaryKey)
|
|
241
|
+
for (const query of queries) {
|
|
242
|
+
fromSelectionSet(query.info.fieldNodes[0].selectionSet, fields)
|
|
243
|
+
}
|
|
244
|
+
return [...fields]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
module.exports = constructGraph
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const camelcase = require('camelcase')
|
|
4
|
+
const {
|
|
5
|
+
fromSelectionSet
|
|
6
|
+
} = require('./utils')
|
|
7
|
+
const assert = require('assert')
|
|
8
|
+
|
|
9
|
+
module.exports = function establishRelations (app, relations, resolvers, loaders, queryTopFields, relationships, metaMap) {
|
|
10
|
+
const tablesTypeMap = {}
|
|
11
|
+
const entities = app.platformatic.entities
|
|
12
|
+
for (const key of Object.keys(entities)) {
|
|
13
|
+
const entity = entities[key]
|
|
14
|
+
tablesTypeMap[entity.table] = metaMap.get(entity)
|
|
15
|
+
}
|
|
16
|
+
for (const relation of relations) {
|
|
17
|
+
assert(relation.table_name, 'table_name is required')
|
|
18
|
+
assert(relation.foreign_table_name, 'foreign_table_name is required')
|
|
19
|
+
|
|
20
|
+
const current = tablesTypeMap[relation.table_name]
|
|
21
|
+
const foreign = tablesTypeMap[relation.foreign_table_name]
|
|
22
|
+
assert(foreign !== undefined, `No foreign table named "${relation.foreign_table_name}" was found`)
|
|
23
|
+
|
|
24
|
+
// current to foreign
|
|
25
|
+
{
|
|
26
|
+
const lowered = lowerCaseFirst(foreign.type)
|
|
27
|
+
if (!relationships[current.type] || relationships[current.type][lowered] !== false) {
|
|
28
|
+
current.fields[lowered] = { type: foreign.type }
|
|
29
|
+
const originalField = camelcase(relation.column_name)
|
|
30
|
+
delete current.fields[originalField]
|
|
31
|
+
loaders[current.type] = resolvers[current.type] || {}
|
|
32
|
+
loaders[current.type][lowered] = {
|
|
33
|
+
loader (queries, ctx) {
|
|
34
|
+
const keys = queries.map(({ obj }) => {
|
|
35
|
+
return obj[originalField]
|
|
36
|
+
})
|
|
37
|
+
return foreign.loadMany(keys, queries, ctx)
|
|
38
|
+
},
|
|
39
|
+
opts: {
|
|
40
|
+
cache: false
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// foreign to current
|
|
47
|
+
{
|
|
48
|
+
const lowered = lowerCaseFirst(camelcase(current.entity.table))
|
|
49
|
+
if (!relationships[foreign.type] || relationships[foreign.type][lowered] !== false) {
|
|
50
|
+
foreign.fields[lowered] = queryTopFields[lowered]
|
|
51
|
+
resolvers[foreign.type] = resolvers[foreign.type] || {}
|
|
52
|
+
resolvers[foreign.type][lowered] = async function (obj, args, ctx, info) {
|
|
53
|
+
const fields = fromSelectionSet(info.fieldNodes[0].selectionSet, new Set())
|
|
54
|
+
const toSearch = { ...args, fields: [...fields], ctx }
|
|
55
|
+
toSearch.where = toSearch.where || {}
|
|
56
|
+
toSearch.where[camelcase(relation.column_name)] = { eq: obj.id }
|
|
57
|
+
return current.entity.find(toSearch)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function lowerCaseFirst (str) {
|
|
65
|
+
str = str.toString()
|
|
66
|
+
return str.charAt(0).toLowerCase() + str.slice(1)
|
|
67
|
+
}
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const graphql = require('graphql')
|
|
4
|
+
const scalars = require('graphql-scalars')
|
|
5
|
+
|
|
6
|
+
// The sqlTypeToGraphQL is shared between
|
|
7
|
+
// all database adapters.
|
|
8
|
+
function sqlTypeToGraphQL (sqlType) {
|
|
9
|
+
// TODO support more types
|
|
10
|
+
/* istanbul ignore next */
|
|
11
|
+
switch (sqlType) {
|
|
12
|
+
case 'int':
|
|
13
|
+
return graphql.GraphQLInt
|
|
14
|
+
case 'integer':
|
|
15
|
+
return graphql.GraphQLInt
|
|
16
|
+
case 'tinyint':
|
|
17
|
+
return graphql.GraphQLBoolean
|
|
18
|
+
case 'smallint':
|
|
19
|
+
return graphql.GraphQLInt
|
|
20
|
+
case 'decimal':
|
|
21
|
+
return graphql.GraphQLInt
|
|
22
|
+
case 'bigint':
|
|
23
|
+
return graphql.GraphQLInt
|
|
24
|
+
case 'int2':
|
|
25
|
+
return graphql.GraphQLInt
|
|
26
|
+
case 'int4':
|
|
27
|
+
return graphql.GraphQLInt
|
|
28
|
+
case 'varchar':
|
|
29
|
+
return graphql.GraphQLString
|
|
30
|
+
case 'text':
|
|
31
|
+
return graphql.GraphQLString
|
|
32
|
+
case 'bool':
|
|
33
|
+
return graphql.GraphQLBoolean
|
|
34
|
+
case 'real':
|
|
35
|
+
return graphql.GraphQLFloat
|
|
36
|
+
case 'float8':
|
|
37
|
+
return graphql.GraphQLFloat
|
|
38
|
+
case 'double':
|
|
39
|
+
return graphql.GraphQLFloat
|
|
40
|
+
case 'double precision':
|
|
41
|
+
return graphql.GraphQLFloat
|
|
42
|
+
case 'numeric':
|
|
43
|
+
return graphql.GraphQLFloat
|
|
44
|
+
case 'float4':
|
|
45
|
+
return graphql.GraphQLFloat
|
|
46
|
+
case 'date':
|
|
47
|
+
return scalars.GraphQLDate
|
|
48
|
+
case 'time':
|
|
49
|
+
return graphql.GraphQLString
|
|
50
|
+
case 'timestamp':
|
|
51
|
+
return scalars.GraphQLDateTime
|
|
52
|
+
case 'uuid':
|
|
53
|
+
return graphql.GraphQLString
|
|
54
|
+
default:
|
|
55
|
+
return graphql.GraphQLString
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function fromSelectionSet (selectionSet, fields = new Set()) {
|
|
60
|
+
/* istanbul ignore next */
|
|
61
|
+
for (const s of selectionSet.selections) {
|
|
62
|
+
if (s.kind === 'Field') {
|
|
63
|
+
fields.add(s.name.value)
|
|
64
|
+
} else if (s.kind === 'InlineFragment') {
|
|
65
|
+
fromSelectionSet(s.selectionSet, fields)
|
|
66
|
+
} else {
|
|
67
|
+
throw new Error('Unsupported kind: ' + s.kind)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return fields
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
sqlTypeToGraphQL,
|
|
75
|
+
fromSelectionSet,
|
|
76
|
+
typeSym: Symbol('graphlType')
|
|
77
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@platformatic/sql-graphql",
|
|
3
|
+
"version": "0.0.23",
|
|
4
|
+
"description": "Map SQL dbs to GraphQL",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/plaformatic/platformatic.git"
|
|
9
|
+
},
|
|
10
|
+
"author": "Matteo Collina <hello@matteocollina.com>",
|
|
11
|
+
"license": "Apache-2.0",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/plaformatic/platformatic/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/plaformatic/platformatic#readme",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@platformatic/sql-mapper": "0.0.23",
|
|
18
|
+
"fastify": "^4.6.0",
|
|
19
|
+
"snazzy": "^9.0.0",
|
|
20
|
+
"standard": "^17.0.0",
|
|
21
|
+
"tap": "^16.0.0",
|
|
22
|
+
"tsd": "^0.24.0"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"camelcase": "^6.0.0",
|
|
26
|
+
"fastify-plugin": "^4.1.0",
|
|
27
|
+
"graphql": "^16.6.0",
|
|
28
|
+
"graphql-scalars": "^1.13.1",
|
|
29
|
+
"inflected": "^2.1.0",
|
|
30
|
+
"mercurius": "^11.0.0"
|
|
31
|
+
},
|
|
32
|
+
"tsd": {
|
|
33
|
+
"directory": "test/types"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "standard | snazzy && npm run test:typescript && npm run test:postgresql && npm run test:mariadb && npm run test:mysql && npm run test:mysql8 && npm run test:sqlite",
|
|
37
|
+
"test:postgresql": "DB=postgresql tap test/*.test.js",
|
|
38
|
+
"test:mariadb": "DB=mariadb tap test/*.test.js",
|
|
39
|
+
"test:mysql": "DB=mysql tap test/*.test.js",
|
|
40
|
+
"test:mysql8": "DB=mysql8 tap test/*.test.js",
|
|
41
|
+
"test:sqlite": "DB=sqlite tap test/*.test.js",
|
|
42
|
+
"test:typescript": "tsd"
|
|
43
|
+
}
|
|
44
|
+
}
|