wabe 0.6.12 → 0.6.14
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/dist/database/DatabaseController.d.ts +2 -0
- package/dist/file/FileDevAdapter.d.ts +1 -0
- package/dist/graphql/pointerAndRelationFunction.d.ts +6 -0
- package/dist/index.js +3827 -3541
- package/dist/schema/Schema.d.ts +2 -2
- package/dist/server/generateCodegen.d.ts +10 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/utils/objectKeys.d.ts +1 -0
- package/package.json +7 -4
- package/dev/index.ts +0 -215
- package/dist/schema/resolvers/sendEmail.d.ts +0 -1
- package/generated/schema.graphql +0 -1945
- package/generated/wabe.ts +0 -448
- package/src/authentication/OTP.test.ts +0 -69
- package/src/authentication/OTP.ts +0 -64
- package/src/authentication/Session.test.ts +0 -629
- package/src/authentication/Session.ts +0 -517
- package/src/authentication/cookies.ts +0 -10
- package/src/authentication/defaultAuthentication.ts +0 -209
- package/src/authentication/index.ts +0 -4
- package/src/authentication/interface.ts +0 -177
- package/src/authentication/oauth/GitHub.test.ts +0 -91
- package/src/authentication/oauth/GitHub.ts +0 -121
- package/src/authentication/oauth/Google.test.ts +0 -91
- package/src/authentication/oauth/Google.ts +0 -101
- package/src/authentication/oauth/Oauth2Client.test.ts +0 -219
- package/src/authentication/oauth/Oauth2Client.ts +0 -135
- package/src/authentication/oauth/index.ts +0 -2
- package/src/authentication/oauth/utils.test.ts +0 -33
- package/src/authentication/oauth/utils.ts +0 -27
- package/src/authentication/providers/EmailOTP.test.ts +0 -127
- package/src/authentication/providers/EmailOTP.ts +0 -95
- package/src/authentication/providers/EmailPassword.test.ts +0 -263
- package/src/authentication/providers/EmailPassword.ts +0 -138
- package/src/authentication/providers/EmailPasswordSRP.test.ts +0 -208
- package/src/authentication/providers/EmailPasswordSRP.ts +0 -191
- package/src/authentication/providers/GitHub.ts +0 -24
- package/src/authentication/providers/Google.ts +0 -24
- package/src/authentication/providers/OAuth.test.ts +0 -185
- package/src/authentication/providers/OAuth.ts +0 -106
- package/src/authentication/providers/PhonePassword.test.ts +0 -221
- package/src/authentication/providers/PhonePassword.ts +0 -136
- package/src/authentication/providers/QRCodeOTP.test.ts +0 -77
- package/src/authentication/providers/QRCodeOTP.ts +0 -69
- package/src/authentication/providers/index.ts +0 -6
- package/src/authentication/resolvers/refreshResolver.test.ts +0 -30
- package/src/authentication/resolvers/refreshResolver.ts +0 -19
- package/src/authentication/resolvers/signInWithResolver.inte.test.ts +0 -59
- package/src/authentication/resolvers/signInWithResolver.test.ts +0 -306
- package/src/authentication/resolvers/signInWithResolver.ts +0 -106
- package/src/authentication/resolvers/signOutResolver.test.ts +0 -38
- package/src/authentication/resolvers/signOutResolver.ts +0 -18
- package/src/authentication/resolvers/signUpWithResolver.test.ts +0 -180
- package/src/authentication/resolvers/signUpWithResolver.ts +0 -68
- package/src/authentication/resolvers/verifyChallenge.test.ts +0 -230
- package/src/authentication/resolvers/verifyChallenge.ts +0 -78
- package/src/authentication/roles.test.ts +0 -49
- package/src/authentication/roles.ts +0 -40
- package/src/authentication/security.ts +0 -278
- package/src/authentication/utils.test.ts +0 -97
- package/src/authentication/utils.ts +0 -39
- package/src/cache/InMemoryCache.test.ts +0 -62
- package/src/cache/InMemoryCache.ts +0 -45
- package/src/cron/index.test.ts +0 -17
- package/src/cron/index.ts +0 -43
- package/src/database/DatabaseController.test.ts +0 -613
- package/src/database/DatabaseController.ts +0 -1415
- package/src/database/index.test.ts +0 -1551
- package/src/database/index.ts +0 -9
- package/src/database/interface.ts +0 -308
- package/src/email/DevAdapter.ts +0 -7
- package/src/email/EmailController.test.ts +0 -29
- package/src/email/EmailController.ts +0 -13
- package/src/email/index.ts +0 -2
- package/src/email/interface.ts +0 -36
- package/src/email/templates/sendOtpCode.ts +0 -120
- package/src/file/FileController.ts +0 -28
- package/src/file/FileDevAdapter.ts +0 -51
- package/src/file/hookDeleteFile.ts +0 -25
- package/src/file/hookReadFile.ts +0 -66
- package/src/file/hookUploadFile.ts +0 -52
- package/src/file/index.test.ts +0 -1031
- package/src/file/index.ts +0 -2
- package/src/file/interface.ts +0 -63
- package/src/file/security.ts +0 -156
- package/src/graphql/GraphQLSchema.test.ts +0 -5099
- package/src/graphql/GraphQLSchema.ts +0 -886
- package/src/graphql/index.ts +0 -2
- package/src/graphql/parseGraphqlSchema.ts +0 -85
- package/src/graphql/parser.test.ts +0 -203
- package/src/graphql/parser.ts +0 -707
- package/src/graphql/pointerAndRelationFunction.ts +0 -191
- package/src/graphql/resolvers.ts +0 -464
- package/src/graphql/tests/aggregation.test.ts +0 -1115
- package/src/graphql/tests/e2e.test.ts +0 -590
- package/src/graphql/tests/scalars.test.ts +0 -250
- package/src/graphql/types.ts +0 -227
- package/src/hooks/HookObject.test.ts +0 -122
- package/src/hooks/HookObject.ts +0 -165
- package/src/hooks/authentication.ts +0 -67
- package/src/hooks/createUser.test.ts +0 -77
- package/src/hooks/createUser.ts +0 -10
- package/src/hooks/defaultFields.test.ts +0 -176
- package/src/hooks/defaultFields.ts +0 -32
- package/src/hooks/deleteSession.test.ts +0 -181
- package/src/hooks/deleteSession.ts +0 -20
- package/src/hooks/hashFieldHook.test.ts +0 -152
- package/src/hooks/hashFieldHook.ts +0 -89
- package/src/hooks/index.test.ts +0 -258
- package/src/hooks/index.ts +0 -420
- package/src/hooks/permissions.test.ts +0 -412
- package/src/hooks/permissions.ts +0 -93
- package/src/hooks/protected.test.ts +0 -551
- package/src/hooks/protected.ts +0 -74
- package/src/hooks/searchableFields.test.ts +0 -147
- package/src/hooks/searchableFields.ts +0 -86
- package/src/hooks/session.test.ts +0 -134
- package/src/hooks/session.ts +0 -76
- package/src/hooks/setEmail.test.ts +0 -216
- package/src/hooks/setEmail.ts +0 -33
- package/src/hooks/setupAcl.test.ts +0 -618
- package/src/hooks/setupAcl.ts +0 -25
- package/src/hooks/virtualFields.test.ts +0 -228
- package/src/hooks/virtualFields.ts +0 -48
- package/src/index.ts +0 -9
- package/src/schema/Schema.test.ts +0 -482
- package/src/schema/Schema.ts +0 -839
- package/src/schema/defaultResolvers.ts +0 -93
- package/src/schema/index.ts +0 -1
- package/src/schema/resolvers/meResolver.test.ts +0 -62
- package/src/schema/resolvers/meResolver.ts +0 -10
- package/src/schema/resolvers/resetPassword.test.ts +0 -341
- package/src/schema/resolvers/resetPassword.ts +0 -63
- package/src/schema/resolvers/sendEmail.test.ts +0 -118
- package/src/schema/resolvers/sendEmail.ts +0 -21
- package/src/schema/resolvers/sendOtpCode.test.ts +0 -141
- package/src/schema/resolvers/sendOtpCode.ts +0 -52
- package/src/security.test.ts +0 -4136
- package/src/server/defaultSessionHandler.test.ts +0 -62
- package/src/server/defaultSessionHandler.ts +0 -104
- package/src/server/generateCodegen.ts +0 -433
- package/src/server/index.test.ts +0 -843
- package/src/server/index.ts +0 -336
- package/src/server/interface.ts +0 -11
- package/src/server/routes/authHandler.ts +0 -171
- package/src/server/routes/index.ts +0 -48
- package/src/utils/crypto.test.ts +0 -41
- package/src/utils/crypto.ts +0 -105
- package/src/utils/database.ts +0 -8
- package/src/utils/export.ts +0 -12
- package/src/utils/helper.ts +0 -204
- package/src/utils/index.test.ts +0 -11
- package/src/utils/index.ts +0 -196
- package/src/utils/preload.ts +0 -8
- package/src/utils/testHelper.ts +0 -124
- package/tsconfig.json +0 -32
|
@@ -1,1415 +0,0 @@
|
|
|
1
|
-
import { selectFieldsWithoutPrivateFields } from 'src/utils/helper'
|
|
2
|
-
import type { WabeTypes } from '../..'
|
|
3
|
-
import { initializeHook, OperationType } from '../hooks'
|
|
4
|
-
import type { SchemaInterface } from '../schema'
|
|
5
|
-
import type { WabeContext } from '../server/interface'
|
|
6
|
-
import { contextWithRoot, notEmpty } from '../utils/export'
|
|
7
|
-
import type { DevWabeTypes } from '../utils/helper'
|
|
8
|
-
import {
|
|
9
|
-
type CountOptions,
|
|
10
|
-
type CreateObjectOptions,
|
|
11
|
-
type CreateObjectsOptions,
|
|
12
|
-
type DatabaseAdapter,
|
|
13
|
-
type DeleteObjectOptions,
|
|
14
|
-
type DeleteObjectsOptions,
|
|
15
|
-
type GetObjectOptions,
|
|
16
|
-
type GetObjectsOptions,
|
|
17
|
-
type OutputType,
|
|
18
|
-
type UpdateObjectOptions,
|
|
19
|
-
type UpdateObjectsOptions,
|
|
20
|
-
type WhereType,
|
|
21
|
-
} from './interface'
|
|
22
|
-
|
|
23
|
-
export type Select = Record<string, boolean>
|
|
24
|
-
type SelectWithObject = Record<string, object | boolean>
|
|
25
|
-
|
|
26
|
-
const scalarWhereOperators = new Set([
|
|
27
|
-
'equalTo',
|
|
28
|
-
'notEqualTo',
|
|
29
|
-
'greaterThan',
|
|
30
|
-
'lessThan',
|
|
31
|
-
'greaterThanOrEqualTo',
|
|
32
|
-
'lessThanOrEqualTo',
|
|
33
|
-
'in',
|
|
34
|
-
'notIn',
|
|
35
|
-
'contains',
|
|
36
|
-
'notContains',
|
|
37
|
-
'exists',
|
|
38
|
-
])
|
|
39
|
-
|
|
40
|
-
const isScalarWhereFilter = (value: unknown): boolean =>
|
|
41
|
-
value !== null &&
|
|
42
|
-
typeof value === 'object' &&
|
|
43
|
-
!Array.isArray(value) &&
|
|
44
|
-
Object.keys(value).some((key) => scalarWhereOperators.has(key))
|
|
45
|
-
|
|
46
|
-
type RuntimeVirtualField = {
|
|
47
|
-
type: 'Virtual'
|
|
48
|
-
dependsOn: string[]
|
|
49
|
-
callback: (object: Record<string, unknown>) => unknown
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const isVirtualField = (field: unknown): field is RuntimeVirtualField => {
|
|
53
|
-
if (!field || typeof field !== 'object') return false
|
|
54
|
-
|
|
55
|
-
if (!('type' in field) || field.type !== 'Virtual') return false
|
|
56
|
-
|
|
57
|
-
return true
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export class DatabaseController<T extends WabeTypes> {
|
|
61
|
-
public adapter: DatabaseAdapter<T>
|
|
62
|
-
|
|
63
|
-
constructor(adapter: DatabaseAdapter<T>) {
|
|
64
|
-
this.adapter = adapter
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Get a class definition from the schema by name (case-insensitive)
|
|
69
|
-
*/
|
|
70
|
-
_getClass(className: string | keyof T['types'], context: WabeContext<T>) {
|
|
71
|
-
return context.wabe.config.schema?.classes?.find(
|
|
72
|
-
(c) => c.name.toLowerCase() === String(className).toLowerCase(),
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get field type and target class information
|
|
78
|
-
*/
|
|
79
|
-
_getFieldType(originClassName: string, fieldName: string, context: WabeContext<T>) {
|
|
80
|
-
const realClass = this._getClass(originClassName, context)
|
|
81
|
-
return realClass?.fields[fieldName] as { type: string; class?: string } | undefined
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
_getVirtualFieldsForClass(className: keyof T['types'], context: WabeContext<T>) {
|
|
85
|
-
const currentClass = this._getClass(className, context)
|
|
86
|
-
|
|
87
|
-
if (!currentClass) return {}
|
|
88
|
-
|
|
89
|
-
const virtualFields: Record<string, RuntimeVirtualField> = {}
|
|
90
|
-
|
|
91
|
-
for (const [fieldName, fieldDefinition] of Object.entries(currentClass.fields)) {
|
|
92
|
-
if (!isVirtualField(fieldDefinition)) continue
|
|
93
|
-
|
|
94
|
-
virtualFields[fieldName] = fieldDefinition
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return virtualFields
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
_buildReadSelects({
|
|
101
|
-
className,
|
|
102
|
-
context,
|
|
103
|
-
selectWithoutPointers,
|
|
104
|
-
}: {
|
|
105
|
-
className: keyof T['types']
|
|
106
|
-
context: WabeContext<T>
|
|
107
|
-
selectWithoutPointers: Select
|
|
108
|
-
}) {
|
|
109
|
-
const virtualFieldsByName = this._getVirtualFieldsForClass(className, context)
|
|
110
|
-
const requestedVirtualFields: string[] = []
|
|
111
|
-
|
|
112
|
-
const userSelect: Select = {}
|
|
113
|
-
|
|
114
|
-
for (const [fieldName, selected] of Object.entries(selectWithoutPointers)) {
|
|
115
|
-
if (!selected) continue
|
|
116
|
-
|
|
117
|
-
const virtualField = virtualFieldsByName[fieldName]
|
|
118
|
-
|
|
119
|
-
if (virtualField) {
|
|
120
|
-
requestedVirtualFields.push(fieldName)
|
|
121
|
-
continue
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
userSelect[fieldName] = true
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const adapterSelect: Select = { ...userSelect }
|
|
128
|
-
|
|
129
|
-
for (const virtualFieldName of requestedVirtualFields) {
|
|
130
|
-
const virtualField = virtualFieldsByName[virtualFieldName]
|
|
131
|
-
|
|
132
|
-
if (!virtualField) continue
|
|
133
|
-
|
|
134
|
-
for (const dependencyField of virtualField.dependsOn) {
|
|
135
|
-
const dependencyName = String(dependencyField)
|
|
136
|
-
|
|
137
|
-
// Virtual dependencies are only useful for computation and must never reach adapters.
|
|
138
|
-
if (virtualFieldsByName[dependencyName]) continue
|
|
139
|
-
|
|
140
|
-
adapterSelect[dependencyName] = true
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
userSelect,
|
|
146
|
-
adapterSelect,
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
_buildHookReadSelect({
|
|
151
|
-
className,
|
|
152
|
-
context,
|
|
153
|
-
userSelect,
|
|
154
|
-
selectWithoutPointers,
|
|
155
|
-
}: {
|
|
156
|
-
className: keyof T['types']
|
|
157
|
-
context: WabeContext<T>
|
|
158
|
-
userSelect: Select
|
|
159
|
-
selectWithoutPointers: Select
|
|
160
|
-
}): Select {
|
|
161
|
-
const selectedVirtualFields = Object.keys(this._getVirtualFieldsForClass(className, context))
|
|
162
|
-
.filter((fieldName) => !!selectWithoutPointers[fieldName])
|
|
163
|
-
.map((fieldName) => [fieldName, true])
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
...userSelect,
|
|
167
|
-
...Object.fromEntries(selectedVirtualFields),
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
_initializeReadHook<K extends keyof T['types']>({
|
|
172
|
-
className,
|
|
173
|
-
context,
|
|
174
|
-
userSelect,
|
|
175
|
-
selectWithoutPointers,
|
|
176
|
-
_skipHooks,
|
|
177
|
-
}: {
|
|
178
|
-
className: K
|
|
179
|
-
context: WabeContext<T>
|
|
180
|
-
userSelect: Select
|
|
181
|
-
selectWithoutPointers: Select
|
|
182
|
-
_skipHooks?: boolean
|
|
183
|
-
}) {
|
|
184
|
-
if (_skipHooks) return undefined
|
|
185
|
-
|
|
186
|
-
return initializeHook({
|
|
187
|
-
className,
|
|
188
|
-
context,
|
|
189
|
-
select: this._buildHookReadSelect({
|
|
190
|
-
className,
|
|
191
|
-
context,
|
|
192
|
-
userSelect,
|
|
193
|
-
selectWithoutPointers,
|
|
194
|
-
}),
|
|
195
|
-
objectLoader: this._loadObjectForHooks(className, context),
|
|
196
|
-
objectsLoader: this._loadObjectsForHooks(className, context),
|
|
197
|
-
})
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
_buildSelectWithPointers({
|
|
201
|
-
adapterSelect,
|
|
202
|
-
pointers,
|
|
203
|
-
}: {
|
|
204
|
-
adapterSelect: Select
|
|
205
|
-
pointers: Record<string, { className: string; select: Select }>
|
|
206
|
-
}) {
|
|
207
|
-
return Object.keys(pointers).reduce(
|
|
208
|
-
(acc, fieldName) => {
|
|
209
|
-
acc[fieldName] = true
|
|
210
|
-
return acc
|
|
211
|
-
},
|
|
212
|
-
{ ...adapterSelect },
|
|
213
|
-
)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
_isEmptySelect(select?: Record<string, unknown>): boolean {
|
|
217
|
-
return !!select && Object.keys(select).length === 0
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
_projectObjectForUserSelect({
|
|
221
|
-
object,
|
|
222
|
-
select,
|
|
223
|
-
}: {
|
|
224
|
-
object: Record<string, any> | null | undefined
|
|
225
|
-
select?: SelectWithObject
|
|
226
|
-
}): any {
|
|
227
|
-
if (!object) return object
|
|
228
|
-
if (!select) return object
|
|
229
|
-
|
|
230
|
-
const projectedObject: Record<string, any> = {}
|
|
231
|
-
|
|
232
|
-
for (const [fieldName, selected] of Object.entries(select)) {
|
|
233
|
-
if (!selected) continue
|
|
234
|
-
if (!(fieldName in object)) continue
|
|
235
|
-
|
|
236
|
-
projectedObject[fieldName] = object[fieldName]
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return projectedObject
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
_stripVirtualFieldsFromPayload({
|
|
243
|
-
className,
|
|
244
|
-
context,
|
|
245
|
-
payload,
|
|
246
|
-
}: {
|
|
247
|
-
className: keyof T['types']
|
|
248
|
-
context: WabeContext<T>
|
|
249
|
-
payload: unknown
|
|
250
|
-
}): any {
|
|
251
|
-
if (!payload || typeof payload !== 'object') return {}
|
|
252
|
-
|
|
253
|
-
const virtualFields = this._getVirtualFieldsForClass(className, context)
|
|
254
|
-
|
|
255
|
-
if (Object.keys(virtualFields).length === 0) return payload
|
|
256
|
-
|
|
257
|
-
const filteredPayload: Record<string, unknown> = {}
|
|
258
|
-
|
|
259
|
-
for (const [fieldName, value] of Object.entries(payload)) {
|
|
260
|
-
if (virtualFields[fieldName]) continue
|
|
261
|
-
|
|
262
|
-
filteredPayload[fieldName] = value
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return filteredPayload
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
_stripVirtualFieldsFromSchema(schema: SchemaInterface<T>): SchemaInterface<T> {
|
|
269
|
-
const classes = schema.classes?.map((classDefinition) => {
|
|
270
|
-
const filteredFieldEntries = Object.entries(classDefinition.fields).filter(
|
|
271
|
-
([_fieldName, fieldDefinition]) => !isVirtualField(fieldDefinition),
|
|
272
|
-
)
|
|
273
|
-
const filteredFields = Object.fromEntries(filteredFieldEntries)
|
|
274
|
-
|
|
275
|
-
const allowedFieldNames = new Set(Object.keys(filteredFields))
|
|
276
|
-
|
|
277
|
-
const filteredIndexes = classDefinition.indexes?.filter((index) =>
|
|
278
|
-
allowedFieldNames.has(index.field),
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
return {
|
|
282
|
-
...classDefinition,
|
|
283
|
-
fields: filteredFields,
|
|
284
|
-
indexes: filteredIndexes,
|
|
285
|
-
}
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
return {
|
|
289
|
-
...schema,
|
|
290
|
-
classes,
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
_getSelectMinusPointersAndRelations({
|
|
295
|
-
className,
|
|
296
|
-
context,
|
|
297
|
-
select,
|
|
298
|
-
}: {
|
|
299
|
-
className: keyof T['types']
|
|
300
|
-
context: WabeContext<T>
|
|
301
|
-
select?: SelectWithObject
|
|
302
|
-
}): {
|
|
303
|
-
pointers: Record<string, { className: string; select: Select }>
|
|
304
|
-
selectWithoutPointers: Select
|
|
305
|
-
} {
|
|
306
|
-
const realClass = this._getClass(className, context)
|
|
307
|
-
|
|
308
|
-
if (!realClass) throw new Error('Class not found in schema')
|
|
309
|
-
|
|
310
|
-
if (!select) return { pointers: {}, selectWithoutPointers: {} }
|
|
311
|
-
|
|
312
|
-
const pointers: Record<string, { className: string; select: Select }> = {}
|
|
313
|
-
const selectWithoutPointers: Select = {}
|
|
314
|
-
|
|
315
|
-
const selectEntries = Object.entries(
|
|
316
|
-
context.isRoot ? select : selectFieldsWithoutPrivateFields(select),
|
|
317
|
-
)
|
|
318
|
-
|
|
319
|
-
for (const [fieldName, value] of selectEntries) {
|
|
320
|
-
const field = realClass.fields[fieldName]
|
|
321
|
-
const isPointerOrRelation = field?.type === 'Pointer' || field?.type === 'Relation'
|
|
322
|
-
|
|
323
|
-
if (!isPointerOrRelation) {
|
|
324
|
-
selectWithoutPointers[fieldName] = true
|
|
325
|
-
} else {
|
|
326
|
-
pointers[fieldName] = {
|
|
327
|
-
className: (field as { class: string }).class,
|
|
328
|
-
select: (value === true ? undefined : value) as Select,
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return { pointers, selectWithoutPointers }
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
_isFieldOfType(
|
|
337
|
-
originClassName: string,
|
|
338
|
-
pointerField: string,
|
|
339
|
-
expectedType: 'Pointer' | 'Relation',
|
|
340
|
-
context: WabeContext<T>,
|
|
341
|
-
currentClassName?: string,
|
|
342
|
-
): boolean {
|
|
343
|
-
if (!currentClassName) return false
|
|
344
|
-
|
|
345
|
-
const field = this._getFieldType(originClassName, pointerField, context)
|
|
346
|
-
return (
|
|
347
|
-
field?.type === expectedType && field.class?.toLowerCase() === currentClassName.toLowerCase()
|
|
348
|
-
)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
async _getWhereObjectWithPointerOrRelation<U extends keyof T['types']>(
|
|
352
|
-
className: U,
|
|
353
|
-
where: WhereType<T, U>,
|
|
354
|
-
context: WabeContext<T>,
|
|
355
|
-
) {
|
|
356
|
-
const whereKeys = Object.keys(where) as Array<keyof WhereType<T, U>>
|
|
357
|
-
|
|
358
|
-
const realClass = this._getClass(className, context)
|
|
359
|
-
|
|
360
|
-
const newWhereObject = await whereKeys.reduce(async (acc, whereKey) => {
|
|
361
|
-
const currentAcc = await acc
|
|
362
|
-
|
|
363
|
-
const typedWhereKey = whereKey as string
|
|
364
|
-
|
|
365
|
-
const field = realClass?.fields[typedWhereKey]
|
|
366
|
-
|
|
367
|
-
if (typedWhereKey === 'AND' || typedWhereKey === 'OR') {
|
|
368
|
-
const newWhere = await Promise.all(
|
|
369
|
-
(where[typedWhereKey] as any).map((whereObject: any) =>
|
|
370
|
-
this._getWhereObjectWithPointerOrRelation(className, whereObject, context),
|
|
371
|
-
),
|
|
372
|
-
)
|
|
373
|
-
|
|
374
|
-
return {
|
|
375
|
-
...currentAcc,
|
|
376
|
-
[typedWhereKey]: newWhere,
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
if (field?.type !== 'Pointer' && field?.type !== 'Relation') return acc
|
|
381
|
-
|
|
382
|
-
// @ts-expect-error
|
|
383
|
-
const fieldTargetClass = field.class
|
|
384
|
-
|
|
385
|
-
const relationValue = where[typedWhereKey]
|
|
386
|
-
|
|
387
|
-
// Relation where can already be transformed (e.g. { in: [...] })
|
|
388
|
-
// when reused across count/getObjects; keep scalar filters unchanged.
|
|
389
|
-
if (field?.type === 'Relation' && isScalarWhereFilter(relationValue)) {
|
|
390
|
-
return {
|
|
391
|
-
...currentAcc,
|
|
392
|
-
[typedWhereKey]: relationValue,
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// For Relation: unwrap have/isEmpty structure
|
|
397
|
-
let defaultWhere = relationValue
|
|
398
|
-
if (field?.type === 'Relation' && relationValue) {
|
|
399
|
-
// @ts-expect-error
|
|
400
|
-
if (relationValue.isEmpty !== undefined) {
|
|
401
|
-
// In storage, an empty relation can be either [] or an absent field.
|
|
402
|
-
// Model both cases explicitly so the filter behaves consistently.
|
|
403
|
-
// @ts-expect-error
|
|
404
|
-
return relationValue.isEmpty === true
|
|
405
|
-
? {
|
|
406
|
-
...currentAcc,
|
|
407
|
-
OR: [{ [typedWhereKey]: { equalTo: [] } }, { [typedWhereKey]: { exists: false } }],
|
|
408
|
-
}
|
|
409
|
-
: {
|
|
410
|
-
...currentAcc,
|
|
411
|
-
AND: [
|
|
412
|
-
{ [typedWhereKey]: { exists: true } },
|
|
413
|
-
{ [typedWhereKey]: { notEqualTo: [] } },
|
|
414
|
-
],
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// @ts-expect-error
|
|
419
|
-
if (relationValue.have)
|
|
420
|
-
// @ts-expect-error
|
|
421
|
-
defaultWhere = relationValue.have as typeof defaultWhere
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
const objects = await this.getObjects({
|
|
425
|
-
className: fieldTargetClass,
|
|
426
|
-
// @ts-expect-error
|
|
427
|
-
select: { id: true },
|
|
428
|
-
// @ts-expect-error
|
|
429
|
-
where: defaultWhere,
|
|
430
|
-
context,
|
|
431
|
-
})
|
|
432
|
-
// When no objects match, use impossible condition to return no results
|
|
433
|
-
const relationWhere =
|
|
434
|
-
objects.length > 0
|
|
435
|
-
? {
|
|
436
|
-
in: objects.map((object) => object?.id).filter(notEmpty),
|
|
437
|
-
}
|
|
438
|
-
: { equalTo: '__no_match__' }
|
|
439
|
-
return {
|
|
440
|
-
...currentAcc,
|
|
441
|
-
[typedWhereKey]: relationWhere,
|
|
442
|
-
}
|
|
443
|
-
}, Promise.resolve({}))
|
|
444
|
-
|
|
445
|
-
return {
|
|
446
|
-
...where,
|
|
447
|
-
...newWhereObject,
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
_buildWhereWithACL<K extends keyof T['types']>(
|
|
452
|
-
where: WhereType<T, K>,
|
|
453
|
-
context: WabeContext<T>,
|
|
454
|
-
operation: 'write' | 'read',
|
|
455
|
-
): WhereType<T, K> {
|
|
456
|
-
if (context.isRoot) return where
|
|
457
|
-
|
|
458
|
-
const roleId = context.user?.role?.id
|
|
459
|
-
const userId = context.user?.id
|
|
460
|
-
|
|
461
|
-
const aclNullCondition = {
|
|
462
|
-
acl: { equalTo: null },
|
|
463
|
-
}
|
|
464
|
-
const aclUserCondition = userId
|
|
465
|
-
? {
|
|
466
|
-
acl: {
|
|
467
|
-
users: {
|
|
468
|
-
contains: {
|
|
469
|
-
userId,
|
|
470
|
-
[operation]: true,
|
|
471
|
-
},
|
|
472
|
-
},
|
|
473
|
-
},
|
|
474
|
-
}
|
|
475
|
-
: undefined
|
|
476
|
-
const aclRoleCondition = roleId
|
|
477
|
-
? {
|
|
478
|
-
AND: [
|
|
479
|
-
{
|
|
480
|
-
acl: {
|
|
481
|
-
users: {
|
|
482
|
-
notContains: {
|
|
483
|
-
userId,
|
|
484
|
-
},
|
|
485
|
-
},
|
|
486
|
-
},
|
|
487
|
-
},
|
|
488
|
-
{
|
|
489
|
-
acl: {
|
|
490
|
-
roles: {
|
|
491
|
-
contains: {
|
|
492
|
-
roleId,
|
|
493
|
-
[operation]: true,
|
|
494
|
-
},
|
|
495
|
-
},
|
|
496
|
-
},
|
|
497
|
-
},
|
|
498
|
-
],
|
|
499
|
-
}
|
|
500
|
-
: undefined
|
|
501
|
-
|
|
502
|
-
const aclForUnauthenticated = !userId ? aclNullCondition : undefined
|
|
503
|
-
const aclForUserOrRole =
|
|
504
|
-
userId || roleId
|
|
505
|
-
? {
|
|
506
|
-
OR: [aclNullCondition, aclUserCondition, aclRoleCondition].filter(notEmpty),
|
|
507
|
-
}
|
|
508
|
-
: undefined
|
|
509
|
-
|
|
510
|
-
return {
|
|
511
|
-
AND: [{ ...where }, aclForUnauthenticated, aclForUserOrRole].filter(notEmpty),
|
|
512
|
-
} as WhereType<T, K>
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Private helper to load a single object for hooks (skips hooks to avoid recursion)
|
|
517
|
-
*/
|
|
518
|
-
_loadObjectForHooks(className: keyof T['types'], context: WabeContext<T>) {
|
|
519
|
-
return (id: string) =>
|
|
520
|
-
this.getObject({
|
|
521
|
-
className,
|
|
522
|
-
context: contextWithRoot(context),
|
|
523
|
-
id,
|
|
524
|
-
_skipHooks: true,
|
|
525
|
-
})
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Private helper to load multiple objects for hooks (skips hooks to avoid recursion)
|
|
530
|
-
*/
|
|
531
|
-
_loadObjectsForHooks(className: keyof T['types'], context: WabeContext<T>) {
|
|
532
|
-
return ({ where, ids }: { where?: WhereType<DevWabeTypes, any>; ids: string[] }) =>
|
|
533
|
-
this.getObjects({
|
|
534
|
-
className,
|
|
535
|
-
context: contextWithRoot(context),
|
|
536
|
-
// @ts-expect-error
|
|
537
|
-
where: where ? where : { id: { in: ids } },
|
|
538
|
-
_skipHooks: true,
|
|
539
|
-
})
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* Generic executor for single object operations (create, update, delete, read)
|
|
544
|
-
* Encapsulates the hook lifecycle: Init -> Before -> Adapter -> After
|
|
545
|
-
*/
|
|
546
|
-
async _executeSingleOperationWithHooks<
|
|
547
|
-
K extends keyof T['types'],
|
|
548
|
-
U extends keyof T['types'][K],
|
|
549
|
-
>({
|
|
550
|
-
operationTypeBefore,
|
|
551
|
-
operationTypeAfter,
|
|
552
|
-
className,
|
|
553
|
-
context,
|
|
554
|
-
data,
|
|
555
|
-
select,
|
|
556
|
-
id,
|
|
557
|
-
adapterCallback,
|
|
558
|
-
inputObject,
|
|
559
|
-
}: {
|
|
560
|
-
operationTypeBefore: OperationType
|
|
561
|
-
operationTypeAfter: OperationType
|
|
562
|
-
className: K
|
|
563
|
-
context: WabeContext<T>
|
|
564
|
-
data?: any
|
|
565
|
-
select?: Select
|
|
566
|
-
id?: string
|
|
567
|
-
inputObject?: OutputType<T, K, U>
|
|
568
|
-
adapterCallback: (newData: any) => Promise<OutputType<T, K, U> | { id: string } | null>
|
|
569
|
-
}) {
|
|
570
|
-
const hook = initializeHook({
|
|
571
|
-
className,
|
|
572
|
-
context,
|
|
573
|
-
newData: data,
|
|
574
|
-
// @ts-expect-error
|
|
575
|
-
select,
|
|
576
|
-
objectLoader: this._loadObjectForHooks(className, context),
|
|
577
|
-
objectsLoader: this._loadObjectsForHooks(className, context),
|
|
578
|
-
})
|
|
579
|
-
|
|
580
|
-
const { newData, object: objectFromHook } = await hook.runOnSingleObject({
|
|
581
|
-
operationType: operationTypeBefore,
|
|
582
|
-
id,
|
|
583
|
-
|
|
584
|
-
object: inputObject,
|
|
585
|
-
})
|
|
586
|
-
|
|
587
|
-
const res = await adapterCallback(newData || data)
|
|
588
|
-
|
|
589
|
-
if (!res) return null
|
|
590
|
-
|
|
591
|
-
// If the operation is delete, we use the objectFromHook (snapshot before delete)
|
|
592
|
-
// Otherwise we use the result from adapter (which might be just { id })
|
|
593
|
-
// loading the full object if needed happens inside runOnSingleObject if 'id' is passed
|
|
594
|
-
await hook.runOnSingleObject({
|
|
595
|
-
operationType: operationTypeAfter,
|
|
596
|
-
id: res.id,
|
|
597
|
-
|
|
598
|
-
originalObject: objectFromHook,
|
|
599
|
-
})
|
|
600
|
-
|
|
601
|
-
return res
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
_getRelationSelectWithoutTotalCount(currentSelect?: Select): Select {
|
|
605
|
-
const selectWithoutTotalCount = currentSelect
|
|
606
|
-
? Object.entries(currentSelect).reduce((acc, [key, value]) => {
|
|
607
|
-
if (key === 'totalCount' || key === '_args') return acc
|
|
608
|
-
return {
|
|
609
|
-
...acc,
|
|
610
|
-
[key]: value,
|
|
611
|
-
}
|
|
612
|
-
}, {})
|
|
613
|
-
: undefined
|
|
614
|
-
|
|
615
|
-
return selectWithoutTotalCount && Object.keys(selectWithoutTotalCount).length > 0
|
|
616
|
-
? (selectWithoutTotalCount as Select)
|
|
617
|
-
: { id: true }
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
async _resolvePointerField({
|
|
621
|
-
currentClassName,
|
|
622
|
-
object,
|
|
623
|
-
pointerField,
|
|
624
|
-
currentSelect,
|
|
625
|
-
context,
|
|
626
|
-
_skipHooks,
|
|
627
|
-
}: {
|
|
628
|
-
currentClassName: string
|
|
629
|
-
object: Record<string, any>
|
|
630
|
-
pointerField: string
|
|
631
|
-
currentSelect?: Select
|
|
632
|
-
context: WabeContext<any>
|
|
633
|
-
_skipHooks?: boolean
|
|
634
|
-
}) {
|
|
635
|
-
if (!object[pointerField]) return null
|
|
636
|
-
|
|
637
|
-
return this.getObject({
|
|
638
|
-
className: currentClassName,
|
|
639
|
-
id: object[pointerField],
|
|
640
|
-
context,
|
|
641
|
-
// @ts-expect-error
|
|
642
|
-
select: currentSelect,
|
|
643
|
-
_skipHooks,
|
|
644
|
-
})
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
async _resolveRelationField({
|
|
648
|
-
currentClassName,
|
|
649
|
-
object,
|
|
650
|
-
pointerField,
|
|
651
|
-
currentSelect,
|
|
652
|
-
context,
|
|
653
|
-
_skipHooks,
|
|
654
|
-
}: {
|
|
655
|
-
currentClassName: string
|
|
656
|
-
object: Record<string, any>
|
|
657
|
-
pointerField: string
|
|
658
|
-
currentSelect?: Select
|
|
659
|
-
context: WabeContext<any>
|
|
660
|
-
_skipHooks?: boolean
|
|
661
|
-
}) {
|
|
662
|
-
const relationIds = object[pointerField]
|
|
663
|
-
if (!relationIds) return undefined
|
|
664
|
-
|
|
665
|
-
const selectWithoutTotalCount = this._getRelationSelectWithoutTotalCount(currentSelect)
|
|
666
|
-
const args = (currentSelect as any)?._args || {}
|
|
667
|
-
|
|
668
|
-
const where: any = args.where
|
|
669
|
-
? { AND: [{ id: { in: relationIds } }, args.where] }
|
|
670
|
-
: { id: { in: relationIds } }
|
|
671
|
-
|
|
672
|
-
const order: any = args.order?.reduce(
|
|
673
|
-
(acc: any, currentOrder: any) => {
|
|
674
|
-
// In some AST parsing, enums may come as strings like "age_DESC"
|
|
675
|
-
// or as objects depending on how valueFromASTUntyped processed it.
|
|
676
|
-
if (typeof currentOrder === 'string') {
|
|
677
|
-
const lastUnderscore = currentOrder.lastIndexOf('_')
|
|
678
|
-
if (lastUnderscore !== -1) {
|
|
679
|
-
const field = currentOrder.slice(0, lastUnderscore)
|
|
680
|
-
const direction = currentOrder.slice(lastUnderscore + 1)
|
|
681
|
-
return { ...acc, [field]: direction }
|
|
682
|
-
}
|
|
683
|
-
} else {
|
|
684
|
-
const result = Object.entries(currentOrder)[0]
|
|
685
|
-
if (result && result[0] && result[1]) {
|
|
686
|
-
return { ...acc, [result[0]]: result[1] }
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
return acc
|
|
690
|
-
},
|
|
691
|
-
{} as Record<string, 'ASC' | 'DESC'>,
|
|
692
|
-
)
|
|
693
|
-
|
|
694
|
-
const relationObjects = await this.getObjects({
|
|
695
|
-
className: currentClassName,
|
|
696
|
-
select: selectWithoutTotalCount as any,
|
|
697
|
-
where,
|
|
698
|
-
offset: args.offset,
|
|
699
|
-
first: args.first,
|
|
700
|
-
order,
|
|
701
|
-
context,
|
|
702
|
-
_skipHooks,
|
|
703
|
-
})
|
|
704
|
-
|
|
705
|
-
if (!context.isGraphQLCall) return relationObjects
|
|
706
|
-
|
|
707
|
-
const shouldCount =
|
|
708
|
-
args.offset !== undefined || args.first !== undefined || args.where !== undefined
|
|
709
|
-
const totalCount = shouldCount
|
|
710
|
-
? await this.count({
|
|
711
|
-
className: currentClassName,
|
|
712
|
-
where,
|
|
713
|
-
context,
|
|
714
|
-
})
|
|
715
|
-
: relationObjects.length
|
|
716
|
-
|
|
717
|
-
return {
|
|
718
|
-
totalCount,
|
|
719
|
-
edges: relationObjects.map((object: any) => ({
|
|
720
|
-
node: object,
|
|
721
|
-
})),
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
_getFinalObjectWithPointerAndRelation({
|
|
726
|
-
pointers,
|
|
727
|
-
context,
|
|
728
|
-
originClassName,
|
|
729
|
-
object,
|
|
730
|
-
_skipHooks,
|
|
731
|
-
}: {
|
|
732
|
-
originClassName: keyof T['types']
|
|
733
|
-
pointers: Record<string, { className: string; select: Select }>
|
|
734
|
-
context: WabeContext<any>
|
|
735
|
-
object: Record<string, any> | null | undefined
|
|
736
|
-
_skipHooks?: boolean
|
|
737
|
-
}) {
|
|
738
|
-
if (!object) return Promise.resolve({})
|
|
739
|
-
|
|
740
|
-
return Object.entries(pointers).reduce(
|
|
741
|
-
async (acc, [pointerField, { className: currentClassName, select: currentSelect }]) => {
|
|
742
|
-
const accObject = await acc
|
|
743
|
-
|
|
744
|
-
const isPointer = this._isFieldOfType(
|
|
745
|
-
String(originClassName),
|
|
746
|
-
pointerField,
|
|
747
|
-
'Pointer',
|
|
748
|
-
context,
|
|
749
|
-
currentClassName,
|
|
750
|
-
)
|
|
751
|
-
|
|
752
|
-
if (isPointer) {
|
|
753
|
-
return {
|
|
754
|
-
...accObject,
|
|
755
|
-
[pointerField]: await this._resolvePointerField({
|
|
756
|
-
currentClassName,
|
|
757
|
-
object,
|
|
758
|
-
pointerField,
|
|
759
|
-
currentSelect,
|
|
760
|
-
context,
|
|
761
|
-
_skipHooks,
|
|
762
|
-
}),
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
const isRelation = this._isFieldOfType(
|
|
767
|
-
String(originClassName),
|
|
768
|
-
pointerField,
|
|
769
|
-
'Relation',
|
|
770
|
-
context,
|
|
771
|
-
currentClassName,
|
|
772
|
-
)
|
|
773
|
-
|
|
774
|
-
if (!isRelation) return accObject
|
|
775
|
-
|
|
776
|
-
const relationValue = await this._resolveRelationField({
|
|
777
|
-
currentClassName,
|
|
778
|
-
object,
|
|
779
|
-
pointerField,
|
|
780
|
-
currentSelect,
|
|
781
|
-
context,
|
|
782
|
-
_skipHooks,
|
|
783
|
-
})
|
|
784
|
-
|
|
785
|
-
if (relationValue === undefined) return accObject
|
|
786
|
-
|
|
787
|
-
return {
|
|
788
|
-
...accObject,
|
|
789
|
-
[pointerField]: relationValue,
|
|
790
|
-
}
|
|
791
|
-
},
|
|
792
|
-
Promise.resolve({} as Record<string, any>),
|
|
793
|
-
)
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
async close() {
|
|
797
|
-
await this.adapter.close()
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
createClassIfNotExist(className: string, schema: SchemaInterface<T>): Promise<any> {
|
|
801
|
-
return this.adapter.createClassIfNotExist(className, this._stripVirtualFieldsFromSchema(schema))
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
initializeDatabase(schema: SchemaInterface<T>): Promise<void> {
|
|
805
|
-
return this.adapter.initializeDatabase(this._stripVirtualFieldsFromSchema(schema))
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
async count<K extends keyof T['types']>({
|
|
809
|
-
className,
|
|
810
|
-
context,
|
|
811
|
-
where,
|
|
812
|
-
}: CountOptions<T, K>): Promise<number> {
|
|
813
|
-
const whereWithPointer = await this._getWhereObjectWithPointerOrRelation(
|
|
814
|
-
className,
|
|
815
|
-
where || {},
|
|
816
|
-
context,
|
|
817
|
-
)
|
|
818
|
-
|
|
819
|
-
const whereWithACLCondition = this._buildWhereWithACL(whereWithPointer, context, 'read')
|
|
820
|
-
|
|
821
|
-
const hook = initializeHook({
|
|
822
|
-
className,
|
|
823
|
-
context,
|
|
824
|
-
select: {},
|
|
825
|
-
})
|
|
826
|
-
|
|
827
|
-
await hook?.runOnSingleObject({
|
|
828
|
-
operationType: OperationType.BeforeRead,
|
|
829
|
-
})
|
|
830
|
-
|
|
831
|
-
const count = await this.adapter.count({
|
|
832
|
-
className,
|
|
833
|
-
context,
|
|
834
|
-
where: whereWithACLCondition,
|
|
835
|
-
})
|
|
836
|
-
|
|
837
|
-
await hook?.runOnSingleObject({
|
|
838
|
-
operationType: OperationType.AfterRead,
|
|
839
|
-
})
|
|
840
|
-
|
|
841
|
-
return count
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
async clearDatabase(): Promise<void> {
|
|
845
|
-
await this.adapter.clearDatabase()
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
async getObject<K extends keyof T['types'], U extends keyof T['types'][K]>({
|
|
849
|
-
select,
|
|
850
|
-
className,
|
|
851
|
-
context,
|
|
852
|
-
_skipHooks,
|
|
853
|
-
id,
|
|
854
|
-
where,
|
|
855
|
-
}: GetObjectOptions<T, K, U>): Promise<OutputType<T, K, U>> {
|
|
856
|
-
const { pointers, selectWithoutPointers } = this._getSelectMinusPointersAndRelations({
|
|
857
|
-
className,
|
|
858
|
-
context,
|
|
859
|
-
select: select as SelectWithObject,
|
|
860
|
-
})
|
|
861
|
-
const { userSelect, adapterSelect } = this._buildReadSelects({
|
|
862
|
-
className,
|
|
863
|
-
context,
|
|
864
|
-
selectWithoutPointers,
|
|
865
|
-
})
|
|
866
|
-
|
|
867
|
-
const hook = this._initializeReadHook({
|
|
868
|
-
className,
|
|
869
|
-
context,
|
|
870
|
-
userSelect,
|
|
871
|
-
selectWithoutPointers,
|
|
872
|
-
_skipHooks,
|
|
873
|
-
})
|
|
874
|
-
|
|
875
|
-
await hook?.runOnSingleObject({
|
|
876
|
-
operationType: OperationType.BeforeRead,
|
|
877
|
-
id,
|
|
878
|
-
})
|
|
879
|
-
|
|
880
|
-
const whereWithACLCondition = this._buildWhereWithACL(where || {}, context, 'read')
|
|
881
|
-
|
|
882
|
-
const selectWithPointersAndRelationsToGetId = this._buildSelectWithPointers({
|
|
883
|
-
adapterSelect,
|
|
884
|
-
pointers,
|
|
885
|
-
})
|
|
886
|
-
|
|
887
|
-
const objectToReturn = await this.adapter.getObject({
|
|
888
|
-
className,
|
|
889
|
-
id,
|
|
890
|
-
context: contextWithRoot(context),
|
|
891
|
-
// @ts-expect-error
|
|
892
|
-
select: !select ? undefined : selectWithPointersAndRelationsToGetId,
|
|
893
|
-
where: whereWithACLCondition,
|
|
894
|
-
})
|
|
895
|
-
|
|
896
|
-
const finalObject = {
|
|
897
|
-
...objectToReturn,
|
|
898
|
-
...(await this._getFinalObjectWithPointerAndRelation({
|
|
899
|
-
context,
|
|
900
|
-
originClassName: className,
|
|
901
|
-
pointers,
|
|
902
|
-
object: objectToReturn,
|
|
903
|
-
_skipHooks,
|
|
904
|
-
})),
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
const afterReadResult = await hook?.runOnSingleObject({
|
|
908
|
-
operationType: OperationType.AfterRead,
|
|
909
|
-
id,
|
|
910
|
-
// @ts-expect-error
|
|
911
|
-
object: finalObject,
|
|
912
|
-
})
|
|
913
|
-
const objectAfterHooks = afterReadResult?.object || finalObject
|
|
914
|
-
const objectProjectedForUser = this._projectObjectForUserSelect({
|
|
915
|
-
object: objectAfterHooks,
|
|
916
|
-
select: select as SelectWithObject,
|
|
917
|
-
})
|
|
918
|
-
|
|
919
|
-
return objectProjectedForUser
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
async getObjects<
|
|
923
|
-
K extends keyof T['types'],
|
|
924
|
-
U extends keyof T['types'][K],
|
|
925
|
-
W extends keyof T['types'][K],
|
|
926
|
-
>({
|
|
927
|
-
className,
|
|
928
|
-
select,
|
|
929
|
-
context,
|
|
930
|
-
where,
|
|
931
|
-
_skipHooks,
|
|
932
|
-
first,
|
|
933
|
-
offset,
|
|
934
|
-
order,
|
|
935
|
-
}: GetObjectsOptions<T, K, U, W>): Promise<OutputType<T, K, W>[]> {
|
|
936
|
-
const { pointers, selectWithoutPointers } = this._getSelectMinusPointersAndRelations({
|
|
937
|
-
className,
|
|
938
|
-
context,
|
|
939
|
-
select: select as SelectWithObject,
|
|
940
|
-
})
|
|
941
|
-
const { userSelect, adapterSelect } = this._buildReadSelects({
|
|
942
|
-
className,
|
|
943
|
-
context,
|
|
944
|
-
selectWithoutPointers,
|
|
945
|
-
})
|
|
946
|
-
|
|
947
|
-
const whereWithPointer = await this._getWhereObjectWithPointerOrRelation(
|
|
948
|
-
className,
|
|
949
|
-
where || {},
|
|
950
|
-
context,
|
|
951
|
-
)
|
|
952
|
-
|
|
953
|
-
const whereWithACLCondition = this._buildWhereWithACL(whereWithPointer || {}, context, 'read')
|
|
954
|
-
|
|
955
|
-
const selectWithPointersAndRelationsToGetId = this._buildSelectWithPointers({
|
|
956
|
-
adapterSelect,
|
|
957
|
-
pointers,
|
|
958
|
-
})
|
|
959
|
-
|
|
960
|
-
const hook = this._initializeReadHook({
|
|
961
|
-
className,
|
|
962
|
-
context,
|
|
963
|
-
userSelect,
|
|
964
|
-
selectWithoutPointers,
|
|
965
|
-
_skipHooks,
|
|
966
|
-
})
|
|
967
|
-
|
|
968
|
-
await hook?.runOnMultipleObjects({
|
|
969
|
-
operationType: OperationType.BeforeRead,
|
|
970
|
-
where: whereWithACLCondition,
|
|
971
|
-
})
|
|
972
|
-
|
|
973
|
-
const objectsToReturn = await this.adapter.getObjects({
|
|
974
|
-
className,
|
|
975
|
-
context: contextWithRoot(context),
|
|
976
|
-
first,
|
|
977
|
-
offset,
|
|
978
|
-
where: whereWithACLCondition,
|
|
979
|
-
// @ts-expect-error
|
|
980
|
-
select: !select ? undefined : selectWithPointersAndRelationsToGetId,
|
|
981
|
-
order,
|
|
982
|
-
})
|
|
983
|
-
|
|
984
|
-
const objectsWithPointers = await Promise.all(
|
|
985
|
-
objectsToReturn.map(async (object) => {
|
|
986
|
-
return {
|
|
987
|
-
...object,
|
|
988
|
-
...(await this._getFinalObjectWithPointerAndRelation({
|
|
989
|
-
object,
|
|
990
|
-
context,
|
|
991
|
-
originClassName: className,
|
|
992
|
-
pointers,
|
|
993
|
-
_skipHooks,
|
|
994
|
-
})),
|
|
995
|
-
}
|
|
996
|
-
}),
|
|
997
|
-
)
|
|
998
|
-
|
|
999
|
-
const afterReadResults = await hook?.runOnMultipleObjects({
|
|
1000
|
-
operationType: OperationType.AfterRead,
|
|
1001
|
-
// @ts-expect-error
|
|
1002
|
-
objects: objectsWithPointers,
|
|
1003
|
-
})
|
|
1004
|
-
const objectsAfterHooks = afterReadResults?.objects || objectsWithPointers
|
|
1005
|
-
const projectedObjects = objectsAfterHooks.map((object) =>
|
|
1006
|
-
this._projectObjectForUserSelect({
|
|
1007
|
-
object,
|
|
1008
|
-
select: select as SelectWithObject,
|
|
1009
|
-
}),
|
|
1010
|
-
)
|
|
1011
|
-
|
|
1012
|
-
// Projection keeps only user-requested top-level fields, including virtual fields.
|
|
1013
|
-
return projectedObjects
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
async createObject<
|
|
1017
|
-
K extends keyof T['types'],
|
|
1018
|
-
U extends keyof T['types'][K],
|
|
1019
|
-
W extends keyof T['types'][K],
|
|
1020
|
-
>({
|
|
1021
|
-
className,
|
|
1022
|
-
context,
|
|
1023
|
-
data,
|
|
1024
|
-
select,
|
|
1025
|
-
}: CreateObjectOptions<T, K, U, W>): Promise<OutputType<T, K, W>> {
|
|
1026
|
-
// Here data.file is null but should not be
|
|
1027
|
-
|
|
1028
|
-
const result = await this._executeSingleOperationWithHooks<K, W>({
|
|
1029
|
-
operationTypeBefore: OperationType.BeforeCreate,
|
|
1030
|
-
operationTypeAfter: OperationType.AfterCreate,
|
|
1031
|
-
className,
|
|
1032
|
-
context,
|
|
1033
|
-
data,
|
|
1034
|
-
select: select as Select,
|
|
1035
|
-
adapterCallback: async (newData) => {
|
|
1036
|
-
const payload = this._stripVirtualFieldsFromPayload({
|
|
1037
|
-
className,
|
|
1038
|
-
context,
|
|
1039
|
-
payload: newData || data,
|
|
1040
|
-
})
|
|
1041
|
-
|
|
1042
|
-
const res = await this.adapter.createObject({
|
|
1043
|
-
className,
|
|
1044
|
-
context,
|
|
1045
|
-
select,
|
|
1046
|
-
data: payload,
|
|
1047
|
-
})
|
|
1048
|
-
|
|
1049
|
-
return { id: res.id }
|
|
1050
|
-
},
|
|
1051
|
-
})
|
|
1052
|
-
|
|
1053
|
-
const res = result as { id: string }
|
|
1054
|
-
|
|
1055
|
-
if (this._isEmptySelect(select as Record<string, unknown>)) return null
|
|
1056
|
-
|
|
1057
|
-
const selectWithoutPrivateFields = select ? selectFieldsWithoutPrivateFields(select) : undefined
|
|
1058
|
-
|
|
1059
|
-
return this.getObject({
|
|
1060
|
-
className,
|
|
1061
|
-
context: contextWithRoot(context),
|
|
1062
|
-
select: selectWithoutPrivateFields,
|
|
1063
|
-
id: res.id,
|
|
1064
|
-
})
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
async createObjects<
|
|
1068
|
-
K extends keyof T['types'],
|
|
1069
|
-
U extends keyof T['types'][K],
|
|
1070
|
-
W extends keyof T['types'][K],
|
|
1071
|
-
X extends keyof T['types'][K],
|
|
1072
|
-
>({
|
|
1073
|
-
data,
|
|
1074
|
-
select,
|
|
1075
|
-
className,
|
|
1076
|
-
context,
|
|
1077
|
-
first,
|
|
1078
|
-
offset,
|
|
1079
|
-
order,
|
|
1080
|
-
}: CreateObjectsOptions<T, K, U, W, X>): Promise<OutputType<T, K, W>[]> {
|
|
1081
|
-
if (data.length === 0) return []
|
|
1082
|
-
|
|
1083
|
-
const hooks = await Promise.all(
|
|
1084
|
-
data.map((newData) =>
|
|
1085
|
-
initializeHook({
|
|
1086
|
-
className,
|
|
1087
|
-
context,
|
|
1088
|
-
newData,
|
|
1089
|
-
// @ts-expect-error
|
|
1090
|
-
select,
|
|
1091
|
-
objectLoader: this._loadObjectForHooks(className, context),
|
|
1092
|
-
objectsLoader: this._loadObjectsForHooks(className, context),
|
|
1093
|
-
}),
|
|
1094
|
-
),
|
|
1095
|
-
)
|
|
1096
|
-
|
|
1097
|
-
const arrayOfComputedData = (
|
|
1098
|
-
await Promise.all(
|
|
1099
|
-
hooks.map(
|
|
1100
|
-
async (hook) =>
|
|
1101
|
-
(
|
|
1102
|
-
await hook.runOnMultipleObjects({
|
|
1103
|
-
operationType: OperationType.BeforeCreate,
|
|
1104
|
-
})
|
|
1105
|
-
)?.newData[0],
|
|
1106
|
-
),
|
|
1107
|
-
)
|
|
1108
|
-
).filter(notEmpty)
|
|
1109
|
-
|
|
1110
|
-
const listOfIds = await this.adapter.createObjects({
|
|
1111
|
-
className,
|
|
1112
|
-
select,
|
|
1113
|
-
context,
|
|
1114
|
-
data: arrayOfComputedData.map((payload) =>
|
|
1115
|
-
this._stripVirtualFieldsFromPayload({
|
|
1116
|
-
className,
|
|
1117
|
-
context,
|
|
1118
|
-
payload,
|
|
1119
|
-
}),
|
|
1120
|
-
),
|
|
1121
|
-
first,
|
|
1122
|
-
offset,
|
|
1123
|
-
order,
|
|
1124
|
-
})
|
|
1125
|
-
|
|
1126
|
-
const ids = listOfIds.map(({ id }) => id)
|
|
1127
|
-
|
|
1128
|
-
await Promise.all(
|
|
1129
|
-
hooks.map((hook) =>
|
|
1130
|
-
hook.runOnMultipleObjects({
|
|
1131
|
-
operationType: OperationType.AfterCreate,
|
|
1132
|
-
ids,
|
|
1133
|
-
}),
|
|
1134
|
-
),
|
|
1135
|
-
)
|
|
1136
|
-
|
|
1137
|
-
if (this._isEmptySelect(select as Record<string, unknown>)) return []
|
|
1138
|
-
|
|
1139
|
-
return this.getObjects({
|
|
1140
|
-
className,
|
|
1141
|
-
context: contextWithRoot(context),
|
|
1142
|
-
select,
|
|
1143
|
-
// @ts-expect-error
|
|
1144
|
-
where: { id: { in: ids } },
|
|
1145
|
-
first,
|
|
1146
|
-
offset,
|
|
1147
|
-
order,
|
|
1148
|
-
})
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
async updateObject<
|
|
1152
|
-
K extends keyof T['types'],
|
|
1153
|
-
U extends keyof T['types'][K],
|
|
1154
|
-
W extends keyof T['types'][K],
|
|
1155
|
-
>({
|
|
1156
|
-
id,
|
|
1157
|
-
className,
|
|
1158
|
-
context,
|
|
1159
|
-
data,
|
|
1160
|
-
select,
|
|
1161
|
-
_skipHooks,
|
|
1162
|
-
}: UpdateObjectOptions<T, K, U, W>): Promise<OutputType<T, K, W>> {
|
|
1163
|
-
if (_skipHooks) {
|
|
1164
|
-
const whereWithACLCondition = this._buildWhereWithACL({}, context, 'write')
|
|
1165
|
-
const payload = this._stripVirtualFieldsFromPayload({
|
|
1166
|
-
className,
|
|
1167
|
-
context,
|
|
1168
|
-
payload: data,
|
|
1169
|
-
})
|
|
1170
|
-
|
|
1171
|
-
return this.adapter.updateObject({
|
|
1172
|
-
className,
|
|
1173
|
-
select,
|
|
1174
|
-
id,
|
|
1175
|
-
context,
|
|
1176
|
-
data: payload,
|
|
1177
|
-
where: whereWithACLCondition,
|
|
1178
|
-
}) as Promise<OutputType<T, K, W>>
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
await this._executeSingleOperationWithHooks<K, W>({
|
|
1182
|
-
operationTypeBefore: OperationType.BeforeUpdate,
|
|
1183
|
-
operationTypeAfter: OperationType.AfterUpdate,
|
|
1184
|
-
className,
|
|
1185
|
-
context,
|
|
1186
|
-
data,
|
|
1187
|
-
id,
|
|
1188
|
-
select: select as Select,
|
|
1189
|
-
adapterCallback: async (newData) => {
|
|
1190
|
-
const whereWithACLCondition = this._buildWhereWithACL({}, context, 'write')
|
|
1191
|
-
const payload = this._stripVirtualFieldsFromPayload({
|
|
1192
|
-
className,
|
|
1193
|
-
context,
|
|
1194
|
-
payload: newData || data,
|
|
1195
|
-
})
|
|
1196
|
-
|
|
1197
|
-
await this.adapter.updateObject({
|
|
1198
|
-
className,
|
|
1199
|
-
select,
|
|
1200
|
-
id,
|
|
1201
|
-
context,
|
|
1202
|
-
data: payload,
|
|
1203
|
-
where: whereWithACLCondition,
|
|
1204
|
-
})
|
|
1205
|
-
|
|
1206
|
-
return { id }
|
|
1207
|
-
},
|
|
1208
|
-
})
|
|
1209
|
-
|
|
1210
|
-
if (this._isEmptySelect(select as Record<string, unknown>)) return null
|
|
1211
|
-
|
|
1212
|
-
return this.getObject({
|
|
1213
|
-
className,
|
|
1214
|
-
context,
|
|
1215
|
-
select,
|
|
1216
|
-
id,
|
|
1217
|
-
})
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
async updateObjects<
|
|
1221
|
-
K extends keyof T['types'],
|
|
1222
|
-
U extends keyof T['types'][K],
|
|
1223
|
-
W extends keyof T['types'][K],
|
|
1224
|
-
X extends keyof T['types'][K],
|
|
1225
|
-
>({
|
|
1226
|
-
className,
|
|
1227
|
-
where,
|
|
1228
|
-
context,
|
|
1229
|
-
select,
|
|
1230
|
-
data,
|
|
1231
|
-
first,
|
|
1232
|
-
offset,
|
|
1233
|
-
order,
|
|
1234
|
-
_skipHooks,
|
|
1235
|
-
}: UpdateObjectsOptions<T, K, U, W, X>): Promise<OutputType<T, K, W>[]> {
|
|
1236
|
-
const whereObject = await this._getWhereObjectWithPointerOrRelation(
|
|
1237
|
-
className,
|
|
1238
|
-
where || {},
|
|
1239
|
-
context,
|
|
1240
|
-
)
|
|
1241
|
-
|
|
1242
|
-
const hook = !_skipHooks
|
|
1243
|
-
? initializeHook({
|
|
1244
|
-
className,
|
|
1245
|
-
context,
|
|
1246
|
-
newData: data,
|
|
1247
|
-
// @ts-expect-error
|
|
1248
|
-
select,
|
|
1249
|
-
objectLoader: this._loadObjectForHooks(className, context),
|
|
1250
|
-
objectsLoader: this._loadObjectsForHooks(className, context),
|
|
1251
|
-
})
|
|
1252
|
-
: undefined
|
|
1253
|
-
|
|
1254
|
-
const whereWithACLCondition = this._buildWhereWithACL(whereObject, context, 'write')
|
|
1255
|
-
|
|
1256
|
-
const resultsAfterBeforeUpdate = await hook?.runOnMultipleObjects({
|
|
1257
|
-
operationType: OperationType.BeforeUpdate,
|
|
1258
|
-
where: whereWithACLCondition,
|
|
1259
|
-
})
|
|
1260
|
-
|
|
1261
|
-
const objects = await this.adapter.updateObjects({
|
|
1262
|
-
className,
|
|
1263
|
-
context,
|
|
1264
|
-
select,
|
|
1265
|
-
data: this._stripVirtualFieldsFromPayload({
|
|
1266
|
-
className,
|
|
1267
|
-
context,
|
|
1268
|
-
payload: resultsAfterBeforeUpdate?.newData[0] || data || {},
|
|
1269
|
-
}),
|
|
1270
|
-
where: whereWithACLCondition,
|
|
1271
|
-
first,
|
|
1272
|
-
offset,
|
|
1273
|
-
order,
|
|
1274
|
-
})
|
|
1275
|
-
|
|
1276
|
-
const objectsId = objects.map((object) => object?.id).filter(notEmpty)
|
|
1277
|
-
|
|
1278
|
-
await hook?.runOnMultipleObjects({
|
|
1279
|
-
operationType: OperationType.AfterUpdate,
|
|
1280
|
-
ids: objectsId,
|
|
1281
|
-
originalObjects: resultsAfterBeforeUpdate?.objects || [],
|
|
1282
|
-
})
|
|
1283
|
-
|
|
1284
|
-
if (this._isEmptySelect(select as Record<string, unknown>)) return []
|
|
1285
|
-
|
|
1286
|
-
return this.getObjects({
|
|
1287
|
-
className,
|
|
1288
|
-
context,
|
|
1289
|
-
select,
|
|
1290
|
-
// @ts-expect-error
|
|
1291
|
-
where: { id: { in: objectsId } },
|
|
1292
|
-
first,
|
|
1293
|
-
offset,
|
|
1294
|
-
order,
|
|
1295
|
-
})
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
async deleteObject<K extends keyof T['types'], U extends keyof T['types'][K]>({
|
|
1299
|
-
context,
|
|
1300
|
-
className,
|
|
1301
|
-
id,
|
|
1302
|
-
select,
|
|
1303
|
-
}: DeleteObjectOptions<T, K, U>): Promise<OutputType<T, K, U>> {
|
|
1304
|
-
const result = (await this._executeSingleOperationWithHooks<K, U>({
|
|
1305
|
-
operationTypeBefore: OperationType.BeforeDelete,
|
|
1306
|
-
operationTypeAfter: OperationType.AfterDelete,
|
|
1307
|
-
className,
|
|
1308
|
-
context,
|
|
1309
|
-
id,
|
|
1310
|
-
select: select as Select,
|
|
1311
|
-
adapterCallback: async (_newData) => {
|
|
1312
|
-
const whereWithACLCondition = this._buildWhereWithACL({}, context, 'write')
|
|
1313
|
-
|
|
1314
|
-
// We need to fetch the object before deleting it if we want to return it
|
|
1315
|
-
// But executeSingleOperationWithHooks already fetched it in runOnSingleObject if an id is present
|
|
1316
|
-
// Wait, runOnSingleObject fetches it for the hook context 'object', but does not return it unless we use it.
|
|
1317
|
-
// However, if we utilize _executeSingleOperationWithHooks, the 'object' from before-hook is kept.
|
|
1318
|
-
// But _executeSingleOperationWithHooks logic for delete is slightly different regarding return value:
|
|
1319
|
-
// Delete usually returns the deleted object.
|
|
1320
|
-
// Update: My abstraction returns 'res' from adapterCallback.
|
|
1321
|
-
// So I need to return the object here.
|
|
1322
|
-
|
|
1323
|
-
let objectBeforeDelete = null
|
|
1324
|
-
|
|
1325
|
-
if (select && Object.keys(select).length > 0)
|
|
1326
|
-
objectBeforeDelete = await this.getObject({
|
|
1327
|
-
className,
|
|
1328
|
-
context,
|
|
1329
|
-
select,
|
|
1330
|
-
id,
|
|
1331
|
-
})
|
|
1332
|
-
|
|
1333
|
-
await this.adapter.deleteObject({
|
|
1334
|
-
className,
|
|
1335
|
-
context,
|
|
1336
|
-
id,
|
|
1337
|
-
|
|
1338
|
-
where: whereWithACLCondition,
|
|
1339
|
-
})
|
|
1340
|
-
|
|
1341
|
-
return objectBeforeDelete || { id }
|
|
1342
|
-
},
|
|
1343
|
-
})) as unknown as OutputType<T, K, U>
|
|
1344
|
-
|
|
1345
|
-
if (this._isEmptySelect(select as Record<string, unknown>)) return null as any
|
|
1346
|
-
|
|
1347
|
-
return result
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
async deleteObjects<
|
|
1351
|
-
K extends keyof T['types'],
|
|
1352
|
-
U extends keyof T['types'][K],
|
|
1353
|
-
W extends keyof T['types'][K],
|
|
1354
|
-
>({
|
|
1355
|
-
className,
|
|
1356
|
-
context,
|
|
1357
|
-
select,
|
|
1358
|
-
where,
|
|
1359
|
-
first,
|
|
1360
|
-
offset,
|
|
1361
|
-
order,
|
|
1362
|
-
}: DeleteObjectsOptions<T, K, U, W>): Promise<OutputType<T, K, W>[]> {
|
|
1363
|
-
const whereObject = await this._getWhereObjectWithPointerOrRelation(
|
|
1364
|
-
className,
|
|
1365
|
-
where || {},
|
|
1366
|
-
context,
|
|
1367
|
-
)
|
|
1368
|
-
|
|
1369
|
-
const hook = initializeHook({
|
|
1370
|
-
className,
|
|
1371
|
-
context,
|
|
1372
|
-
// @ts-expect-error
|
|
1373
|
-
select,
|
|
1374
|
-
objectLoader: this._loadObjectForHooks(className, context),
|
|
1375
|
-
objectsLoader: this._loadObjectsForHooks(className, context),
|
|
1376
|
-
})
|
|
1377
|
-
|
|
1378
|
-
const whereWithACLCondition = this._buildWhereWithACL(whereObject, context, 'write')
|
|
1379
|
-
|
|
1380
|
-
let objectsBeforeDelete: OutputType<T, K, W>[] = []
|
|
1381
|
-
|
|
1382
|
-
if (select && Object.keys(select).length > 0)
|
|
1383
|
-
objectsBeforeDelete = await this.getObjects({
|
|
1384
|
-
className,
|
|
1385
|
-
where,
|
|
1386
|
-
select,
|
|
1387
|
-
context,
|
|
1388
|
-
first,
|
|
1389
|
-
offset,
|
|
1390
|
-
order,
|
|
1391
|
-
})
|
|
1392
|
-
|
|
1393
|
-
const resultOfBeforeDelete = await hook.runOnMultipleObjects({
|
|
1394
|
-
operationType: OperationType.BeforeDelete,
|
|
1395
|
-
where: whereWithACLCondition,
|
|
1396
|
-
})
|
|
1397
|
-
|
|
1398
|
-
await this.adapter.deleteObjects({
|
|
1399
|
-
className,
|
|
1400
|
-
context,
|
|
1401
|
-
select,
|
|
1402
|
-
first,
|
|
1403
|
-
offset,
|
|
1404
|
-
where: whereWithACLCondition,
|
|
1405
|
-
order,
|
|
1406
|
-
})
|
|
1407
|
-
|
|
1408
|
-
await hook.runOnMultipleObjects({
|
|
1409
|
-
operationType: OperationType.AfterDelete,
|
|
1410
|
-
originalObjects: resultOfBeforeDelete.objects,
|
|
1411
|
-
})
|
|
1412
|
-
|
|
1413
|
-
return objectsBeforeDelete
|
|
1414
|
-
}
|
|
1415
|
-
}
|