-
-
Notifications
You must be signed in to change notification settings - Fork 92
/
find.js
50 lines (42 loc) · 1.81 KB
/
find.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import { CollectionHooks } from './collection-hooks'
const ASYNC_METHODS = ['countAsync', 'fetchAsync', 'forEachAsync', 'mapAsync']
/**
* With Meteor v3 this behaves differently than with Meteor v2.
* We cannot use async hooks on find() directly because in Meteor it is a sync method that returns cursor instance.
*
* That's why we need to wrap all async methods of cursor instance. We're doing this by creating another cursor
* within these wrapped methods with selector and options updated by before hooks.
*/
CollectionHooks.defineWrapper('find', function (userId, _super, instance, hooks, getTransform, args, suppressHooks) {
const selector = CollectionHooks.normalizeSelector(instance._getFindSelector(args))
const options = instance._getFindOptions(args)
// Apply synchronous before hooks
hooks.before.forEach(hook => {
if (!hook.hook.constructor.name.includes('Async')) {
hook.hook.call(this, userId, selector, options)
} else {
throw new Error('Cannot use async function as before.find hook')
}
})
const cursor = _super.call(this, selector, options)
// Wrap async cursor methods
ASYNC_METHODS.forEach((method) => {
if (cursor[method]) {
const originalMethod = cursor[method]
cursor[method] = async function (...args) {
// Do not try to apply asynchronous before hooks here because they act on the cursor which is already defined
const result = await originalMethod.apply(this, args)
// Apply after hooks
for (const hook of hooks.after) {
if (hook.hook.constructor.name.includes('Async')) {
await hook.hook.call(this, userId, selector, options, this)
} else {
hook.hook.call(this, userId, selector, options, this)
}
}
return result
}
}
})
return cursor
})