-
Notifications
You must be signed in to change notification settings - Fork 132
/
Copy pathwith-filter.ts
72 lines (63 loc) · 2.57 KB
/
with-filter.ts
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
export type FilterFn<TSource = any, TArgs = any, TContext = any> = (rootValue?: TSource, args?: TArgs, context?: TContext, info?: any) => boolean | Promise<boolean>;
export type ResolverFn<TSource = any, TArgs = any, TContext = any> = (rootValue?: TSource, args?: TArgs, context?: TContext, info?: any) => AsyncIterator<any> | Promise<AsyncIterator<any>>;
export type IterableResolverFn<TSource = any, TArgs = any, TContext = any> = (rootValue?: TSource, args?: TArgs, context?: TContext, info?: any) => AsyncIterableIterator<any> | Promise<AsyncIterableIterator<any>>;
interface IterallAsyncIterator<T> extends AsyncIterableIterator<T> {
[Symbol.asyncIterator](): IterallAsyncIterator<T>;
}
export type WithFilter<TSource = any, TArgs = any, TContext = any> = (
asyncIteratorFn: ResolverFn<TSource, TArgs, TContext>,
filterFn: FilterFn<TSource, TArgs, TContext>
) => IterableResolverFn<TSource, TArgs, TContext>;
export function withFilter<TSource = any, TArgs = any, TContext = any>(
asyncIteratorFn: ResolverFn<TSource, TArgs, TContext>,
filterFn: FilterFn<TSource, TArgs, TContext>
): IterableResolverFn<TSource, TArgs, TContext> {
return async (rootValue: TSource, args: TArgs, context: TContext, info: any): Promise<IterallAsyncIterator<any>> => {
const asyncIterator = await asyncIteratorFn(rootValue, args, context, info);
const getNextPromise = () => {
return new Promise<IteratorResult<any>>((resolve, reject) => {
const inner = () => {
asyncIterator
.next()
.then(payload => {
if (payload.done === true) {
resolve(payload);
return;
}
Promise.resolve(filterFn(payload.value, args, context, info))
.catch(() => false) // We ignore errors from filter function
.then(filterResult => {
if (filterResult === true) {
resolve(payload);
return;
}
// Skip the current value and wait for the next one
inner();
return;
});
})
.catch((err) => {
reject(err);
return;
});
};
inner();
});
};
const asyncIterator2 = {
next() {
return getNextPromise();
},
return() {
return asyncIterator.return();
},
throw(error) {
return asyncIterator.throw(error);
},
[Symbol.asyncIterator]() {
return this;
},
};
return asyncIterator2;
};
};