@deessejs/collections 0.0.1
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/package.json +60 -0
- package/src/adapter.ts +38 -0
- package/src/collection.ts +138 -0
- package/src/config.ts +134 -0
- package/src/field-type.ts +40 -0
- package/src/field.ts +46 -0
- package/src/fields/f.ts +192 -0
- package/src/fields/index.ts +1 -0
- package/src/index.ts +27 -0
- package/src/migrations.ts +49 -0
- package/src/operations/collection-operations.ts +808 -0
- package/src/operations/index.ts +2 -0
- package/src/operations/types.ts +141 -0
- package/src/schema.ts +62 -0
- package/tests/adapter.test.ts +35 -0
- package/tests/collection.test.ts +205 -0
- package/tests/config.test.ts +58 -0
- package/tests/field-type.test.ts +181 -0
- package/tests/field.test.ts +201 -0
- package/tests/fixtures.ts +44 -0
- package/tests/hooks.test.ts +1076 -0
- package/tests/integration/hooks.test.ts +329 -0
- package/tests/metadata.test.ts +200 -0
- package/tests/schema.test.ts +58 -0
- package/tests/type-inference.test.ts +108 -0
- package/tsconfig.json +32 -0
- package/tsup.config.ts +11 -0
- package/vitest.config.ts +29 -0
- package/vitest.integration.config.ts +9 -0
|
@@ -0,0 +1,1076 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { collection } from '../src/collection'
|
|
3
|
+
import { field } from '../src/field'
|
|
4
|
+
import { f } from '../src'
|
|
5
|
+
import { createCollectionOperations } from '../src/operations/collection-operations'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Mock table schema for testing
|
|
9
|
+
*/
|
|
10
|
+
const mockTable = {
|
|
11
|
+
id: { name: 'id' },
|
|
12
|
+
name: { name: 'name' },
|
|
13
|
+
email: { name: 'email' },
|
|
14
|
+
active: { name: 'active' }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a mock database query builder that properly handles chaining
|
|
19
|
+
*/
|
|
20
|
+
const createQueryBuilder = (baseReturn: unknown[], options: { limit?: number } = {}) => {
|
|
21
|
+
let returnValue = [...baseReturn]
|
|
22
|
+
|
|
23
|
+
const builder: any = {
|
|
24
|
+
where: vi.fn(() => builder),
|
|
25
|
+
limit: vi.fn((n: number) => {
|
|
26
|
+
returnValue = returnValue.slice(0, n)
|
|
27
|
+
return builder
|
|
28
|
+
}),
|
|
29
|
+
orderBy: vi.fn(() => builder),
|
|
30
|
+
offset: vi.fn((n: number) => {
|
|
31
|
+
returnValue = returnValue.slice(n)
|
|
32
|
+
return builder
|
|
33
|
+
}),
|
|
34
|
+
returning: vi.fn(() => returnValue)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Make the builder thenable (for Promise support)
|
|
38
|
+
builder.then = (resolve: any) => resolve(returnValue)
|
|
39
|
+
|
|
40
|
+
return builder
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Create a mock database
|
|
45
|
+
*/
|
|
46
|
+
const createMockDb = (overrides: {
|
|
47
|
+
selectReturn?: unknown[]
|
|
48
|
+
insertReturn?: unknown[]
|
|
49
|
+
updateReturn?: unknown[]
|
|
50
|
+
deleteReturn?: unknown[]
|
|
51
|
+
} = {}) => {
|
|
52
|
+
const selectResult = overrides.selectReturn || []
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
select: vi.fn(() => ({
|
|
56
|
+
from: vi.fn(() => createQueryBuilder(selectResult))
|
|
57
|
+
})),
|
|
58
|
+
insert: vi.fn(() => ({
|
|
59
|
+
values: vi.fn(() => createQueryBuilder(overrides.insertReturn || []))
|
|
60
|
+
})),
|
|
61
|
+
update: vi.fn(() => ({
|
|
62
|
+
set: vi.fn(() => ({
|
|
63
|
+
where: vi.fn(() => createQueryBuilder(overrides.updateReturn || []))
|
|
64
|
+
}))
|
|
65
|
+
})),
|
|
66
|
+
delete: vi.fn(() => ({
|
|
67
|
+
where: vi.fn(() => createQueryBuilder(overrides.deleteReturn || []))
|
|
68
|
+
}))
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe('hooks execution', () => {
|
|
73
|
+
describe('create operations', () => {
|
|
74
|
+
it('executes hooks in correct order for create operation', async () => {
|
|
75
|
+
const executionOrder: string[] = []
|
|
76
|
+
|
|
77
|
+
const users = collection({
|
|
78
|
+
slug: 'users',
|
|
79
|
+
fields: {
|
|
80
|
+
name: field({ fieldType: f.text() }),
|
|
81
|
+
email: field({ fieldType: f.text() })
|
|
82
|
+
},
|
|
83
|
+
hooks: {
|
|
84
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
85
|
+
beforeCreate: [async () => { executionOrder.push('beforeCreate') }],
|
|
86
|
+
afterCreate: [async () => { executionOrder.push('afterCreate') }],
|
|
87
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const mockDb = createMockDb({
|
|
92
|
+
insertReturn: [{ id: 1, name: 'John', email: 'john@example.com' }]
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
96
|
+
|
|
97
|
+
await operations.create({
|
|
98
|
+
data: { name: 'John', email: 'john@example.com' },
|
|
99
|
+
returning: true
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
expect(executionOrder).toEqual([
|
|
103
|
+
'beforeOperation',
|
|
104
|
+
'beforeCreate',
|
|
105
|
+
'afterCreate',
|
|
106
|
+
'afterOperation'
|
|
107
|
+
])
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('passes correct context to beforeOperation hook on create', async () => {
|
|
111
|
+
let receivedContext: any = null
|
|
112
|
+
|
|
113
|
+
const users = collection({
|
|
114
|
+
slug: 'users',
|
|
115
|
+
fields: {
|
|
116
|
+
name: field({ fieldType: f.text() })
|
|
117
|
+
},
|
|
118
|
+
hooks: {
|
|
119
|
+
beforeOperation: [async (context) => { receivedContext = context }]
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
const mockDb = createMockDb({
|
|
124
|
+
insertReturn: [{ id: 1, name: 'John' }]
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
128
|
+
|
|
129
|
+
await operations.create({
|
|
130
|
+
data: { name: 'John' }
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
expect(receivedContext).toEqual({
|
|
134
|
+
collection: 'users',
|
|
135
|
+
operation: 'create',
|
|
136
|
+
data: { name: 'John' },
|
|
137
|
+
where: undefined
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('passes correct context to beforeCreate hook on create', async () => {
|
|
142
|
+
let receivedContext: any = null
|
|
143
|
+
|
|
144
|
+
const users = collection({
|
|
145
|
+
slug: 'users',
|
|
146
|
+
fields: {
|
|
147
|
+
name: field({ fieldType: f.text() })
|
|
148
|
+
},
|
|
149
|
+
hooks: {
|
|
150
|
+
beforeCreate: [async (context) => { receivedContext = context }]
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const mockDb = createMockDb({
|
|
155
|
+
insertReturn: [{ id: 1, name: 'John' }]
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
159
|
+
|
|
160
|
+
await operations.create({
|
|
161
|
+
data: { name: 'John' }
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
expect(receivedContext).toMatchObject({
|
|
165
|
+
collection: 'users',
|
|
166
|
+
operation: 'create',
|
|
167
|
+
data: { name: 'John' }
|
|
168
|
+
})
|
|
169
|
+
expect(receivedContext.db).toBeDefined()
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('passes correct context to afterCreate hook on create', async () => {
|
|
173
|
+
let receivedContext: any = null
|
|
174
|
+
|
|
175
|
+
const users = collection({
|
|
176
|
+
slug: 'users',
|
|
177
|
+
fields: {
|
|
178
|
+
name: field({ fieldType: f.text() })
|
|
179
|
+
},
|
|
180
|
+
hooks: {
|
|
181
|
+
afterCreate: [async (context) => { receivedContext = context }]
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const mockDb = createMockDb({
|
|
186
|
+
insertReturn: [{ id: 1, name: 'John' }]
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
190
|
+
|
|
191
|
+
await operations.create({
|
|
192
|
+
data: { name: 'John' },
|
|
193
|
+
returning: true
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
expect(receivedContext).toMatchObject({
|
|
197
|
+
collection: 'users',
|
|
198
|
+
operation: 'create',
|
|
199
|
+
data: { name: 'John' }
|
|
200
|
+
})
|
|
201
|
+
expect(receivedContext.result).toEqual({ id: 1, name: 'John' })
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('executes multiple hooks in order', async () => {
|
|
205
|
+
const executionOrder: string[] = []
|
|
206
|
+
|
|
207
|
+
const users = collection({
|
|
208
|
+
slug: 'users',
|
|
209
|
+
fields: {
|
|
210
|
+
name: field({ fieldType: f.text() })
|
|
211
|
+
},
|
|
212
|
+
hooks: {
|
|
213
|
+
beforeCreate: [
|
|
214
|
+
async () => { executionOrder.push('hook1') },
|
|
215
|
+
async () => { executionOrder.push('hook2') },
|
|
216
|
+
async () => { executionOrder.push('hook3') }
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const mockDb = createMockDb({
|
|
222
|
+
insertReturn: [{ id: 1, name: 'John' }]
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
226
|
+
|
|
227
|
+
await operations.create({
|
|
228
|
+
data: { name: 'John' }
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
expect(executionOrder).toEqual(['hook1', 'hook2', 'hook3'])
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('supports synchronous hooks', async () => {
|
|
235
|
+
let hookCalled = false
|
|
236
|
+
|
|
237
|
+
const users = collection({
|
|
238
|
+
slug: 'users',
|
|
239
|
+
fields: {
|
|
240
|
+
name: field({ fieldType: f.text() })
|
|
241
|
+
},
|
|
242
|
+
hooks: {
|
|
243
|
+
beforeCreate: [() => { hookCalled = true }]
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
const mockDb = createMockDb({
|
|
248
|
+
insertReturn: [{ id: 1, name: 'John' }]
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
252
|
+
|
|
253
|
+
await operations.create({
|
|
254
|
+
data: { name: 'John' }
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
expect(hookCalled).toBe(true)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
it('allows hooks to modify data before create', async () => {
|
|
261
|
+
let capturedData: any = null
|
|
262
|
+
|
|
263
|
+
const users = collection({
|
|
264
|
+
slug: 'users',
|
|
265
|
+
fields: {
|
|
266
|
+
name: field({ fieldType: f.text() }),
|
|
267
|
+
email: field({ fieldType: f.text() })
|
|
268
|
+
},
|
|
269
|
+
hooks: {
|
|
270
|
+
beforeCreate: [async (context) => {
|
|
271
|
+
context.data.email = 'modified@example.com'
|
|
272
|
+
capturedData = context.data
|
|
273
|
+
}]
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
const mockDb = createMockDb({
|
|
278
|
+
insertReturn: [{ id: 1, name: 'John', email: 'modified@example.com' }]
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
282
|
+
|
|
283
|
+
await operations.create({
|
|
284
|
+
data: { name: 'John', email: 'original@example.com' }
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
expect(capturedData.email).toBe('modified@example.com')
|
|
288
|
+
})
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
describe('update operations', () => {
|
|
292
|
+
it('executes hooks in correct order for update operation', async () => {
|
|
293
|
+
const executionOrder: string[] = []
|
|
294
|
+
|
|
295
|
+
const users = collection({
|
|
296
|
+
slug: 'users',
|
|
297
|
+
fields: {
|
|
298
|
+
name: field({ fieldType: f.text() })
|
|
299
|
+
},
|
|
300
|
+
hooks: {
|
|
301
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
302
|
+
beforeUpdate: [async () => { executionOrder.push('beforeUpdate') }],
|
|
303
|
+
afterUpdate: [async () => { executionOrder.push('afterUpdate') }],
|
|
304
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
305
|
+
}
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
const mockDb = createMockDb({
|
|
309
|
+
selectReturn: [{ id: 1, name: 'Old Name' }],
|
|
310
|
+
updateReturn: [{ id: 1, name: 'New Name' }]
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
314
|
+
|
|
315
|
+
await operations.update({
|
|
316
|
+
where: { id: 1 },
|
|
317
|
+
data: { name: 'New Name' },
|
|
318
|
+
returning: true
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
expect(executionOrder).toEqual([
|
|
322
|
+
'beforeOperation',
|
|
323
|
+
'beforeUpdate',
|
|
324
|
+
'afterUpdate',
|
|
325
|
+
'afterOperation'
|
|
326
|
+
])
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
it('passes previousData to beforeUpdate hook', async () => {
|
|
330
|
+
let receivedContext: any = null
|
|
331
|
+
|
|
332
|
+
const users = collection({
|
|
333
|
+
slug: 'users',
|
|
334
|
+
fields: {
|
|
335
|
+
name: field({ fieldType: f.text() })
|
|
336
|
+
},
|
|
337
|
+
hooks: {
|
|
338
|
+
beforeUpdate: [async (context) => { receivedContext = context }]
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
const mockDb = createMockDb({
|
|
343
|
+
selectReturn: [{ id: 1, name: 'Old Name' }],
|
|
344
|
+
updateReturn: [{ id: 1, name: 'New Name' }]
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
348
|
+
|
|
349
|
+
await operations.update({
|
|
350
|
+
where: { id: 1 },
|
|
351
|
+
data: { name: 'New Name' }
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
expect(receivedContext.previousData).toEqual({ id: 1, name: 'Old Name' })
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('passes previousData to afterUpdate hook', async () => {
|
|
358
|
+
let receivedContext: any = null
|
|
359
|
+
|
|
360
|
+
const users = collection({
|
|
361
|
+
slug: 'users',
|
|
362
|
+
fields: {
|
|
363
|
+
name: field({ fieldType: f.text() })
|
|
364
|
+
},
|
|
365
|
+
hooks: {
|
|
366
|
+
afterUpdate: [async (context) => { receivedContext = context }]
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
const mockDb = createMockDb({
|
|
371
|
+
selectReturn: [{ id: 1, name: 'Old Name' }],
|
|
372
|
+
updateReturn: [{ id: 1, name: 'New Name' }]
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
376
|
+
|
|
377
|
+
await operations.update({
|
|
378
|
+
where: { id: 1 },
|
|
379
|
+
data: { name: 'New Name' },
|
|
380
|
+
returning: true
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
expect(receivedContext.previousData).toEqual({ id: 1, name: 'Old Name' })
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('passes correct context to beforeOperation hook on update', async () => {
|
|
387
|
+
let receivedContext: any = null
|
|
388
|
+
|
|
389
|
+
const users = collection({
|
|
390
|
+
slug: 'users',
|
|
391
|
+
fields: {
|
|
392
|
+
name: field({ fieldType: f.text() })
|
|
393
|
+
},
|
|
394
|
+
hooks: {
|
|
395
|
+
beforeOperation: [async (context) => { receivedContext = context }]
|
|
396
|
+
}
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
const mockDb = createMockDb({
|
|
400
|
+
selectReturn: [{ id: 1, name: 'Old' }],
|
|
401
|
+
updateReturn: [{ id: 1, name: 'New' }]
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
405
|
+
|
|
406
|
+
await operations.update({
|
|
407
|
+
where: { id: 1 },
|
|
408
|
+
data: { name: 'New' }
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
expect(receivedContext).toEqual({
|
|
412
|
+
collection: 'users',
|
|
413
|
+
operation: 'update',
|
|
414
|
+
data: { name: 'New' },
|
|
415
|
+
where: { id: 1 }
|
|
416
|
+
})
|
|
417
|
+
})
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
describe('delete operations', () => {
|
|
421
|
+
it('executes hooks in correct order for delete operation', async () => {
|
|
422
|
+
const executionOrder: string[] = []
|
|
423
|
+
|
|
424
|
+
const users = collection({
|
|
425
|
+
slug: 'users',
|
|
426
|
+
fields: {
|
|
427
|
+
name: field({ fieldType: f.text() })
|
|
428
|
+
},
|
|
429
|
+
hooks: {
|
|
430
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
431
|
+
beforeDelete: [async () => { executionOrder.push('beforeDelete') }],
|
|
432
|
+
afterDelete: [async () => { executionOrder.push('afterDelete') }],
|
|
433
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
434
|
+
}
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
const mockDb = createMockDb({
|
|
438
|
+
selectReturn: [{ id: 1, name: 'John' }],
|
|
439
|
+
deleteReturn: [{ id: 1, name: 'John' }]
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
443
|
+
|
|
444
|
+
await operations.delete({
|
|
445
|
+
where: { id: 1 },
|
|
446
|
+
returning: true
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
expect(executionOrder).toEqual([
|
|
450
|
+
'beforeOperation',
|
|
451
|
+
'beforeDelete',
|
|
452
|
+
'afterDelete',
|
|
453
|
+
'afterOperation'
|
|
454
|
+
])
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
it('passes previousData to beforeDelete hook', async () => {
|
|
458
|
+
let receivedContext: any = null
|
|
459
|
+
|
|
460
|
+
const users = collection({
|
|
461
|
+
slug: 'users',
|
|
462
|
+
fields: {
|
|
463
|
+
name: field({ fieldType: f.text() })
|
|
464
|
+
},
|
|
465
|
+
hooks: {
|
|
466
|
+
beforeDelete: [async (context) => { receivedContext = context }]
|
|
467
|
+
}
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
const mockDb = createMockDb({
|
|
471
|
+
selectReturn: [{ id: 1, name: 'John' }],
|
|
472
|
+
deleteReturn: [{ id: 1, name: 'John' }]
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
476
|
+
|
|
477
|
+
await operations.delete({
|
|
478
|
+
where: { id: 1 }
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
expect(receivedContext.previousData).toEqual({ id: 1, name: 'John' })
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
it('passes previousData to afterDelete hook', async () => {
|
|
485
|
+
let receivedContext: any = null
|
|
486
|
+
|
|
487
|
+
const users = collection({
|
|
488
|
+
slug: 'users',
|
|
489
|
+
fields: {
|
|
490
|
+
name: field({ fieldType: f.text() })
|
|
491
|
+
},
|
|
492
|
+
hooks: {
|
|
493
|
+
afterDelete: [async (context) => { receivedContext = context }]
|
|
494
|
+
}
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
const mockDb = createMockDb({
|
|
498
|
+
selectReturn: [{ id: 1, name: 'John' }],
|
|
499
|
+
deleteReturn: [{ id: 1, name: 'John' }]
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
503
|
+
|
|
504
|
+
await operations.delete({
|
|
505
|
+
where: { id: 1 },
|
|
506
|
+
returning: true
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
expect(receivedContext.previousData).toEqual({ id: 1, name: 'John' })
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
it('passes correct context to beforeOperation hook on delete', async () => {
|
|
513
|
+
let receivedContext: any = null
|
|
514
|
+
|
|
515
|
+
const users = collection({
|
|
516
|
+
slug: 'users',
|
|
517
|
+
fields: {
|
|
518
|
+
name: field({ fieldType: f.text() })
|
|
519
|
+
},
|
|
520
|
+
hooks: {
|
|
521
|
+
beforeOperation: [async (context) => { receivedContext = context }]
|
|
522
|
+
}
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
const mockDb = createMockDb({
|
|
526
|
+
selectReturn: [{ id: 1, name: 'John' }],
|
|
527
|
+
deleteReturn: [{ id: 1, name: 'John' }]
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
531
|
+
|
|
532
|
+
await operations.delete({
|
|
533
|
+
where: { id: 1 }
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
expect(receivedContext).toEqual({
|
|
537
|
+
collection: 'users',
|
|
538
|
+
operation: 'delete',
|
|
539
|
+
where: { id: 1 },
|
|
540
|
+
data: undefined
|
|
541
|
+
})
|
|
542
|
+
})
|
|
543
|
+
})
|
|
544
|
+
|
|
545
|
+
describe('read operations', () => {
|
|
546
|
+
it('executes hooks in correct order for findMany operation', async () => {
|
|
547
|
+
const executionOrder: string[] = []
|
|
548
|
+
|
|
549
|
+
const users = collection({
|
|
550
|
+
slug: 'users',
|
|
551
|
+
fields: {
|
|
552
|
+
name: field({ fieldType: f.text() })
|
|
553
|
+
},
|
|
554
|
+
hooks: {
|
|
555
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
556
|
+
beforeRead: [async () => { executionOrder.push('beforeRead') }],
|
|
557
|
+
afterRead: [async () => { executionOrder.push('afterRead') }],
|
|
558
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
559
|
+
}
|
|
560
|
+
})
|
|
561
|
+
|
|
562
|
+
const mockDb = createMockDb({
|
|
563
|
+
selectReturn: [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
567
|
+
|
|
568
|
+
await operations.findMany()
|
|
569
|
+
|
|
570
|
+
expect(executionOrder).toEqual([
|
|
571
|
+
'beforeOperation',
|
|
572
|
+
'beforeRead',
|
|
573
|
+
'afterRead',
|
|
574
|
+
'afterOperation'
|
|
575
|
+
])
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
it('passes correct context to beforeOperation hook on read', async () => {
|
|
579
|
+
let receivedContext: any = null
|
|
580
|
+
|
|
581
|
+
const users = collection({
|
|
582
|
+
slug: 'users',
|
|
583
|
+
fields: {
|
|
584
|
+
name: field({ fieldType: f.text() })
|
|
585
|
+
},
|
|
586
|
+
hooks: {
|
|
587
|
+
beforeOperation: [async (context) => { receivedContext = context }]
|
|
588
|
+
}
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
const mockDb = createMockDb({
|
|
592
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
593
|
+
})
|
|
594
|
+
|
|
595
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
596
|
+
|
|
597
|
+
await operations.findMany({
|
|
598
|
+
where: { name: { contains: 'John' } }
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
expect(receivedContext).toEqual({
|
|
602
|
+
collection: 'users',
|
|
603
|
+
operation: 'read',
|
|
604
|
+
where: { name: { contains: 'John' } }
|
|
605
|
+
})
|
|
606
|
+
})
|
|
607
|
+
|
|
608
|
+
it('passes query to beforeRead hook', async () => {
|
|
609
|
+
let receivedContext: any = null
|
|
610
|
+
|
|
611
|
+
const users = collection({
|
|
612
|
+
slug: 'users',
|
|
613
|
+
fields: {
|
|
614
|
+
name: field({ fieldType: f.text() })
|
|
615
|
+
},
|
|
616
|
+
hooks: {
|
|
617
|
+
beforeRead: [async (context) => { receivedContext = context }]
|
|
618
|
+
}
|
|
619
|
+
})
|
|
620
|
+
|
|
621
|
+
const mockDb = createMockDb({
|
|
622
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
623
|
+
})
|
|
624
|
+
|
|
625
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
626
|
+
|
|
627
|
+
await operations.findMany({
|
|
628
|
+
where: { name: 'John' },
|
|
629
|
+
limit: 10,
|
|
630
|
+
offset: 5
|
|
631
|
+
})
|
|
632
|
+
|
|
633
|
+
expect(receivedContext.query).toMatchObject({
|
|
634
|
+
where: { name: 'John' },
|
|
635
|
+
limit: 10,
|
|
636
|
+
offset: 5
|
|
637
|
+
})
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
it('passes result to afterRead hook', async () => {
|
|
641
|
+
let receivedContext: any = null
|
|
642
|
+
|
|
643
|
+
const users = collection({
|
|
644
|
+
slug: 'users',
|
|
645
|
+
fields: {
|
|
646
|
+
name: field({ fieldType: f.text() })
|
|
647
|
+
},
|
|
648
|
+
hooks: {
|
|
649
|
+
afterRead: [async (context) => { receivedContext = context }]
|
|
650
|
+
}
|
|
651
|
+
})
|
|
652
|
+
|
|
653
|
+
const mockDb = createMockDb({
|
|
654
|
+
selectReturn: [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]
|
|
655
|
+
})
|
|
656
|
+
|
|
657
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
658
|
+
|
|
659
|
+
const result = await operations.findMany()
|
|
660
|
+
|
|
661
|
+
expect(receivedContext.result).toEqual([
|
|
662
|
+
{ id: 1, name: 'John' },
|
|
663
|
+
{ id: 2, name: 'Jane' }
|
|
664
|
+
])
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
it('executes hooks for findUnique operation', async () => {
|
|
668
|
+
const executionOrder: string[] = []
|
|
669
|
+
|
|
670
|
+
const users = collection({
|
|
671
|
+
slug: 'users',
|
|
672
|
+
fields: {
|
|
673
|
+
name: field({ fieldType: f.text() })
|
|
674
|
+
},
|
|
675
|
+
hooks: {
|
|
676
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
677
|
+
beforeRead: [async () => { executionOrder.push('beforeRead') }],
|
|
678
|
+
afterRead: [async () => { executionOrder.push('afterRead') }],
|
|
679
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
680
|
+
}
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
const mockDb = createMockDb({
|
|
684
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
688
|
+
|
|
689
|
+
await operations.findUnique({
|
|
690
|
+
where: { id: 1 }
|
|
691
|
+
})
|
|
692
|
+
|
|
693
|
+
expect(executionOrder).toEqual([
|
|
694
|
+
'beforeOperation',
|
|
695
|
+
'beforeRead',
|
|
696
|
+
'afterRead',
|
|
697
|
+
'afterOperation'
|
|
698
|
+
])
|
|
699
|
+
})
|
|
700
|
+
|
|
701
|
+
it('executes hooks for findFirst operation', async () => {
|
|
702
|
+
const executionOrder: string[] = []
|
|
703
|
+
|
|
704
|
+
const users = collection({
|
|
705
|
+
slug: 'users',
|
|
706
|
+
fields: {
|
|
707
|
+
name: field({ fieldType: f.text() })
|
|
708
|
+
},
|
|
709
|
+
hooks: {
|
|
710
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
711
|
+
beforeRead: [async () => { executionOrder.push('beforeRead') }],
|
|
712
|
+
afterRead: [async () => { executionOrder.push('afterRead') }],
|
|
713
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
714
|
+
}
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
const mockDb = createMockDb({
|
|
718
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
719
|
+
})
|
|
720
|
+
|
|
721
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
722
|
+
|
|
723
|
+
await operations.findFirst({
|
|
724
|
+
where: { name: 'John' }
|
|
725
|
+
})
|
|
726
|
+
|
|
727
|
+
expect(executionOrder).toEqual([
|
|
728
|
+
'beforeOperation',
|
|
729
|
+
'beforeRead',
|
|
730
|
+
'afterRead',
|
|
731
|
+
'afterOperation'
|
|
732
|
+
])
|
|
733
|
+
})
|
|
734
|
+
|
|
735
|
+
it('executes hooks for count operation', async () => {
|
|
736
|
+
const executionOrder: string[] = []
|
|
737
|
+
|
|
738
|
+
const users = collection({
|
|
739
|
+
slug: 'users',
|
|
740
|
+
fields: {
|
|
741
|
+
name: field({ fieldType: f.text() })
|
|
742
|
+
},
|
|
743
|
+
hooks: {
|
|
744
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
745
|
+
beforeRead: [async () => { executionOrder.push('beforeRead') }],
|
|
746
|
+
afterRead: [async () => { executionOrder.push('afterRead') }],
|
|
747
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
748
|
+
}
|
|
749
|
+
})
|
|
750
|
+
|
|
751
|
+
const mockDb = createMockDb({
|
|
752
|
+
selectReturn: [{ id: 1 }, { id: 2 }, { id: 3 }]
|
|
753
|
+
})
|
|
754
|
+
|
|
755
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
756
|
+
|
|
757
|
+
await operations.count()
|
|
758
|
+
|
|
759
|
+
expect(executionOrder).toEqual([
|
|
760
|
+
'beforeOperation',
|
|
761
|
+
'beforeRead',
|
|
762
|
+
'afterRead',
|
|
763
|
+
'afterOperation'
|
|
764
|
+
])
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
it('executes hooks for exists operation', async () => {
|
|
768
|
+
const executionOrder: string[] = []
|
|
769
|
+
|
|
770
|
+
const users = collection({
|
|
771
|
+
slug: 'users',
|
|
772
|
+
fields: {
|
|
773
|
+
name: field({ fieldType: f.text() })
|
|
774
|
+
},
|
|
775
|
+
hooks: {
|
|
776
|
+
beforeOperation: [async () => { executionOrder.push('beforeOperation') }],
|
|
777
|
+
beforeRead: [async () => { executionOrder.push('beforeRead') }],
|
|
778
|
+
afterRead: [async () => { executionOrder.push('afterRead') }],
|
|
779
|
+
afterOperation: [async () => { executionOrder.push('afterOperation') }]
|
|
780
|
+
}
|
|
781
|
+
})
|
|
782
|
+
|
|
783
|
+
const mockDb = createMockDb({
|
|
784
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
785
|
+
})
|
|
786
|
+
|
|
787
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
788
|
+
|
|
789
|
+
await operations.exists({
|
|
790
|
+
where: { id: 1 }
|
|
791
|
+
})
|
|
792
|
+
|
|
793
|
+
expect(executionOrder).toEqual([
|
|
794
|
+
'beforeOperation',
|
|
795
|
+
'beforeRead',
|
|
796
|
+
'afterRead',
|
|
797
|
+
'afterOperation'
|
|
798
|
+
])
|
|
799
|
+
})
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
describe('createMany operations', () => {
|
|
803
|
+
it('executes hooks for each item in createMany', async () => {
|
|
804
|
+
const executionOrder: string[] = []
|
|
805
|
+
|
|
806
|
+
const users = collection({
|
|
807
|
+
slug: 'users',
|
|
808
|
+
fields: {
|
|
809
|
+
name: field({ fieldType: f.text() })
|
|
810
|
+
},
|
|
811
|
+
hooks: {
|
|
812
|
+
beforeOperation: [async (context) => { executionOrder.push(`beforeOperation-${context.data.name}`) }],
|
|
813
|
+
beforeCreate: [async (context) => { executionOrder.push(`beforeCreate-${context.data.name}`) }],
|
|
814
|
+
afterCreate: [async (context) => { executionOrder.push(`afterCreate-${context.data.name}`) }],
|
|
815
|
+
afterOperation: [async (context) => { executionOrder.push(`afterOperation-${context.data.name}`) }]
|
|
816
|
+
}
|
|
817
|
+
})
|
|
818
|
+
|
|
819
|
+
const mockDb = createMockDb({
|
|
820
|
+
insertReturn: [
|
|
821
|
+
{ id: 1, name: 'John' },
|
|
822
|
+
{ id: 2, name: 'Jane' }
|
|
823
|
+
]
|
|
824
|
+
})
|
|
825
|
+
|
|
826
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
827
|
+
|
|
828
|
+
await operations.createMany({
|
|
829
|
+
data: [
|
|
830
|
+
{ name: 'John' },
|
|
831
|
+
{ name: 'Jane' }
|
|
832
|
+
]
|
|
833
|
+
})
|
|
834
|
+
|
|
835
|
+
expect(executionOrder).toEqual([
|
|
836
|
+
'beforeOperation-John',
|
|
837
|
+
'beforeCreate-John',
|
|
838
|
+
'beforeOperation-Jane',
|
|
839
|
+
'beforeCreate-Jane',
|
|
840
|
+
'afterCreate-John',
|
|
841
|
+
'afterOperation-John',
|
|
842
|
+
'afterCreate-Jane',
|
|
843
|
+
'afterOperation-Jane'
|
|
844
|
+
])
|
|
845
|
+
})
|
|
846
|
+
})
|
|
847
|
+
|
|
848
|
+
describe('updateMany operations', () => {
|
|
849
|
+
it('executes hooks for each item in updateMany', async () => {
|
|
850
|
+
const executionOrder: string[] = []
|
|
851
|
+
|
|
852
|
+
const users = collection({
|
|
853
|
+
slug: 'users',
|
|
854
|
+
fields: {
|
|
855
|
+
name: field({ fieldType: f.text() })
|
|
856
|
+
},
|
|
857
|
+
hooks: {
|
|
858
|
+
beforeUpdate: [async (context) => {
|
|
859
|
+
executionOrder.push(`beforeUpdate-${context.previousData?.name}`)
|
|
860
|
+
}],
|
|
861
|
+
afterUpdate: [async (context) => {
|
|
862
|
+
executionOrder.push(`afterUpdate-${context.previousData?.name}`)
|
|
863
|
+
}]
|
|
864
|
+
}
|
|
865
|
+
})
|
|
866
|
+
|
|
867
|
+
const mockDb = createMockDb({
|
|
868
|
+
selectReturn: [
|
|
869
|
+
{ id: 1, name: 'John' },
|
|
870
|
+
{ id: 2, name: 'Jane' }
|
|
871
|
+
]
|
|
872
|
+
})
|
|
873
|
+
|
|
874
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
875
|
+
|
|
876
|
+
await operations.updateMany({
|
|
877
|
+
where: { active: true },
|
|
878
|
+
data: { active: false }
|
|
879
|
+
})
|
|
880
|
+
|
|
881
|
+
expect(executionOrder).toEqual([
|
|
882
|
+
'beforeUpdate-John',
|
|
883
|
+
'beforeUpdate-Jane',
|
|
884
|
+
'afterUpdate-John',
|
|
885
|
+
'afterUpdate-Jane'
|
|
886
|
+
])
|
|
887
|
+
})
|
|
888
|
+
})
|
|
889
|
+
|
|
890
|
+
describe('deleteMany operations', () => {
|
|
891
|
+
it('executes hooks for each item in deleteMany', async () => {
|
|
892
|
+
const executionOrder: string[] = []
|
|
893
|
+
|
|
894
|
+
const users = collection({
|
|
895
|
+
slug: 'users',
|
|
896
|
+
fields: {
|
|
897
|
+
name: field({ fieldType: f.text() })
|
|
898
|
+
},
|
|
899
|
+
hooks: {
|
|
900
|
+
beforeDelete: [async (context) => {
|
|
901
|
+
executionOrder.push(`beforeDelete-${context.previousData?.name}`)
|
|
902
|
+
}],
|
|
903
|
+
afterDelete: [async (context) => {
|
|
904
|
+
executionOrder.push(`afterDelete-${context.previousData?.name}`)
|
|
905
|
+
}]
|
|
906
|
+
}
|
|
907
|
+
})
|
|
908
|
+
|
|
909
|
+
const mockDb = createMockDb({
|
|
910
|
+
selectReturn: [
|
|
911
|
+
{ id: 1, name: 'John' },
|
|
912
|
+
{ id: 2, name: 'Jane' }
|
|
913
|
+
]
|
|
914
|
+
})
|
|
915
|
+
|
|
916
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
917
|
+
|
|
918
|
+
await operations.deleteMany({
|
|
919
|
+
where: { active: false }
|
|
920
|
+
})
|
|
921
|
+
|
|
922
|
+
expect(executionOrder).toEqual([
|
|
923
|
+
'beforeDelete-John',
|
|
924
|
+
'beforeDelete-Jane',
|
|
925
|
+
'afterDelete-John',
|
|
926
|
+
'afterDelete-Jane'
|
|
927
|
+
])
|
|
928
|
+
})
|
|
929
|
+
})
|
|
930
|
+
|
|
931
|
+
describe('hooks without db', () => {
|
|
932
|
+
it('returns placeholder operations when db is not provided', async () => {
|
|
933
|
+
const users = collection({
|
|
934
|
+
slug: 'users',
|
|
935
|
+
fields: {
|
|
936
|
+
name: field({ fieldType: f.text() })
|
|
937
|
+
},
|
|
938
|
+
hooks: {
|
|
939
|
+
beforeCreate: [async () => { throw new Error('Should not be called') }]
|
|
940
|
+
}
|
|
941
|
+
})
|
|
942
|
+
|
|
943
|
+
const operations = createCollectionOperations(users, 'users', null, mockTable, users.hooks)
|
|
944
|
+
|
|
945
|
+
const result = await operations.findMany()
|
|
946
|
+
expect(result).toEqual([])
|
|
947
|
+
|
|
948
|
+
const unique = await operations.findUnique({ where: { id: 1 } })
|
|
949
|
+
expect(unique).toBeUndefined()
|
|
950
|
+
|
|
951
|
+
const created = await operations.create({ data: { name: 'John' } })
|
|
952
|
+
expect(created).toBeUndefined()
|
|
953
|
+
|
|
954
|
+
const count = await operations.count()
|
|
955
|
+
expect(count).toBe(0)
|
|
956
|
+
|
|
957
|
+
const exists = await operations.exists({ where: { id: 1 } })
|
|
958
|
+
expect(exists).toBe(false)
|
|
959
|
+
})
|
|
960
|
+
})
|
|
961
|
+
|
|
962
|
+
describe('error handling in hooks', () => {
|
|
963
|
+
it('throws error when beforeOperation hook throws', async () => {
|
|
964
|
+
const users = collection({
|
|
965
|
+
slug: 'users',
|
|
966
|
+
fields: {
|
|
967
|
+
name: field({ fieldType: f.text() })
|
|
968
|
+
},
|
|
969
|
+
hooks: {
|
|
970
|
+
beforeOperation: [async () => { throw new Error('Hook error') }]
|
|
971
|
+
}
|
|
972
|
+
})
|
|
973
|
+
|
|
974
|
+
const mockDb = createMockDb({
|
|
975
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
976
|
+
})
|
|
977
|
+
|
|
978
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
979
|
+
|
|
980
|
+
await expect(operations.findMany()).rejects.toThrow('Hook error')
|
|
981
|
+
})
|
|
982
|
+
|
|
983
|
+
it('throws error when beforeCreate hook throws', async () => {
|
|
984
|
+
const users = collection({
|
|
985
|
+
slug: 'users',
|
|
986
|
+
fields: {
|
|
987
|
+
name: field({ fieldType: f.text() })
|
|
988
|
+
},
|
|
989
|
+
hooks: {
|
|
990
|
+
beforeCreate: [async () => { throw new Error('Create hook error') }]
|
|
991
|
+
}
|
|
992
|
+
})
|
|
993
|
+
|
|
994
|
+
const mockDb = createMockDb({
|
|
995
|
+
insertReturn: [{ id: 1, name: 'John' }]
|
|
996
|
+
})
|
|
997
|
+
|
|
998
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
999
|
+
|
|
1000
|
+
await expect(operations.create({ data: { name: 'John' } })).rejects.toThrow('Create hook error')
|
|
1001
|
+
})
|
|
1002
|
+
|
|
1003
|
+
it('throws error when afterOperation hook throws', async () => {
|
|
1004
|
+
const users = collection({
|
|
1005
|
+
slug: 'users',
|
|
1006
|
+
fields: {
|
|
1007
|
+
name: field({ fieldType: f.text() })
|
|
1008
|
+
},
|
|
1009
|
+
hooks: {
|
|
1010
|
+
afterOperation: [async () => { throw new Error('After hook error') }]
|
|
1011
|
+
}
|
|
1012
|
+
})
|
|
1013
|
+
|
|
1014
|
+
const mockDb = createMockDb({
|
|
1015
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
1016
|
+
})
|
|
1017
|
+
|
|
1018
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
1019
|
+
|
|
1020
|
+
await expect(operations.findMany()).rejects.toThrow('After hook error')
|
|
1021
|
+
})
|
|
1022
|
+
})
|
|
1023
|
+
|
|
1024
|
+
describe('afterOperation hook context', () => {
|
|
1025
|
+
it('passes result to afterOperation hook on create', async () => {
|
|
1026
|
+
let receivedContext: any = null
|
|
1027
|
+
|
|
1028
|
+
const users = collection({
|
|
1029
|
+
slug: 'users',
|
|
1030
|
+
fields: {
|
|
1031
|
+
name: field({ fieldType: f.text() })
|
|
1032
|
+
},
|
|
1033
|
+
hooks: {
|
|
1034
|
+
afterOperation: [async (context) => { receivedContext = context }]
|
|
1035
|
+
}
|
|
1036
|
+
})
|
|
1037
|
+
|
|
1038
|
+
const mockDb = createMockDb({
|
|
1039
|
+
insertReturn: [{ id: 1, name: 'John' }]
|
|
1040
|
+
})
|
|
1041
|
+
|
|
1042
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
1043
|
+
|
|
1044
|
+
await operations.create({
|
|
1045
|
+
data: { name: 'John' },
|
|
1046
|
+
returning: true
|
|
1047
|
+
})
|
|
1048
|
+
|
|
1049
|
+
expect(receivedContext.result).toEqual({ id: 1, name: 'John' })
|
|
1050
|
+
})
|
|
1051
|
+
|
|
1052
|
+
it('passes result to afterOperation hook on read', async () => {
|
|
1053
|
+
let receivedContext: any = null
|
|
1054
|
+
|
|
1055
|
+
const users = collection({
|
|
1056
|
+
slug: 'users',
|
|
1057
|
+
fields: {
|
|
1058
|
+
name: field({ fieldType: f.text() })
|
|
1059
|
+
},
|
|
1060
|
+
hooks: {
|
|
1061
|
+
afterOperation: [async (context) => { receivedContext = context }]
|
|
1062
|
+
}
|
|
1063
|
+
})
|
|
1064
|
+
|
|
1065
|
+
const mockDb = createMockDb({
|
|
1066
|
+
selectReturn: [{ id: 1, name: 'John' }]
|
|
1067
|
+
})
|
|
1068
|
+
|
|
1069
|
+
const operations = createCollectionOperations(users, 'users', mockDb, mockTable, users.hooks)
|
|
1070
|
+
|
|
1071
|
+
await operations.findMany()
|
|
1072
|
+
|
|
1073
|
+
expect(receivedContext.result).toEqual([{ id: 1, name: 'John' }])
|
|
1074
|
+
})
|
|
1075
|
+
})
|
|
1076
|
+
})
|