wabe 0.6.9 → 0.6.10

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 (158) hide show
  1. package/README.md +138 -32
  2. package/bucket/b.txt +1 -0
  3. package/dev/index.ts +215 -0
  4. package/dist/authentication/Session.d.ts +4 -1
  5. package/dist/authentication/interface.d.ts +16 -0
  6. package/dist/email/interface.d.ts +1 -1
  7. package/dist/graphql/resolvers.d.ts +4 -2
  8. package/dist/hooks/index.d.ts +1 -0
  9. package/dist/index.d.ts +0 -1
  10. package/dist/index.js +8713 -8867
  11. package/dist/server/index.d.ts +4 -2
  12. package/dist/utils/crypto.d.ts +7 -0
  13. package/dist/utils/helper.d.ts +4 -1
  14. package/generated/schema.graphql +16 -14
  15. package/generated/wabe.ts +4 -4
  16. package/package.json +15 -15
  17. package/src/authentication/OTP.test.ts +69 -0
  18. package/src/authentication/OTP.ts +66 -0
  19. package/src/authentication/Session.test.ts +665 -0
  20. package/src/authentication/Session.ts +529 -0
  21. package/src/authentication/defaultAuthentication.ts +214 -0
  22. package/src/authentication/index.ts +3 -0
  23. package/src/authentication/interface.ts +157 -0
  24. package/src/authentication/oauth/GitHub.test.ts +105 -0
  25. package/src/authentication/oauth/GitHub.ts +133 -0
  26. package/src/authentication/oauth/Google.test.ts +105 -0
  27. package/src/authentication/oauth/Google.ts +110 -0
  28. package/src/authentication/oauth/Oauth2Client.test.ts +225 -0
  29. package/src/authentication/oauth/Oauth2Client.ts +140 -0
  30. package/src/authentication/oauth/index.ts +2 -0
  31. package/src/authentication/oauth/utils.test.ts +35 -0
  32. package/src/authentication/oauth/utils.ts +28 -0
  33. package/src/authentication/providers/EmailOTP.test.ts +138 -0
  34. package/src/authentication/providers/EmailOTP.ts +93 -0
  35. package/src/authentication/providers/EmailPassword.test.ts +187 -0
  36. package/src/authentication/providers/EmailPassword.ts +130 -0
  37. package/src/authentication/providers/EmailPasswordSRP.test.ts +206 -0
  38. package/src/authentication/providers/EmailPasswordSRP.ts +184 -0
  39. package/src/authentication/providers/GitHub.ts +30 -0
  40. package/src/authentication/providers/Google.ts +30 -0
  41. package/src/authentication/providers/OAuth.test.ts +185 -0
  42. package/src/authentication/providers/OAuth.ts +112 -0
  43. package/src/authentication/providers/PhonePassword.test.ts +187 -0
  44. package/src/authentication/providers/PhonePassword.ts +129 -0
  45. package/src/authentication/providers/QRCodeOTP.test.ts +79 -0
  46. package/src/authentication/providers/QRCodeOTP.ts +65 -0
  47. package/src/authentication/providers/index.ts +6 -0
  48. package/src/authentication/resolvers/refreshResolver.test.ts +37 -0
  49. package/src/authentication/resolvers/refreshResolver.ts +20 -0
  50. package/src/authentication/resolvers/signInWithResolver.inte.test.ts +59 -0
  51. package/src/authentication/resolvers/signInWithResolver.test.ts +307 -0
  52. package/src/authentication/resolvers/signInWithResolver.ts +102 -0
  53. package/src/authentication/resolvers/signOutResolver.test.ts +41 -0
  54. package/src/authentication/resolvers/signOutResolver.ts +22 -0
  55. package/src/authentication/resolvers/signUpWithResolver.test.ts +186 -0
  56. package/src/authentication/resolvers/signUpWithResolver.ts +69 -0
  57. package/src/authentication/resolvers/verifyChallenge.test.ts +136 -0
  58. package/src/authentication/resolvers/verifyChallenge.ts +69 -0
  59. package/src/authentication/roles.test.ts +59 -0
  60. package/src/authentication/roles.ts +40 -0
  61. package/src/authentication/utils.test.ts +99 -0
  62. package/src/authentication/utils.ts +43 -0
  63. package/src/cache/InMemoryCache.test.ts +62 -0
  64. package/src/cache/InMemoryCache.ts +45 -0
  65. package/src/cron/index.test.ts +17 -0
  66. package/src/cron/index.ts +46 -0
  67. package/src/database/DatabaseController.test.ts +625 -0
  68. package/src/database/DatabaseController.ts +983 -0
  69. package/src/database/index.test.ts +1230 -0
  70. package/src/database/index.ts +9 -0
  71. package/src/database/interface.ts +312 -0
  72. package/src/email/DevAdapter.ts +8 -0
  73. package/src/email/EmailController.test.ts +29 -0
  74. package/src/email/EmailController.ts +13 -0
  75. package/src/email/index.ts +2 -0
  76. package/src/email/interface.ts +36 -0
  77. package/src/email/templates/sendOtpCode.ts +120 -0
  78. package/src/file/FileController.ts +28 -0
  79. package/src/file/FileDevAdapter.ts +54 -0
  80. package/src/file/hookDeleteFile.ts +27 -0
  81. package/src/file/hookReadFile.ts +70 -0
  82. package/src/file/hookUploadFile.ts +53 -0
  83. package/src/file/index.test.ts +979 -0
  84. package/src/file/index.ts +2 -0
  85. package/src/file/interface.ts +42 -0
  86. package/src/graphql/GraphQLSchema.test.ts +4399 -0
  87. package/src/graphql/GraphQLSchema.ts +928 -0
  88. package/src/graphql/index.ts +2 -0
  89. package/src/graphql/parseGraphqlSchema.ts +94 -0
  90. package/src/graphql/parser.test.ts +217 -0
  91. package/src/graphql/parser.ts +566 -0
  92. package/src/graphql/pointerAndRelationFunction.ts +200 -0
  93. package/src/graphql/resolvers.ts +467 -0
  94. package/src/graphql/tests/aggregation.test.ts +1123 -0
  95. package/src/graphql/tests/e2e.test.ts +596 -0
  96. package/src/graphql/tests/scalars.test.ts +250 -0
  97. package/src/graphql/types.ts +219 -0
  98. package/src/hooks/HookObject.test.ts +122 -0
  99. package/src/hooks/HookObject.ts +168 -0
  100. package/src/hooks/authentication.ts +76 -0
  101. package/src/hooks/createUser.test.ts +77 -0
  102. package/src/hooks/createUser.ts +10 -0
  103. package/src/hooks/defaultFields.test.ts +187 -0
  104. package/src/hooks/defaultFields.ts +40 -0
  105. package/src/hooks/deleteSession.test.ts +181 -0
  106. package/src/hooks/deleteSession.ts +20 -0
  107. package/src/hooks/hashFieldHook.test.ts +163 -0
  108. package/src/hooks/hashFieldHook.ts +97 -0
  109. package/src/hooks/index.test.ts +207 -0
  110. package/src/hooks/index.ts +430 -0
  111. package/src/hooks/permissions.test.ts +424 -0
  112. package/src/hooks/permissions.ts +113 -0
  113. package/src/hooks/protected.test.ts +551 -0
  114. package/src/hooks/protected.ts +72 -0
  115. package/src/hooks/searchableFields.test.ts +166 -0
  116. package/src/hooks/searchableFields.ts +98 -0
  117. package/src/hooks/session.test.ts +138 -0
  118. package/src/hooks/session.ts +78 -0
  119. package/src/hooks/setEmail.test.ts +216 -0
  120. package/src/hooks/setEmail.ts +35 -0
  121. package/src/hooks/setupAcl.test.ts +589 -0
  122. package/src/hooks/setupAcl.ts +29 -0
  123. package/src/index.ts +9 -0
  124. package/src/schema/Schema.test.ts +484 -0
  125. package/src/schema/Schema.ts +795 -0
  126. package/src/schema/defaultResolvers.ts +94 -0
  127. package/src/schema/index.ts +1 -0
  128. package/src/schema/resolvers/meResolver.test.ts +62 -0
  129. package/src/schema/resolvers/meResolver.ts +14 -0
  130. package/src/schema/resolvers/newFile.ts +0 -0
  131. package/src/schema/resolvers/resetPassword.test.ts +345 -0
  132. package/src/schema/resolvers/resetPassword.ts +64 -0
  133. package/src/schema/resolvers/sendEmail.test.ts +118 -0
  134. package/src/schema/resolvers/sendEmail.ts +21 -0
  135. package/src/schema/resolvers/sendOtpCode.test.ts +153 -0
  136. package/src/schema/resolvers/sendOtpCode.ts +52 -0
  137. package/src/security.test.ts +3461 -0
  138. package/src/server/defaultSessionHandler.test.ts +66 -0
  139. package/src/server/defaultSessionHandler.ts +115 -0
  140. package/src/server/generateCodegen.ts +476 -0
  141. package/src/server/index.test.ts +552 -0
  142. package/src/server/index.ts +354 -0
  143. package/src/server/interface.ts +11 -0
  144. package/src/server/routes/authHandler.ts +187 -0
  145. package/src/server/routes/index.ts +40 -0
  146. package/src/utils/crypto.test.ts +41 -0
  147. package/src/utils/crypto.ts +121 -0
  148. package/src/utils/export.ts +13 -0
  149. package/src/utils/helper.ts +195 -0
  150. package/src/utils/index.test.ts +11 -0
  151. package/src/utils/index.ts +201 -0
  152. package/src/utils/preload.ts +8 -0
  153. package/src/utils/testHelper.ts +117 -0
  154. package/tsconfig.json +32 -0
  155. package/bunfig.toml +0 -4
  156. package/dist/ai/index.d.ts +0 -1
  157. package/dist/ai/interface.d.ts +0 -9
  158. /package/dist/server/{defaultHandlers.d.ts → defaultSessionHandler.d.ts} +0 -0
