- commit
- e18a41f
- parent
- e0dffb4
- author
- Eric Bower
- date
- 2023-09-16 02:29:18 +0000 UTC
chore: export supervisors
3 files changed,
+87,
-2
+1,
-0
1@@ -4,3 +4,4 @@ export * from "./middleware.ts";
2 export * from "./types.ts";
3 export type { ActionWPayload, AnyAction, AnyState } from "../types.ts";
4 export { createSelector } from "../deps.ts";
5+export * from "./supervisor.ts";
+76,
-0
1@@ -0,0 +1,76 @@
2+import { call, race } from "../fx/mod.ts";
3+import { take, takeLatest, takeLeading } from "./fx.ts";
4+import { Operation, sleep, spawn, Task } from "../deps.ts";
5+import type { ActionWPayload, AnyAction, OpFn } from "../types.ts";
6+import type { CreateActionPayload } from "../query/mod.ts";
7+
8+const MS = 1000;
9+const SECONDS = 1 * MS;
10+const MINUTES = 60 * SECONDS;
11+
12+export function* latest(action: string, saga: any) {
13+ yield takeLatest(`${action}`, saga);
14+}
15+
16+export function* leading(action: string, saga: any) {
17+ yield takeLeading(`${action}`, saga);
18+}
19+
20+export function poll(parentTimer: number = 5 * 1000, cancelType?: string) {
21+ return function* poller<T>(
22+ actionType: string,
23+ op: (action: AnyAction) => Operation<T>,
24+ ): Operation<T> {
25+ const cancel = cancelType || actionType;
26+ function* fire(action: { type: string }, timer: number) {
27+ while (true) {
28+ yield* call(() => op(action));
29+ yield* sleep(timer);
30+ }
31+ }
32+
33+ while (true) {
34+ const action = yield* take<{ timer?: number }>(actionType);
35+ const timer = action.payload?.timer || parentTimer;
36+ yield* race({
37+ fire: () => call(() => fire(action, timer)),
38+ cancel: () => take(`${cancel}`),
39+ });
40+ }
41+ };
42+}
43+
44+/**
45+ * timer() will create a cache timer for each `key` inside
46+ * of a saga-query api endpoint. `key` is a hash of the action type and payload.
47+ *
48+ * Why do we want this? If we have an api endpoint to fetch a single app: `fetchApp({ id: 1 })`
49+ * if we don't set a timer per key then all calls to `fetchApp` will be on a timer.
50+ * So if we call `fetchApp({ id: 1 })` and then `fetchApp({ id: 2 })` if we use a normal
51+ * cache timer then the second call will not send an http request.
52+ */
53+export function timer(timer: number = 5 * MINUTES) {
54+ return function* onTimer(
55+ actionType: string,
56+ op: (action: AnyAction) => OpFn,
57+ ) {
58+ const map: { [key: string]: Task<unknown> } = {};
59+
60+ function* activate(action: ActionWPayload<CreateActionPayload>) {
61+ yield* call(() => op(action));
62+ yield* sleep(timer);
63+ delete map[action.payload.key];
64+ }
65+
66+ while (true) {
67+ const action = yield* take<CreateActionPayload>(`${actionType}`);
68+ const key = action.payload.key;
69+ if (!map[key]) {
70+ const task = yield* spawn(function* () {
71+ yield* activate(action);
72+ });
73+ map[key] = task;
74+ }
75+ }
76+ };
77+}
+10,
-2
1@@ -1,13 +1,21 @@
2 import { call, race } from "../fx/mod.ts";
3-import { take } from "../store/mod.ts";
4+import { take, takeLatest, takeLeading } from "./fx.ts";
5 import { Operation, sleep, spawn, Task } from "../deps.ts";
6 import type { ActionWPayload, AnyAction, OpFn } from "../types.ts";
7-import type { CreateActionPayload } from "../query/types.ts";
8+import type { CreateActionPayload } from "../query/mod.ts";
9
10 const MS = 1000;
11 const SECONDS = 1 * MS;
12 const MINUTES = 60 * SECONDS;
13
14+export function* latest(action: string, saga: any) {
15+ yield takeLatest(`${action}`, saga);
16+}
17+
18+export function* leading(action: string, saga: any) {
19+ yield takeLeading(`${action}`, saga);
20+}
21+
22 export function poll(parentTimer: number = 5 * 1000, cancelType?: string) {
23 return function* poller<T>(
24 actionType: string,