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.
- package/README.md +138 -32
- package/bucket/b.txt +1 -0
- package/dev/index.ts +215 -0
- package/dist/authentication/Session.d.ts +4 -1
- package/dist/authentication/interface.d.ts +16 -0
- package/dist/email/interface.d.ts +1 -1
- package/dist/graphql/resolvers.d.ts +4 -2
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +8713 -8867
- package/dist/server/index.d.ts +4 -2
- package/dist/utils/crypto.d.ts +7 -0
- package/dist/utils/helper.d.ts +4 -1
- package/generated/schema.graphql +16 -14
- package/generated/wabe.ts +4 -4
- package/package.json +15 -15
- package/src/authentication/OTP.test.ts +69 -0
- package/src/authentication/OTP.ts +66 -0
- package/src/authentication/Session.test.ts +665 -0
- package/src/authentication/Session.ts +529 -0
- package/src/authentication/defaultAuthentication.ts +214 -0
- package/src/authentication/index.ts +3 -0
- package/src/authentication/interface.ts +157 -0
- package/src/authentication/oauth/GitHub.test.ts +105 -0
- package/src/authentication/oauth/GitHub.ts +133 -0
- package/src/authentication/oauth/Google.test.ts +105 -0
- package/src/authentication/oauth/Google.ts +110 -0
- package/src/authentication/oauth/Oauth2Client.test.ts +225 -0
- package/src/authentication/oauth/Oauth2Client.ts +140 -0
- package/src/authentication/oauth/index.ts +2 -0
- package/src/authentication/oauth/utils.test.ts +35 -0
- package/src/authentication/oauth/utils.ts +28 -0
- package/src/authentication/providers/EmailOTP.test.ts +138 -0
- package/src/authentication/providers/EmailOTP.ts +93 -0
- package/src/authentication/providers/EmailPassword.test.ts +187 -0
- package/src/authentication/providers/EmailPassword.ts +130 -0
- package/src/authentication/providers/EmailPasswordSRP.test.ts +206 -0
- package/src/authentication/providers/EmailPasswordSRP.ts +184 -0
- package/src/authentication/providers/GitHub.ts +30 -0
- package/src/authentication/providers/Google.ts +30 -0
- package/src/authentication/providers/OAuth.test.ts +185 -0
- package/src/authentication/providers/OAuth.ts +112 -0
- package/src/authentication/providers/PhonePassword.test.ts +187 -0
- package/src/authentication/providers/PhonePassword.ts +129 -0
- package/src/authentication/providers/QRCodeOTP.test.ts +79 -0
- package/src/authentication/providers/QRCodeOTP.ts +65 -0
- package/src/authentication/providers/index.ts +6 -0
- package/src/authentication/resolvers/refreshResolver.test.ts +37 -0
- package/src/authentication/resolvers/refreshResolver.ts +20 -0
- package/src/authentication/resolvers/signInWithResolver.inte.test.ts +59 -0
- package/src/authentication/resolvers/signInWithResolver.test.ts +307 -0
- package/src/authentication/resolvers/signInWithResolver.ts +102 -0
- package/src/authentication/resolvers/signOutResolver.test.ts +41 -0
- package/src/authentication/resolvers/signOutResolver.ts +22 -0
- package/src/authentication/resolvers/signUpWithResolver.test.ts +186 -0
- package/src/authentication/resolvers/signUpWithResolver.ts +69 -0
- package/src/authentication/resolvers/verifyChallenge.test.ts +136 -0
- package/src/authentication/resolvers/verifyChallenge.ts +69 -0
- package/src/authentication/roles.test.ts +59 -0
- package/src/authentication/roles.ts +40 -0
- package/src/authentication/utils.test.ts +99 -0
- package/src/authentication/utils.ts +43 -0
- package/src/cache/InMemoryCache.test.ts +62 -0
- package/src/cache/InMemoryCache.ts +45 -0
- package/src/cron/index.test.ts +17 -0
- package/src/cron/index.ts +46 -0
- package/src/database/DatabaseController.test.ts +625 -0
- package/src/database/DatabaseController.ts +983 -0
- package/src/database/index.test.ts +1230 -0
- package/src/database/index.ts +9 -0
- package/src/database/interface.ts +312 -0
- package/src/email/DevAdapter.ts +8 -0
- package/src/email/EmailController.test.ts +29 -0
- package/src/email/EmailController.ts +13 -0
- package/src/email/index.ts +2 -0
- package/src/email/interface.ts +36 -0
- package/src/email/templates/sendOtpCode.ts +120 -0
- package/src/file/FileController.ts +28 -0
- package/src/file/FileDevAdapter.ts +54 -0
- package/src/file/hookDeleteFile.ts +27 -0
- package/src/file/hookReadFile.ts +70 -0
- package/src/file/hookUploadFile.ts +53 -0
- package/src/file/index.test.ts +979 -0
- package/src/file/index.ts +2 -0
- package/src/file/interface.ts +42 -0
- package/src/graphql/GraphQLSchema.test.ts +4399 -0
- package/src/graphql/GraphQLSchema.ts +928 -0
- package/src/graphql/index.ts +2 -0
- package/src/graphql/parseGraphqlSchema.ts +94 -0
- package/src/graphql/parser.test.ts +217 -0
- package/src/graphql/parser.ts +566 -0
- package/src/graphql/pointerAndRelationFunction.ts +200 -0
- package/src/graphql/resolvers.ts +467 -0
- package/src/graphql/tests/aggregation.test.ts +1123 -0
- package/src/graphql/tests/e2e.test.ts +596 -0
- package/src/graphql/tests/scalars.test.ts +250 -0
- package/src/graphql/types.ts +219 -0
- package/src/hooks/HookObject.test.ts +122 -0
- package/src/hooks/HookObject.ts +168 -0
- package/src/hooks/authentication.ts +76 -0
- package/src/hooks/createUser.test.ts +77 -0
- package/src/hooks/createUser.ts +10 -0
- package/src/hooks/defaultFields.test.ts +187 -0
- package/src/hooks/defaultFields.ts +40 -0
- package/src/hooks/deleteSession.test.ts +181 -0
- package/src/hooks/deleteSession.ts +20 -0
- package/src/hooks/hashFieldHook.test.ts +163 -0
- package/src/hooks/hashFieldHook.ts +97 -0
- package/src/hooks/index.test.ts +207 -0
- package/src/hooks/index.ts +430 -0
- package/src/hooks/permissions.test.ts +424 -0
- package/src/hooks/permissions.ts +113 -0
- package/src/hooks/protected.test.ts +551 -0
- package/src/hooks/protected.ts +72 -0
- package/src/hooks/searchableFields.test.ts +166 -0
- package/src/hooks/searchableFields.ts +98 -0
- package/src/hooks/session.test.ts +138 -0
- package/src/hooks/session.ts +78 -0
- package/src/hooks/setEmail.test.ts +216 -0
- package/src/hooks/setEmail.ts +35 -0
- package/src/hooks/setupAcl.test.ts +589 -0
- package/src/hooks/setupAcl.ts +29 -0
- package/src/index.ts +9 -0
- package/src/schema/Schema.test.ts +484 -0
- package/src/schema/Schema.ts +795 -0
- package/src/schema/defaultResolvers.ts +94 -0
- package/src/schema/index.ts +1 -0
- package/src/schema/resolvers/meResolver.test.ts +62 -0
- package/src/schema/resolvers/meResolver.ts +14 -0
- package/src/schema/resolvers/newFile.ts +0 -0
- package/src/schema/resolvers/resetPassword.test.ts +345 -0
- package/src/schema/resolvers/resetPassword.ts +64 -0
- package/src/schema/resolvers/sendEmail.test.ts +118 -0
- package/src/schema/resolvers/sendEmail.ts +21 -0
- package/src/schema/resolvers/sendOtpCode.test.ts +153 -0
- package/src/schema/resolvers/sendOtpCode.ts +52 -0
- package/src/security.test.ts +3461 -0
- package/src/server/defaultSessionHandler.test.ts +66 -0
- package/src/server/defaultSessionHandler.ts +115 -0
- package/src/server/generateCodegen.ts +476 -0
- package/src/server/index.test.ts +552 -0
- package/src/server/index.ts +354 -0
- package/src/server/interface.ts +11 -0
- package/src/server/routes/authHandler.ts +187 -0
- package/src/server/routes/index.ts +40 -0
- package/src/utils/crypto.test.ts +41 -0
- package/src/utils/crypto.ts +121 -0
- package/src/utils/export.ts +13 -0
- package/src/utils/helper.ts +195 -0
- package/src/utils/index.test.ts +11 -0
- package/src/utils/index.ts +201 -0
- package/src/utils/preload.ts +8 -0
- package/src/utils/testHelper.ts +117 -0
- package/tsconfig.json +32 -0
- package/bunfig.toml +0 -4
- package/dist/ai/index.d.ts +0 -1
- package/dist/ai/interface.d.ts +0 -9
- /package/dist/server/{defaultHandlers.d.ts → defaultSessionHandler.d.ts} +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { getClassFromClassName } from '../utils'
|
|
2
|
+
import type { WabeContext } from '../server/interface'
|
|
3
|
+
import { notEmpty } from '../utils/export'
|
|
4
|
+
|
|
5
|
+
type CreateAndLink = any
|
|
6
|
+
type Link = string
|
|
7
|
+
type Unlink = boolean
|
|
8
|
+
type Add = Array<string>
|
|
9
|
+
type Remove = Array<string>
|
|
10
|
+
type CreateAndAdd = Array<any>
|
|
11
|
+
|
|
12
|
+
export type TypeOfExecution = 'create' | 'update' | 'updateMany'
|
|
13
|
+
|
|
14
|
+
export type InputFields = Record<
|
|
15
|
+
string,
|
|
16
|
+
| {
|
|
17
|
+
createAndLink?: CreateAndLink
|
|
18
|
+
link?: Link
|
|
19
|
+
unlink?: Unlink
|
|
20
|
+
add?: Add
|
|
21
|
+
remove?: Remove
|
|
22
|
+
createAndAdd?: CreateAndAdd
|
|
23
|
+
}
|
|
24
|
+
| string
|
|
25
|
+
>
|
|
26
|
+
|
|
27
|
+
export const createAndLink = async ({
|
|
28
|
+
createAndLink,
|
|
29
|
+
context,
|
|
30
|
+
fieldName,
|
|
31
|
+
className,
|
|
32
|
+
}: {
|
|
33
|
+
createAndLink: CreateAndLink
|
|
34
|
+
fieldName: string
|
|
35
|
+
context: WabeContext<any>
|
|
36
|
+
className: string
|
|
37
|
+
}) => {
|
|
38
|
+
const classInSchema = getClassFromClassName(className, context.wabe.config)
|
|
39
|
+
|
|
40
|
+
const res = await context.wabe.controllers.database.createObject({
|
|
41
|
+
// @ts-expect-error
|
|
42
|
+
className: classInSchema.fields[fieldName].class,
|
|
43
|
+
data: createAndLink,
|
|
44
|
+
select: { id: true },
|
|
45
|
+
context,
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
return res?.id
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const createAndAdd = async ({
|
|
52
|
+
createAndAdd,
|
|
53
|
+
context,
|
|
54
|
+
fieldName,
|
|
55
|
+
className,
|
|
56
|
+
}: {
|
|
57
|
+
createAndAdd: CreateAndAdd
|
|
58
|
+
fieldName: string
|
|
59
|
+
context: WabeContext<any>
|
|
60
|
+
className: string
|
|
61
|
+
}) => {
|
|
62
|
+
const classInSchema = getClassFromClassName(className, context.wabe.config)
|
|
63
|
+
|
|
64
|
+
const result = await context.wabe.controllers.database.createObjects({
|
|
65
|
+
// @ts-expect-error
|
|
66
|
+
className: classInSchema.fields[fieldName].class,
|
|
67
|
+
data: createAndAdd,
|
|
68
|
+
select: { id: true },
|
|
69
|
+
context,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
return result.map((object: any) => object.id)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const add = async ({
|
|
76
|
+
add,
|
|
77
|
+
context,
|
|
78
|
+
fieldName,
|
|
79
|
+
typeOfExecution,
|
|
80
|
+
id,
|
|
81
|
+
className,
|
|
82
|
+
where,
|
|
83
|
+
}: {
|
|
84
|
+
add: Add
|
|
85
|
+
fieldName: string
|
|
86
|
+
context: WabeContext<any>
|
|
87
|
+
typeOfExecution: TypeOfExecution
|
|
88
|
+
id?: string
|
|
89
|
+
className: string
|
|
90
|
+
where: any
|
|
91
|
+
}) => {
|
|
92
|
+
if (typeOfExecution === 'create') return add
|
|
93
|
+
|
|
94
|
+
if (typeOfExecution === 'update' && id) {
|
|
95
|
+
const currentValue = await context.wabe.controllers.database.getObject({
|
|
96
|
+
className,
|
|
97
|
+
id,
|
|
98
|
+
select: { [fieldName]: true },
|
|
99
|
+
context,
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const currentValueIds =
|
|
103
|
+
currentValue?.[fieldName]?.map((object: any) => object.id) || []
|
|
104
|
+
|
|
105
|
+
return [...currentValueIds, ...add].filter(notEmpty)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// For update many we need to get all objects that match the where and add the new value
|
|
109
|
+
// So we doesn't update the field for updateMany
|
|
110
|
+
if (typeOfExecution === 'updateMany' && where) {
|
|
111
|
+
const allObjectsMatchedWithWhere =
|
|
112
|
+
await context.wabe.controllers.database.getObjects({
|
|
113
|
+
className,
|
|
114
|
+
where,
|
|
115
|
+
select: { [fieldName]: true },
|
|
116
|
+
context,
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
return Promise.all(
|
|
120
|
+
allObjectsMatchedWithWhere.flatMap((object: any) => {
|
|
121
|
+
const currentValueIds =
|
|
122
|
+
object[fieldName]?.map((object: any) => object.id) || []
|
|
123
|
+
|
|
124
|
+
return [...currentValueIds, ...add]
|
|
125
|
+
}),
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const remove = async ({
|
|
131
|
+
remove,
|
|
132
|
+
context,
|
|
133
|
+
fieldName,
|
|
134
|
+
typeOfExecution,
|
|
135
|
+
id,
|
|
136
|
+
className,
|
|
137
|
+
where,
|
|
138
|
+
}: {
|
|
139
|
+
remove: Remove
|
|
140
|
+
fieldName: string
|
|
141
|
+
context: WabeContext<any>
|
|
142
|
+
typeOfExecution: TypeOfExecution
|
|
143
|
+
id?: string
|
|
144
|
+
className: string
|
|
145
|
+
where: any
|
|
146
|
+
}) => {
|
|
147
|
+
if (typeOfExecution === 'create') return []
|
|
148
|
+
|
|
149
|
+
const classInSchema = getClassFromClassName(className, context.wabe.config)
|
|
150
|
+
|
|
151
|
+
if (typeOfExecution === 'update' && id) {
|
|
152
|
+
const currentValue = await context.wabe.controllers.database.getObject({
|
|
153
|
+
className,
|
|
154
|
+
id,
|
|
155
|
+
select: { [fieldName]: true },
|
|
156
|
+
context,
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const olderValuesIds =
|
|
160
|
+
currentValue?.[fieldName]?.map((object: any) => object.id) || []
|
|
161
|
+
|
|
162
|
+
await context.wabe.controllers.database.deleteObjects({
|
|
163
|
+
// @ts-expect-error
|
|
164
|
+
className: classInSchema.fields[fieldName].class,
|
|
165
|
+
where: { id: { in: remove } },
|
|
166
|
+
context,
|
|
167
|
+
select: {},
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
return olderValuesIds.filter(
|
|
171
|
+
(olderValue: any) => !remove.includes(olderValue),
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (typeOfExecution === 'updateMany' && where) {
|
|
176
|
+
const allObjectsMatchedWithWhere =
|
|
177
|
+
await context.wabe.controllers.database.getObjects({
|
|
178
|
+
className,
|
|
179
|
+
where,
|
|
180
|
+
select: { [fieldName]: true },
|
|
181
|
+
context,
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const olderValuesIds = allObjectsMatchedWithWhere.flatMap(
|
|
185
|
+
(object: any) => object[fieldName]?.map((object: any) => object.id) || [],
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
await context.wabe.controllers.database.deleteObjects({
|
|
189
|
+
// @ts-expect-error
|
|
190
|
+
className: classInSchema.fields[fieldName].class,
|
|
191
|
+
where: { id: { in: remove } },
|
|
192
|
+
context,
|
|
193
|
+
select: {},
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
return olderValuesIds.filter(
|
|
197
|
+
(olderValue: any) => !remove.includes(olderValue),
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GraphQLResolveInfo,
|
|
3
|
+
SelectionSetNode,
|
|
4
|
+
FragmentSpreadNode,
|
|
5
|
+
FragmentDefinitionNode,
|
|
6
|
+
} from 'graphql'
|
|
7
|
+
import type { WabeTypes } from '..'
|
|
8
|
+
import type { WabeContext } from '../server/interface'
|
|
9
|
+
import { contextWithoutGraphQLCall, firstLetterInLowerCase } from '../utils'
|
|
10
|
+
import {
|
|
11
|
+
type InputFields,
|
|
12
|
+
type TypeOfExecution,
|
|
13
|
+
add,
|
|
14
|
+
createAndAdd,
|
|
15
|
+
createAndLink,
|
|
16
|
+
remove,
|
|
17
|
+
} from './pointerAndRelationFunction'
|
|
18
|
+
|
|
19
|
+
const expandFragmentSpread = (
|
|
20
|
+
fragmentSpread: FragmentSpreadNode,
|
|
21
|
+
fragments: Record<string, FragmentDefinitionNode>,
|
|
22
|
+
className: string,
|
|
23
|
+
): Record<string, any> => {
|
|
24
|
+
const fragmentName = fragmentSpread.name.value
|
|
25
|
+
const fragmentDef = fragments[fragmentName]
|
|
26
|
+
|
|
27
|
+
if (!fragmentDef) {
|
|
28
|
+
throw new Error(`Fragment "${fragmentName}" not found`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return extractFieldsFromSetNode(
|
|
32
|
+
fragmentDef.selectionSet,
|
|
33
|
+
className,
|
|
34
|
+
fragments,
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const extractFieldsFromSetNode = (
|
|
39
|
+
selectionSet: SelectionSetNode,
|
|
40
|
+
className: string,
|
|
41
|
+
fragments?: Record<string, FragmentDefinitionNode>,
|
|
42
|
+
options?: { ignoreClassField?: boolean },
|
|
43
|
+
): Record<string, any> => {
|
|
44
|
+
const ignoredFields = ['edges', 'node', 'clientMutationId', 'ok']
|
|
45
|
+
const shouldIgnoreClassField = options?.ignoreClassField ?? true
|
|
46
|
+
|
|
47
|
+
if (shouldIgnoreClassField && className)
|
|
48
|
+
ignoredFields.push(firstLetterInLowerCase(className))
|
|
49
|
+
|
|
50
|
+
return selectionSet.selections?.reduce(
|
|
51
|
+
(acc, selection) => {
|
|
52
|
+
// Handle fragment spreads
|
|
53
|
+
if (selection.kind === 'FragmentSpread') {
|
|
54
|
+
if (!fragments) {
|
|
55
|
+
throw new Error('Fragment spreads require fragments to be provided')
|
|
56
|
+
}
|
|
57
|
+
const fragmentFields = expandFragmentSpread(
|
|
58
|
+
selection as FragmentSpreadNode,
|
|
59
|
+
fragments,
|
|
60
|
+
className,
|
|
61
|
+
)
|
|
62
|
+
return { ...acc, ...fragmentFields }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//@ts-expect-error
|
|
66
|
+
const currentValue = selection.name.value
|
|
67
|
+
|
|
68
|
+
if (
|
|
69
|
+
selection.selectionSet?.selections &&
|
|
70
|
+
selection.selectionSet?.selections?.length > 0
|
|
71
|
+
) {
|
|
72
|
+
const res = extractFieldsFromSetNode(
|
|
73
|
+
selection.selectionSet,
|
|
74
|
+
className,
|
|
75
|
+
fragments,
|
|
76
|
+
{ ignoreClassField: false },
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if (ignoredFields.indexOf(currentValue) === -1)
|
|
80
|
+
return {
|
|
81
|
+
...acc,
|
|
82
|
+
[currentValue]: res,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
...acc,
|
|
87
|
+
...res,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (ignoredFields.indexOf(currentValue) === -1) acc[currentValue] = true
|
|
92
|
+
|
|
93
|
+
return acc
|
|
94
|
+
},
|
|
95
|
+
{} as Record<string, any>,
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const getFieldsFromInfo = (info: GraphQLResolveInfo, className: string) => {
|
|
100
|
+
const selectionSet = info.fieldNodes[0]?.selectionSet
|
|
101
|
+
|
|
102
|
+
if (!selectionSet) throw new Error('No output fields provided')
|
|
103
|
+
|
|
104
|
+
const fields = extractFieldsFromSetNode(
|
|
105
|
+
selectionSet,
|
|
106
|
+
className,
|
|
107
|
+
info.fragments,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if (!fields) throw new Error('No fields provided')
|
|
111
|
+
|
|
112
|
+
return fields
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const getFieldsOfClassName = ({
|
|
116
|
+
fields,
|
|
117
|
+
className,
|
|
118
|
+
context,
|
|
119
|
+
}: {
|
|
120
|
+
fields: string[]
|
|
121
|
+
className: string
|
|
122
|
+
context: WabeContext<any>
|
|
123
|
+
}): {
|
|
124
|
+
classFields: string[]
|
|
125
|
+
othersFields: string[]
|
|
126
|
+
} => {
|
|
127
|
+
const classFields = context.wabe.config.schema?.classes?.find(
|
|
128
|
+
(schemaClass) => schemaClass.name === className,
|
|
129
|
+
)?.fields
|
|
130
|
+
|
|
131
|
+
if (!classFields) return { classFields: [], othersFields: fields }
|
|
132
|
+
|
|
133
|
+
const sameFieldsAsClass = fields.filter((field) => {
|
|
134
|
+
// If the field exist in the class
|
|
135
|
+
// id is automatically include in a class but not provided in fields
|
|
136
|
+
if (classFields[field] || field === 'id') return true
|
|
137
|
+
|
|
138
|
+
// If the name of the field is include in the field provided
|
|
139
|
+
// For example if a pointer field name "Role" is include in the field "role.name"
|
|
140
|
+
if (
|
|
141
|
+
Object.keys(classFields).find((classField) => field.includes(classField))
|
|
142
|
+
)
|
|
143
|
+
return true
|
|
144
|
+
|
|
145
|
+
return false
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const othersFields = fields.filter(
|
|
149
|
+
(field) => !sameFieldsAsClass.includes(field),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
return { classFields: sameFieldsAsClass, othersFields }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const executeRelationOnFields = ({
|
|
156
|
+
className,
|
|
157
|
+
fields,
|
|
158
|
+
context,
|
|
159
|
+
id,
|
|
160
|
+
typeOfExecution,
|
|
161
|
+
where,
|
|
162
|
+
}: {
|
|
163
|
+
className: string
|
|
164
|
+
fields: InputFields
|
|
165
|
+
context: WabeContext<any>
|
|
166
|
+
id?: string
|
|
167
|
+
where?: any
|
|
168
|
+
typeOfExecution?: TypeOfExecution
|
|
169
|
+
}) => {
|
|
170
|
+
const entries = Object.entries(fields)
|
|
171
|
+
|
|
172
|
+
return entries.reduce(
|
|
173
|
+
async (acc, [fieldName, value]) => {
|
|
174
|
+
const newAcc = await acc
|
|
175
|
+
|
|
176
|
+
if (value instanceof File) {
|
|
177
|
+
newAcc[fieldName] = value
|
|
178
|
+
} else if (typeof value === 'object' && value?.createAndLink) {
|
|
179
|
+
newAcc[fieldName] = await createAndLink({
|
|
180
|
+
createAndLink: value.createAndLink,
|
|
181
|
+
fieldName,
|
|
182
|
+
context: contextWithoutGraphQLCall(context),
|
|
183
|
+
className,
|
|
184
|
+
})
|
|
185
|
+
} else if (typeof value === 'object' && value?.link) {
|
|
186
|
+
newAcc[fieldName] = value.link
|
|
187
|
+
} else if (typeof value === 'object' && value.unlink) {
|
|
188
|
+
newAcc[fieldName] = null
|
|
189
|
+
} else if (typeof value === 'object' && value?.createAndAdd) {
|
|
190
|
+
newAcc[fieldName] = await createAndAdd({
|
|
191
|
+
createAndAdd: value.createAndAdd,
|
|
192
|
+
fieldName,
|
|
193
|
+
context: contextWithoutGraphQLCall(context),
|
|
194
|
+
className,
|
|
195
|
+
})
|
|
196
|
+
} else if (typeof value === 'object' && value?.add) {
|
|
197
|
+
const addValue = await add({
|
|
198
|
+
add: value.add,
|
|
199
|
+
context: contextWithoutGraphQLCall(context),
|
|
200
|
+
fieldName,
|
|
201
|
+
typeOfExecution: typeOfExecution || 'create',
|
|
202
|
+
id,
|
|
203
|
+
className,
|
|
204
|
+
where,
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
if (addValue) newAcc[fieldName] = addValue
|
|
208
|
+
} else if (typeof value === 'object' && value?.remove) {
|
|
209
|
+
const removeValue = await remove({
|
|
210
|
+
remove: value.remove,
|
|
211
|
+
context: contextWithoutGraphQLCall(context),
|
|
212
|
+
fieldName,
|
|
213
|
+
typeOfExecution: typeOfExecution || 'create',
|
|
214
|
+
id,
|
|
215
|
+
className,
|
|
216
|
+
where,
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
if (removeValue) newAcc[fieldName] = removeValue
|
|
220
|
+
} else {
|
|
221
|
+
newAcc[fieldName] = value
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return newAcc
|
|
225
|
+
},
|
|
226
|
+
Promise.resolve({}) as Promise<Record<string, any>>,
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const transformOrder = (
|
|
231
|
+
order?: Array<string>,
|
|
232
|
+
): Record<string, 'ASC' | 'DESC'> =>
|
|
233
|
+
order?.reduce(
|
|
234
|
+
(acc, currentOrder) => {
|
|
235
|
+
const result = Object.entries(currentOrder)[0]
|
|
236
|
+
|
|
237
|
+
if (!result || !result[0] || !result[1]) return acc
|
|
238
|
+
|
|
239
|
+
// @ts-expect-error
|
|
240
|
+
acc[result[0]] = result[1]
|
|
241
|
+
|
|
242
|
+
return acc
|
|
243
|
+
},
|
|
244
|
+
{} as Record<string, 'ASC' | 'DESC'>,
|
|
245
|
+
) || {}
|
|
246
|
+
|
|
247
|
+
export const queryForOneObject = (
|
|
248
|
+
_: any,
|
|
249
|
+
{ id }: any,
|
|
250
|
+
context: WabeContext<any>,
|
|
251
|
+
info: GraphQLResolveInfo,
|
|
252
|
+
className: keyof WabeTypes['types'],
|
|
253
|
+
) => {
|
|
254
|
+
const select = getFieldsFromInfo(info, className)
|
|
255
|
+
|
|
256
|
+
return context.wabe.controllers.database.getObject({
|
|
257
|
+
className,
|
|
258
|
+
id,
|
|
259
|
+
select,
|
|
260
|
+
context,
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export const queryForMultipleObject = async (
|
|
265
|
+
_: any,
|
|
266
|
+
{ where, offset, first, order }: any,
|
|
267
|
+
context: WabeContext<any>,
|
|
268
|
+
info: GraphQLResolveInfo,
|
|
269
|
+
className: keyof WabeTypes['types'],
|
|
270
|
+
) => {
|
|
271
|
+
const select = getFieldsFromInfo(info, className)
|
|
272
|
+
|
|
273
|
+
const { totalCount, ...selectWithoutTotalCount } = select
|
|
274
|
+
|
|
275
|
+
const objects = await context.wabe.controllers.database.getObjects({
|
|
276
|
+
className,
|
|
277
|
+
where,
|
|
278
|
+
select: selectWithoutTotalCount,
|
|
279
|
+
offset,
|
|
280
|
+
first,
|
|
281
|
+
context,
|
|
282
|
+
order: transformOrder(order),
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
totalCount: totalCount
|
|
287
|
+
? await context.wabe.controllers.database.count({
|
|
288
|
+
className,
|
|
289
|
+
where,
|
|
290
|
+
context,
|
|
291
|
+
})
|
|
292
|
+
: undefined,
|
|
293
|
+
edges: objects.map((object: any) => ({
|
|
294
|
+
node: object,
|
|
295
|
+
})),
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export const mutationToCreateObject = async (
|
|
300
|
+
_: any,
|
|
301
|
+
args: any,
|
|
302
|
+
context: WabeContext<any>,
|
|
303
|
+
info: GraphQLResolveInfo,
|
|
304
|
+
className: keyof WabeTypes['types'],
|
|
305
|
+
) => {
|
|
306
|
+
const select = getFieldsFromInfo(info, className)
|
|
307
|
+
|
|
308
|
+
const updatedFieldsToCreate = await executeRelationOnFields({
|
|
309
|
+
className,
|
|
310
|
+
fields: args.input?.fields,
|
|
311
|
+
context,
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
return {
|
|
315
|
+
[firstLetterInLowerCase(className)]:
|
|
316
|
+
await context.wabe.controllers.database.createObject({
|
|
317
|
+
className,
|
|
318
|
+
data: updatedFieldsToCreate,
|
|
319
|
+
select,
|
|
320
|
+
context,
|
|
321
|
+
}),
|
|
322
|
+
ok: true,
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export const mutationToCreateMultipleObjects = async (
|
|
327
|
+
_: any,
|
|
328
|
+
{ input: { fields, offset, first, order } }: any,
|
|
329
|
+
context: WabeContext<any>,
|
|
330
|
+
info: GraphQLResolveInfo,
|
|
331
|
+
className: keyof WabeTypes['types'],
|
|
332
|
+
) => {
|
|
333
|
+
const select = getFieldsFromInfo(info, className)
|
|
334
|
+
const inputFields = fields as Array<any>
|
|
335
|
+
|
|
336
|
+
const updatedFieldsToCreate = await Promise.all(
|
|
337
|
+
inputFields.map((inputField) =>
|
|
338
|
+
executeRelationOnFields({
|
|
339
|
+
className,
|
|
340
|
+
fields: inputField,
|
|
341
|
+
context,
|
|
342
|
+
}),
|
|
343
|
+
),
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
const objects = await context.wabe.controllers.database.createObjects({
|
|
347
|
+
className,
|
|
348
|
+
data: updatedFieldsToCreate,
|
|
349
|
+
select,
|
|
350
|
+
offset,
|
|
351
|
+
first,
|
|
352
|
+
context,
|
|
353
|
+
order: transformOrder(order),
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
edges: objects.map((object: any) => ({ node: object })),
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export const mutationToUpdateObject = async (
|
|
362
|
+
_: any,
|
|
363
|
+
args: any,
|
|
364
|
+
context: WabeContext<any>,
|
|
365
|
+
info: GraphQLResolveInfo,
|
|
366
|
+
className: keyof WabeTypes['types'],
|
|
367
|
+
) => {
|
|
368
|
+
const select = getFieldsFromInfo(info, className)
|
|
369
|
+
|
|
370
|
+
const updatedFields = await executeRelationOnFields({
|
|
371
|
+
className,
|
|
372
|
+
fields: args.input?.fields,
|
|
373
|
+
context,
|
|
374
|
+
id: args.input?.id,
|
|
375
|
+
typeOfExecution: 'update',
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
[firstLetterInLowerCase(className)]:
|
|
380
|
+
await context.wabe.controllers.database.updateObject({
|
|
381
|
+
className,
|
|
382
|
+
id: args.input?.id,
|
|
383
|
+
data: updatedFields,
|
|
384
|
+
select,
|
|
385
|
+
context,
|
|
386
|
+
}),
|
|
387
|
+
ok: true,
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export const mutationToUpdateMultipleObjects = async (
|
|
392
|
+
_: any,
|
|
393
|
+
{ input: { fields, where, offset, first, order } }: any,
|
|
394
|
+
context: WabeContext<any>,
|
|
395
|
+
info: GraphQLResolveInfo,
|
|
396
|
+
className: keyof WabeTypes['types'],
|
|
397
|
+
) => {
|
|
398
|
+
const select = getFieldsFromInfo(info, className)
|
|
399
|
+
|
|
400
|
+
const updatedFields = await executeRelationOnFields({
|
|
401
|
+
className,
|
|
402
|
+
fields,
|
|
403
|
+
context,
|
|
404
|
+
typeOfExecution: 'updateMany',
|
|
405
|
+
where,
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
const objects = await context.wabe.controllers.database.updateObjects({
|
|
409
|
+
className,
|
|
410
|
+
where,
|
|
411
|
+
data: updatedFields,
|
|
412
|
+
select,
|
|
413
|
+
offset,
|
|
414
|
+
first,
|
|
415
|
+
context,
|
|
416
|
+
order,
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
edges: objects.map((object: any) => ({ node: object })),
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export const mutationToDeleteObject = async (
|
|
425
|
+
_: any,
|
|
426
|
+
args: any,
|
|
427
|
+
context: WabeContext<any>,
|
|
428
|
+
info: GraphQLResolveInfo,
|
|
429
|
+
className: keyof WabeTypes['types'],
|
|
430
|
+
) => {
|
|
431
|
+
const select = getFieldsFromInfo(info, className)
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
[firstLetterInLowerCase(className)]:
|
|
435
|
+
await context.wabe.controllers.database.deleteObject({
|
|
436
|
+
className,
|
|
437
|
+
id: args.input?.id,
|
|
438
|
+
select,
|
|
439
|
+
context,
|
|
440
|
+
}),
|
|
441
|
+
ok: true,
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export const mutationToDeleteMultipleObjects = async (
|
|
446
|
+
_: any,
|
|
447
|
+
{ input: { where, offset, first, order } }: any,
|
|
448
|
+
context: WabeContext<any>,
|
|
449
|
+
info: GraphQLResolveInfo,
|
|
450
|
+
className: keyof WabeTypes['types'],
|
|
451
|
+
) => {
|
|
452
|
+
const select = getFieldsFromInfo(info, className)
|
|
453
|
+
|
|
454
|
+
const objects = await context.wabe.controllers.database.deleteObjects({
|
|
455
|
+
className,
|
|
456
|
+
where,
|
|
457
|
+
select,
|
|
458
|
+
offset,
|
|
459
|
+
first,
|
|
460
|
+
context,
|
|
461
|
+
order,
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
return {
|
|
465
|
+
edges: objects.map((object: any) => ({ node: object })),
|
|
466
|
+
}
|
|
467
|
+
}
|