@@ -0,0 +1,928 @@
1
+ import {
2
+ GraphQLEnumType,
3
+ type GraphQLFieldConfig,
4
+ GraphQLID,
5
+ GraphQLInputObjectType,
6
+ GraphQLInt,
7
+ GraphQLList,
8
+ GraphQLNonNull,
9
+ GraphQLObjectType,
10
+ type GraphQLOutputType,
11
+ GraphQLScalarType,
12
+ GraphQLBoolean,
13
+ GraphQLString,
14
+ } from 'graphql'
15
+ import { pluralize } from 'wabe-pluralize'
16
+ import type { WabeTypes } from '..'
17
+ import type {
18
+ ClassInterface,
19
+ MutationResolver,
20
+ QueryResolver,
21
+ Schema,
22
+ SchemaFields,
23
+ } from '../schema'
24
+ import { firstLetterInLowerCase } from '../utils'
25
+ import type { DevWabeTypes } from '../utils/helper'
26
+ import { GraphqlParser, type GraphqlParserFactory } from './parser'
27
+ import {
28
+ mutationToCreateMultipleObjects,
29
+ mutationToCreateObject,
30
+ mutationToDeleteMultipleObjects,
31
+ mutationToDeleteObject,
32
+ mutationToUpdateMultipleObjects,
33
+ mutationToUpdateObject,
34
+ queryForMultipleObject,
35
+ queryForOneObject,
36
+ } from './resolvers'
37
+ import {
38
+ DateScalarType,
39
+ FileScalarType,
40
+ IdWhereInput,
41
+ SearchWhereInput,
42
+ } from './types'
43
+
44
+ type AllPossibleObject =
45
+ | 'object'
46
+ | 'inputObject'
47
+ | 'whereInputObject'
48
+ | 'connectionObject'
49
+ | 'pointerInputObject'
50
+ | 'relationInputObject'
51
+ | 'updateInputObject'
52
+ | 'createInputObject'
53
+ | 'orderEnumType'
54
+
55
+ export type AllObjects = Record<string, Partial<Record<AllPossibleObject, any>>>
56
+
57
+ export class GraphQLSchema {
58
+ private schemas: Schema<DevWabeTypes>
59
+
60
+ private allObjects: AllObjects
61
+
62
+ constructor(schemas: Schema<any>) {
63
+ this.schemas = schemas
64
+ this.allObjects = {}
65
+ }
66
+
67
+ createSchema() {
68
+ if (!this.schemas) throw new Error('Schema not found')
69
+
70
+ const scalars = this.createScalars()
71
+ const enums = this.createEnums()
72
+
73
+ const classes = this.schemas.schema.classes || []
74
+
75
+ const graphqlParser = GraphqlParser({ scalars, enums })
76
+
77
+ classes.map((wabeClass) =>
78
+ this.createCompleteObject(graphqlParser, wabeClass),
79
+ )
80
+
81
+ const queriesMutationAndObjects = classes.reduce(
82
+ (acc, current) => {
83
+ const className = current.name.replace(' ', '')
84
+
85
+ const currentObject = this.allObjects[className]
86
+
87
+ if (!currentObject) throw new Error('Object not found')
88
+
89
+ const {
90
+ object,
91
+ inputObject,
92
+ pointerInputObject,
93
+ relationInputObject,
94
+ createInputObject,
95
+ updateInputObject,
96
+ whereInputObject,
97
+ connectionObject,
98
+ orderEnumType,
99
+ } = currentObject
100
+
101
+ // Queries
102
+ const defaultQueries = this.createDefaultQueries({
103
+ className,
104
+ whereInputType: whereInputObject,
105
+ object,
106
+ connectionObject,
107
+ orderEnumType,
108
+ })
109
+
110
+ const defaultMutations = this.createDefaultMutations({
111
+ className,
112
+ whereInputType: whereInputObject,
113
+ object,
114
+ connectionObject,
115
+ defaultUpdateInputType: updateInputObject,
116
+ defaultCreateInputType: createInputObject,
117
+ orderEnumType,
118
+ })
119
+
120
+ const defaultQueriesKeys = Object.keys(defaultQueries)
121
+ const defaultMutationsKeys = Object.keys(defaultMutations)
122
+
123
+ // Loop to avoid O(n)² complexity of spread on accumulator
124
+ for (const key in defaultQueriesKeys) {
125
+ // @ts-expect-error
126
+ acc.queries[defaultQueriesKeys[key]] =
127
+ // @ts-expect-error
128
+ defaultQueries[defaultQueriesKeys[key]]
129
+ }
130
+
131
+ for (const key in defaultMutationsKeys) {
132
+ // @ts-expect-error
133
+ acc.mutations[defaultMutationsKeys[key]] =
134
+ // @ts-expect-error
135
+ defaultMutations[defaultMutationsKeys[key]]
136
+ }
137
+
138
+ acc.objects.push(object)
139
+ acc.objects.push(inputObject)
140
+ acc.objects.push(pointerInputObject)
141
+ acc.objects.push(relationInputObject)
142
+
143
+ return acc
144
+ },
145
+ {
146
+ queries: {},
147
+ mutations: {},
148
+ objects: [...this.createFileObjects()],
149
+ } as {
150
+ queries: Record<string, GraphQLFieldConfig<any, any, any>>
151
+ mutations: Record<string, GraphQLFieldConfig<any, any, any>>
152
+ objects: Array<GraphQLObjectType | GraphQLInputObjectType>
153
+ },
154
+ )
155
+
156
+ const customQueries = this.createCustomQueries({
157
+ resolvers: this.schemas.schema.resolvers?.queries || {},
158
+ graphqlParser,
159
+ })
160
+ const customQueriesKeys = Object.keys(customQueries)
161
+
162
+ for (const key in customQueriesKeys) {
163
+ // @ts-expect-error
164
+ queriesMutationAndObjects.queries[customQueriesKeys[key]] =
165
+ // @ts-expect-error
166
+ customQueries[customQueriesKeys[key]]
167
+ }
168
+
169
+ // Mutations
170
+ const customMutations = this.createCustomMutations({
171
+ resolvers: this.schemas.schema.resolvers?.mutations || {},
172
+ graphqlParser,
173
+ })
174
+ const customMutationsKeys = Object.keys(customMutations)
175
+
176
+ for (const key in customMutationsKeys) {
177
+ // @ts-expect-error
178
+ queriesMutationAndObjects.mutations[customMutationsKeys[key]] =
179
+ // @ts-expect-error
180
+ customMutations[customMutationsKeys[key]]
181
+ }
182
+
183
+ return {
184
+ queries: queriesMutationAndObjects.queries,
185
+ mutations: queriesMutationAndObjects.mutations,
186
+ scalars,
187
+ enums,
188
+ objects: queriesMutationAndObjects.objects,
189
+ }
190
+ }
191
+
192
+ createFileObjects() {
193
+ const fileInfoObject = new GraphQLObjectType({
194
+ name: 'FileInfo',
195
+ description: 'Object containing information about the file',
196
+ fields: () => ({
197
+ name: { type: GraphQLString },
198
+ url: { type: GraphQLString },
199
+ urlGeneratedAt: {
200
+ type: DateScalarType,
201
+ },
202
+ isPresignedUrl: { type: GraphQLBoolean },
203
+ }),
204
+ })
205
+
206
+ const fileInputObject = new GraphQLInputObjectType({
207
+ name: 'FileInput',
208
+ description: 'Input to create a file',
209
+ fields: () => ({
210
+ file: { type: FileScalarType },
211
+ url: { type: GraphQLString },
212
+ }),
213
+ })
214
+
215
+ this.allObjects.FileInfo = {
216
+ object: fileInfoObject,
217
+ inputObject: fileInputObject,
218
+ }
219
+
220
+ return [fileInfoObject]
221
+ }
222
+
223
+ createScalars() {
224
+ return (
225
+ this.schemas.schema.scalars?.map(
226
+ (scalar) =>
227
+ new GraphQLScalarType({
228
+ ...scalar,
229
+ }),
230
+ ) || []
231
+ )
232
+ }
233
+
234
+ createOrderEnumType(wabeClass: ClassInterface<DevWabeTypes>) {
235
+ const fields = wabeClass.fields
236
+
237
+ const classEnums = Object.keys(fields).reduce(
238
+ (acc, fieldName) => {
239
+ acc[`${fieldName}_ASC`] = { value: { [fieldName]: 'ASC' } }
240
+ acc[`${fieldName}_DESC`] = { value: { [fieldName]: 'DESC' } }
241
+
242
+ return acc
243
+ },
244
+ {} as Record<string, any>,
245
+ )
246
+
247
+ return new GraphQLEnumType({
248
+ name: `${wabeClass.name}Order`,
249
+ values: classEnums,
250
+ })
251
+ }
252
+
253
+ createEnums() {
254
+ return (
255
+ this.schemas.schema.enums?.map((wabeEnum) => {
256
+ const enumValues = wabeEnum.values
257
+
258
+ const values = Object.keys(enumValues).reduce(
259
+ (acc, value) => {
260
+ acc[value] = { value: enumValues[value] }
261
+
262
+ return acc
263
+ },
264
+ {} as Record<string, any>,
265
+ )
266
+
267
+ return new GraphQLEnumType({
268
+ ...wabeEnum,
269
+ values,
270
+ })
271
+ }) || []
272
+ )
273
+ }
274
+
275
+ createObject({
276
+ wabeClass,
277
+ graphqlParser,
278
+ }: {
279
+ wabeClass: ClassInterface<DevWabeTypes>
280
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>
281
+ }) {
282
+ const { name, fields, description } = wabeClass
283
+
284
+ const nameWithoutSpace = name.replace(' ', '')
285
+
286
+ const graphqlParserWithInput = graphqlParser({
287
+ schemaFields: fields,
288
+ graphqlObjectType: 'Object',
289
+ allObjects: this.allObjects,
290
+ })
291
+
292
+ return new GraphQLObjectType({
293
+ name: nameWithoutSpace,
294
+ description,
295
+ // We need to use function here to have lazy loading of fields
296
+ fields: () => ({
297
+ id: { type: new GraphQLNonNull(GraphQLID) },
298
+ ...graphqlParserWithInput.getGraphqlFields(nameWithoutSpace),
299
+ }),
300
+ })
301
+ }
302
+
303
+ createPointerInputObject({
304
+ wabeClass,
305
+ inputCreateFields,
306
+ }: {
307
+ wabeClass: ClassInterface<DevWabeTypes>
308
+ inputCreateFields: GraphQLInputObjectType
309
+ }) {
310
+ const { name } = wabeClass
311
+
312
+ const nameWithoutSpace = name.replace(' ', '')
313
+
314
+ return new GraphQLInputObjectType({
315
+ name: `${nameWithoutSpace}PointerInput`,
316
+ description: `Input to link an object to a pointer ${nameWithoutSpace}`,
317
+ fields: () => ({
318
+ unlink: { type: GraphQLBoolean },
319
+ link: { type: GraphQLID },
320
+ createAndLink: { type: inputCreateFields },
321
+ }),
322
+ })
323
+ }
324
+
325
+ createRelationInputObject({
326
+ wabeClass,
327
+ inputCreateFields,
328
+ }: {
329
+ wabeClass: ClassInterface<DevWabeTypes>
330
+ inputCreateFields: GraphQLInputObjectType
331
+ }) {
332
+ const { name } = wabeClass
333
+
334
+ const nameWithoutSpace = name.replace(' ', '')
335
+
336
+ return new GraphQLInputObjectType({
337
+ name: `${nameWithoutSpace}RelationInput`,
338
+ description: `Input to add a relation to the class ${nameWithoutSpace}`,
339
+ fields: () => ({
340
+ add: { type: new GraphQLList(new GraphQLNonNull(GraphQLID)) },
341
+ remove: {
342
+ type: new GraphQLList(new GraphQLNonNull(GraphQLID)),
343
+ },
344
+ createAndAdd: {
345
+ type: new GraphQLList(new GraphQLNonNull(inputCreateFields)),
346
+ },
347
+ }),
348
+ })
349
+ }
350
+
351
+ createInputObject({
352
+ wabeClass,
353
+ graphqlParser,
354
+ }: {
355
+ wabeClass: ClassInterface<DevWabeTypes>
356
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>
357
+ }) {
358
+ const { name, fields, description } = wabeClass
359
+
360
+ const nameWithoutSpace = name.replace(' ', '')
361
+
362
+ const graphqlParserWithInput = graphqlParser({
363
+ schemaFields: fields,
364
+ graphqlObjectType: 'InputObject',
365
+ allObjects: this.allObjects,
366
+ })
367
+
368
+ return new GraphQLInputObjectType({
369
+ name: `${nameWithoutSpace}Input`,
370
+ description,
371
+ fields: () => ({
372
+ ...graphqlParserWithInput.getGraphqlFields(nameWithoutSpace),
373
+ }),
374
+ })
375
+ }
376
+
377
+ createCreateInputObject({
378
+ wabeClass,
379
+ graphqlParser,
380
+ }: {
381
+ wabeClass: ClassInterface<DevWabeTypes>
382
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>
383
+ }) {
384
+ const { name, fields, description } = wabeClass
385
+
386
+ const nameWithoutSpace = name.replace(' ', '')
387
+
388
+ const graphqlParserWithInput = graphqlParser({
389
+ schemaFields: fields,
390
+ graphqlObjectType: 'CreateFieldsInput',
391
+ allObjects: this.allObjects,
392
+ })
393
+
394
+ return new GraphQLInputObjectType({
395
+ name: `${nameWithoutSpace}CreateFieldsInput`,
396
+ description,
397
+ fields: () => ({
398
+ ...graphqlParserWithInput.getGraphqlFields(nameWithoutSpace),
399
+ }),
400
+ })
401
+ }
402
+
403
+ createUpdateInputObject({
404
+ wabeClass,
405
+ graphqlParser,
406
+ }: {
407
+ wabeClass: ClassInterface<DevWabeTypes>
408
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>
409
+ }) {
410
+ const { name, fields, description } = wabeClass
411
+
412
+ const nameWithoutSpace = name.replace(' ', '')
413
+
414
+ const graphqlParserWithInput = graphqlParser({
415
+ schemaFields: fields,
416
+ graphqlObjectType: 'UpdateFieldsInput',
417
+ allObjects: this.allObjects,
418
+ })
419
+
420
+ return new GraphQLInputObjectType({
421
+ name: `${nameWithoutSpace}UpdateFieldsInput`,
422
+ description,
423
+ fields: () => ({
424
+ ...graphqlParserWithInput.getGraphqlFields(nameWithoutSpace),
425
+ }),
426
+ })
427
+ }
428
+
429
+ createWhereInputObject({
430
+ wabeClass,
431
+ graphqlParser,
432
+ }: {
433
+ wabeClass: ClassInterface<DevWabeTypes>
434
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>
435
+ }) {
436
+ const { name, fields, description } = wabeClass
437
+
438
+ const nameWithoutSpace = name.replace(' ', '')
439
+
440
+ const graphqlParserWithInput = graphqlParser({
441
+ schemaFields: fields,
442
+ graphqlObjectType: 'WhereInputObject',
443
+ allObjects: this.allObjects,
444
+ })
445
+
446
+ const inputObject = new GraphQLInputObjectType({
447
+ name: `${nameWithoutSpace}WhereInput`,
448
+ description,
449
+ fields: (): any => ({
450
+ id: { type: IdWhereInput },
451
+ ...graphqlParserWithInput.getGraphqlFields(nameWithoutSpace),
452
+ ...{
453
+ OR: {
454
+ type: new GraphQLList(inputObject),
455
+ },
456
+ AND: {
457
+ type: new GraphQLList(inputObject),
458
+ },
459
+ },
460
+ search: { type: SearchWhereInput },
461
+ }),
462
+ })
463
+
464
+ return inputObject
465
+ }
466
+
467
+ createConnectionObject({
468
+ object,
469
+ wabeClass,
470
+ }: {
471
+ object: GraphQLObjectType
472
+ wabeClass: ClassInterface<DevWabeTypes>
473
+ }) {
474
+ const edgeObject = new GraphQLObjectType({
475
+ name: `${wabeClass.name}Edge`,
476
+ fields: () => ({
477
+ node: { type: new GraphQLNonNull(object) },
478
+ }),
479
+ })
480
+
481
+ const connectionObject = new GraphQLObjectType({
482
+ name: `${wabeClass.name}Connection`,
483
+ fields: () => ({
484
+ ok: { type: GraphQLBoolean },
485
+ totalCount: { type: GraphQLInt },
486
+ edges: { type: new GraphQLList(edgeObject) },
487
+ }),
488
+ })
489
+
490
+ return connectionObject
491
+ }
492
+
493
+ createCompleteObject(
494
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>,
495
+ wabeClass: ClassInterface<DevWabeTypes>,
496
+ ) {
497
+ const object = this.createObject({ graphqlParser, wabeClass })
498
+
499
+ const connectionObject = this.createConnectionObject({
500
+ object,
501
+ wabeClass,
502
+ })
503
+
504
+ const inputObject = this.createInputObject({
505
+ graphqlParser,
506
+ wabeClass,
507
+ })
508
+
509
+ const createInputObject = this.createCreateInputObject({
510
+ graphqlParser,
511
+ wabeClass,
512
+ })
513
+
514
+ const pointerInputObject = this.createPointerInputObject({
515
+ inputCreateFields: createInputObject,
516
+ wabeClass,
517
+ })
518
+
519
+ const relationInputObject = this.createRelationInputObject({
520
+ inputCreateFields: createInputObject,
521
+ wabeClass,
522
+ })
523
+
524
+ const updateInputObject = this.createUpdateInputObject({
525
+ graphqlParser,
526
+ wabeClass,
527
+ })
528
+
529
+ const whereInputObject = this.createWhereInputObject({
530
+ graphqlParser,
531
+ wabeClass,
532
+ })
533
+
534
+ const orderEnumType = this.createOrderEnumType(wabeClass)
535
+
536
+ this.allObjects[wabeClass.name] = {
537
+ connectionObject,
538
+ createInputObject,
539
+ updateInputObject,
540
+ whereInputObject,
541
+ pointerInputObject,
542
+ relationInputObject,
543
+ inputObject,
544
+ object,
545
+ orderEnumType,
546
+ }
547
+ }
548
+
549
+ _getGraphQLOutputType(
550
+ currentQueryOrMutation:
551
+ | QueryResolver<DevWabeTypes>
552
+ | MutationResolver<DevWabeTypes>,
553
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>,
554
+ currentArgs: SchemaFields<DevWabeTypes>,
555
+ ): GraphQLOutputType | undefined {
556
+ if (currentQueryOrMutation.type === 'Object') {
557
+ const objectGraphqlParser = graphqlParser({
558
+ schemaFields: currentQueryOrMutation.outputObject.fields,
559
+ graphqlObjectType: 'Object',
560
+ allObjects: this.allObjects,
561
+ })
562
+
563
+ return new GraphQLObjectType({
564
+ name: currentQueryOrMutation.outputObject.name,
565
+ fields: () =>
566
+ objectGraphqlParser.getGraphqlFields(
567
+ currentQueryOrMutation.outputObject.name,
568
+ ),
569
+ })
570
+ }
571
+
572
+ if (
573
+ currentQueryOrMutation.type === 'Array' &&
574
+ currentQueryOrMutation.typeValue === 'Object'
575
+ ) {
576
+ const outputObject = graphqlParser({
577
+ schemaFields: currentQueryOrMutation.outputObject.fields,
578
+ graphqlObjectType: 'Object',
579
+ allObjects: this.allObjects,
580
+ })
581
+
582
+ const graphqlObject = new GraphQLObjectType({
583
+ name: currentQueryOrMutation.outputObject.name,
584
+ fields: () =>
585
+ outputObject.getGraphqlFields(
586
+ currentQueryOrMutation.outputObject.name,
587
+ ),
588
+ })
589
+
590
+ return new GraphQLList(
591
+ currentQueryOrMutation.typeValueRequired
592
+ ? new GraphQLNonNull(graphqlObject)
593
+ : graphqlObject,
594
+ )
595
+ }
596
+
597
+ const graphqlParserWithInput = graphqlParser({
598
+ schemaFields: currentArgs,
599
+ graphqlObjectType: 'Object',
600
+ allObjects: this.allObjects,
601
+ })
602
+
603
+ return graphqlParserWithInput.getGraphqlType(currentQueryOrMutation)
604
+ }
605
+
606
+ createCustomMutations({
607
+ resolvers,
608
+ graphqlParser,
609
+ }: {
610
+ resolvers: Record<string, MutationResolver<DevWabeTypes>>
611
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>
612
+ }) {
613
+ return Object.keys(resolvers).reduce(
614
+ (acc, currentKey) => {
615
+ const currentMutation = resolvers[currentKey]
616
+
617
+ if (!currentMutation) return acc
618
+
619
+ const required = !!currentMutation?.required
620
+ const input = currentMutation?.args?.input || {}
621
+ const numberOfFieldsInInput = Object.keys(input).length
622
+
623
+ const currentKeyWithFirstLetterUpperCase = `${currentKey[0]?.toUpperCase()}${currentKey.slice(
624
+ 1,
625
+ )}`
626
+
627
+ const graphqlParserWithInput = graphqlParser({
628
+ schemaFields: input,
629
+ graphqlObjectType: 'InputObject',
630
+ allObjects: this.allObjects,
631
+ })
632
+
633
+ const outputType = this._getGraphQLOutputType(
634
+ currentMutation,
635
+ graphqlParser,
636
+ input,
637
+ )
638
+
639
+ if (!outputType) throw new Error('Invalid mutation output type')
640
+
641
+ const graphqlInput = new GraphQLInputObjectType({
642
+ name: `${currentKeyWithFirstLetterUpperCase}Input`,
643
+ fields: graphqlParserWithInput.getGraphqlFields(
644
+ currentKeyWithFirstLetterUpperCase,
645
+ ),
646
+ })
647
+
648
+ acc[currentKey] = {
649
+ type: required ? new GraphQLNonNull(outputType) : outputType,
650
+ args:
651
+ numberOfFieldsInInput > 0
652
+ ? { input: { type: new GraphQLNonNull(graphqlInput) } }
653
+ : undefined,
654
+ description: currentMutation.description,
655
+ resolve: currentMutation.resolve,
656
+ }
657
+
658
+ return acc
659
+ },
660
+ {} as Record<string, GraphQLFieldConfig<any, any, any>>,
661
+ )
662
+ }
663
+
664
+ createCustomQueries({
665
+ resolvers,
666
+ graphqlParser,
667
+ }: {
668
+ resolvers: Record<string, QueryResolver<DevWabeTypes>>
669
+ graphqlParser: GraphqlParserFactory<DevWabeTypes>
670
+ }) {
671
+ return Object.keys(resolvers).reduce(
672
+ (acc, currentKey) => {
673
+ const currentQuery = resolvers[currentKey]
674
+
675
+ if (!currentQuery) return acc
676
+
677
+ const required = !!currentQuery?.required
678
+ const currentArgs = currentQuery?.args || {}
679
+
680
+ const graphqlParserWithInput = graphqlParser({
681
+ schemaFields: currentArgs,
682
+ graphqlObjectType: 'Object',
683
+ allObjects: this.allObjects,
684
+ })
685
+
686
+ const outputType = this._getGraphQLOutputType(
687
+ currentQuery,
688
+ graphqlParser,
689
+ currentArgs,
690
+ )
691
+
692
+ if (!outputType) throw new Error('Invalid mutation output type')
693
+
694
+ acc[currentKey] = {
695
+ type: required ? new GraphQLNonNull(outputType) : outputType,
696
+ args: graphqlParserWithInput.getGraphqlFields(currentKey),
697
+ description: currentQuery.description,
698
+ resolve: currentQuery.resolve,
699
+ }
700
+
701
+ return acc
702
+ },
703
+ {} as Record<string, GraphQLFieldConfig<any, any, any>>,
704
+ )
705
+ }
706
+
707
+ createDefaultQueries({
708
+ className,
709
+ whereInputType,
710
+ object,
711
+ connectionObject,
712
+ orderEnumType,
713
+ }: {
714
+ className: string
715
+ whereInputType: GraphQLInputObjectType
716
+ object: GraphQLObjectType
717
+ connectionObject: GraphQLObjectType
718
+ orderEnumType: GraphQLEnumType
719
+ }) {
720
+ const classNameWithFirstLetterLowerCase = firstLetterInLowerCase(className)
721
+
722
+ return {
723
+ [classNameWithFirstLetterLowerCase]: {
724
+ type: object,
725
+ description: object.description,
726
+ args: { id: { type: GraphQLID } },
727
+ resolve: (root, args, ctx, info) =>
728
+ queryForOneObject(root, args, ctx, info, className),
729
+ },
730
+ [pluralize(classNameWithFirstLetterLowerCase)]: {
731
+ type: new GraphQLNonNull(connectionObject),
732
+ description: object.description,
733
+ args: {
734
+ where: { type: whereInputType },
735
+ offset: { type: GraphQLInt },
736
+ first: { type: GraphQLInt },
737
+ order: { type: new GraphQLList(new GraphQLNonNull(orderEnumType)) },
738
+ },
739
+ resolve: (root, args, ctx, info) =>
740
+ queryForMultipleObject(root, args, ctx, info, className),
741
+ },
742
+ } as Record<string, GraphQLFieldConfig<any, any, any>>
743
+ }
744
+
745
+ createDefaultMutations({
746
+ className,
747
+ object,
748
+ defaultUpdateInputType,
749
+ defaultCreateInputType,
750
+ whereInputType,
751
+ connectionObject,
752
+ orderEnumType,
753
+ }: {
754
+ className: string
755
+ defaultUpdateInputType: GraphQLInputObjectType
756
+ defaultCreateInputType: GraphQLInputObjectType
757
+ whereInputType: GraphQLInputObjectType
758
+ object: GraphQLObjectType
759
+ connectionObject: GraphQLObjectType
760
+ orderEnumType: GraphQLEnumType
761
+ }) {
762
+ const classNameWithFirstLetterLowerCase = firstLetterInLowerCase(className)
763
+
764
+ const pluralClassName = pluralize(className)
765
+
766
+ const createPayloadType = new GraphQLObjectType({
767
+ name: `Create${className}Payload`,
768
+ fields: () => ({
769
+ [classNameWithFirstLetterLowerCase]: { type: object },
770
+ ok: { type: GraphQLBoolean },
771
+ }),
772
+ })
773
+
774
+ const createInputType = new GraphQLInputObjectType({
775
+ name: `Create${className}Input`,
776
+ fields: () => ({
777
+ fields: { type: defaultCreateInputType },
778
+ }),
779
+ })
780
+
781
+ const createsInputType = new GraphQLInputObjectType({
782
+ name: `Create${pluralClassName}Input`,
783
+ fields: () => ({
784
+ fields: {
785
+ type: new GraphQLNonNull(new GraphQLList(defaultCreateInputType)),
786
+ },
787
+ offset: { type: GraphQLInt },
788
+ first: { type: GraphQLInt },
789
+ order: { type: new GraphQLList(orderEnumType) },
790
+ }),
791
+ })
792
+
793
+ const updatePayloadType = new GraphQLObjectType({
794
+ name: `Update${className}Payload`,
795
+ fields: () => ({
796
+ [classNameWithFirstLetterLowerCase]: { type: object },
797
+ ok: { type: GraphQLBoolean },
798
+ }),
799
+ })
800
+
801
+ const updateInputType = new GraphQLInputObjectType({
802
+ name: `Update${className}Input`,
803
+ fields: () => ({
804
+ id: { type: GraphQLID },
805
+ fields: { type: defaultUpdateInputType },
806
+ }),
807
+ })
808
+
809
+ const updatesInputType = new GraphQLInputObjectType({
810
+ name: `Update${pluralClassName}Input`,
811
+ fields: () => ({
812
+ fields: { type: defaultUpdateInputType },
813
+ where: { type: whereInputType },
814
+ offset: { type: GraphQLInt },
815
+ first: { type: GraphQLInt },
816
+ order: { type: new GraphQLList(orderEnumType) },
817
+ }),
818
+ })
819
+
820
+ const deletePayloadType = new GraphQLObjectType({
821
+ name: `Delete${className}Payload`,
822
+ fields: () => ({
823
+ [classNameWithFirstLetterLowerCase]: { type: object },
824
+ ok: { type: GraphQLBoolean },
825
+ }),
826
+ })
827
+
828
+ const deleteInputType = new GraphQLInputObjectType({
829
+ name: `Delete${className}Input`,
830
+ fields: () => ({
831
+ id: { type: GraphQLID },
832
+ }),
833
+ })
834
+
835
+ const deletesInputType = new GraphQLInputObjectType({
836
+ name: `Delete${pluralClassName}Input`,
837
+ fields: () => ({
838
+ where: { type: whereInputType },
839
+ order: { type: new GraphQLList(orderEnumType) },
840
+ }),
841
+ })
842
+
843
+ return {
844
+ [`create${className}`]: {
845
+ type: createPayloadType,
846
+ description: object.description,
847
+ args: { input: { type: new GraphQLNonNull(createInputType) } },
848
+ resolve: (root, args, ctx, info) =>
849
+ mutationToCreateObject(
850
+ root,
851
+ args,
852
+ ctx,
853
+ info,
854
+ className as keyof WabeTypes['types'],
855
+ ),
856
+ },
857
+ [`create${pluralize(className)}`]: {
858
+ type: new GraphQLNonNull(connectionObject),
859
+ description: object.description,
860
+ args: { input: { type: new GraphQLNonNull(createsInputType) } },
861
+ resolve: (root, args, ctx, info) =>
862
+ mutationToCreateMultipleObjects(
863
+ root,
864
+ args,
865
+ ctx,
866
+ info,
867
+ className as keyof WabeTypes['types'],
868
+ ),
869
+ },
870
+ [`update${className}`]: {
871
+ type: updatePayloadType,
872
+ description: object.description,
873
+ args: { input: { type: new GraphQLNonNull(updateInputType) } },
874
+ resolve: (root, args, ctx, info) =>
875
+ mutationToUpdateObject(
876
+ root,
877
+ args,
878
+ ctx,
879
+ info,
880
+ className as keyof WabeTypes['types'],
881
+ ),
882
+ },
883
+ [`update${pluralize(className)}`]: {
884
+ type: new GraphQLNonNull(connectionObject),
885
+ description: object.description,
886
+ args: { input: { type: new GraphQLNonNull(updatesInputType) } },
887
+ resolve: (root, args, ctx, info) =>
888
+ mutationToUpdateMultipleObjects(
889
+ root,
890
+ args,
891
+ ctx,
892
+ info,
893
+ className as keyof WabeTypes['types'],
894
+ ),
895
+ },
896
+ [`delete${className}`]: {
897
+ type: deletePayloadType,
898
+ description: object.description,
899
+ args: {
900
+ input: {
901
+ type: new GraphQLNonNull(deleteInputType),
902
+ },
903
+ },
904
+ resolve: (root, args, ctx, info) =>
905
+ mutationToDeleteObject(
906
+ root,
907
+ args,
908
+ ctx,
909
+ info,
910
+ className as keyof WabeTypes['types'],
911
+ ),
912
+ },
913
+ [`delete${pluralize(className)}`]: {
914
+ type: new GraphQLNonNull(connectionObject),
915
+ description: object.description,
916
+ args: { input: { type: new GraphQLNonNull(deletesInputType) } },
917
+ resolve: (root, args, ctx, info) =>
918
+ mutationToDeleteMultipleObjects(
919
+ root,
920
+ args,
921
+ ctx,
922
+ info,
923
+ className as keyof WabeTypes['types'],
924
+ ),
925
+ },
926
+ } as Record<string, GraphQLFieldConfig<any, any, any>>
927
+ }
928
+ }