diff --git a/.changeset/light-chefs-applaud.md b/.changeset/light-chefs-applaud.md new file mode 100644 index 000000000..acf642284 --- /dev/null +++ b/.changeset/light-chefs-applaud.md @@ -0,0 +1,5 @@ +--- +'@farfetched/core': patch +--- + +Support `enabled` in `keepFresh` diff --git a/apps/website/docs/api/operators/keep_fresh.md b/apps/website/docs/api/operators/keep_fresh.md index fae79fc53..615daa719 100644 --- a/apps/website/docs/api/operators/keep_fresh.md +++ b/apps/website/docs/api/operators/keep_fresh.md @@ -14,6 +14,7 @@ Config fields: - `automatically?`: _true_ to refresh the data in a [_Query_](/api/primitives/query) automatically if any [_Store_](https://effector.dev/docs/api/effector/store) that is used in the [_Query_](/api/primitives/query) creation is changed. - `triggers?`: _Array_ of [_Events_](https://effector.dev/docs/api/effector/event) after which operator starts refreshing the data in the [_Query_](/api/primitives/query). +- `enabled?`: [_Store_](https://effector.dev/docs/api/effector/store) with the current enabled state. Disabled _keepFresh_ will not execute queries, instead, they will be treated as skipped. Can be `true` or `false`. ```ts import { keepFresh } from '@farfetched/core'; diff --git a/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts b/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts index a4f895923..fc9ead679 100644 --- a/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts +++ b/packages/core/src/trigger_api/__test__/keep_fresh.test-d.ts @@ -1,4 +1,4 @@ -import { Event } from 'effector'; +import { createStore, Event } from 'effector'; import { describe, test } from 'vitest'; import { Query } from '../../query/type'; @@ -11,6 +11,13 @@ describe('keepFresh', () => { keepFresh(q, { automatically: true }); keepFresh(q, { triggers: [] }); keepFresh(q, { automatically: true, triggers: [] }); + keepFresh(q, { automatically: true, enabled: createStore(true) }); + keepFresh(q, { triggers: [], enabled: createStore(true) }); + keepFresh(q, { + automatically: true, + triggers: [], + enabled: createStore(true), + }); }); test('supports any Event as trigger', () => { diff --git a/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts b/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts index 32ca7773a..efe8368ad 100644 --- a/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts +++ b/packages/core/src/trigger_api/__test__/keep_fresh.triggers.test.ts @@ -214,4 +214,56 @@ describe('keepFresh, triggers as TriggerProtocol', () => { // 1 initial + 1 after enabling expect(setupListener).toBeCalledTimes(2); }); + + test('call teardown after config disabling and call start again after enabling', async () => { + const trigger = { + setup: createEvent(), + teardown: createEvent(), + fired: createEvent(), + }; + + const scope = fork(); + + const $enabled = createStore(true); + + const teardownListener = vi.fn(); + + createWatch({ + unit: trigger.teardown, + fn: teardownListener, + scope, + }); + + const setupListener = vi.fn(); + + createWatch({ + unit: trigger.setup, + fn: setupListener, + scope, + }); + + const query = createQuery({ + handler: vi.fn(), + }); + + keepFresh(query, { + enabled: $enabled, + triggers: [ + { + '@@trigger': () => trigger, + }, + ], + }); + + await allSettled(query.refresh, { scope }); + + await allSettled($enabled, { scope, params: false }); + + expect(teardownListener).toBeCalled(); + + await allSettled($enabled, { scope, params: true }); + + // 1 initial + 1 after enabling + expect(setupListener).toBeCalledTimes(2); + }); }); diff --git a/packages/core/src/trigger_api/keep_fresh.ts b/packages/core/src/trigger_api/keep_fresh.ts index 7b80cbb06..bb7f5edd9 100644 --- a/packages/core/src/trigger_api/keep_fresh.ts +++ b/packages/core/src/trigger_api/keep_fresh.ts @@ -5,6 +5,7 @@ import { sample, is, createStore, + Store, } from 'effector'; import { type Query } from '../query/type'; @@ -15,6 +16,7 @@ import { syncBatch, normalizeSourced, extractSource, + every, } from '../libs/patronus'; import { type TriggerProtocol } from './trigger_protocol'; @@ -22,6 +24,7 @@ export function keepFresh( query: Query, config: { automatically: true; + enabled?: Store; } ): void; @@ -29,6 +32,7 @@ export function keepFresh( query: Query, config: { triggers: Array | TriggerProtocol>; + enabled?: Store; } ): void; @@ -37,6 +41,7 @@ export function keepFresh( config: { automatically: true; triggers: Array | TriggerProtocol>; + enabled?: Store; } ): void; @@ -45,6 +50,7 @@ export function keepFresh( config: { automatically?: true; triggers?: Array | TriggerProtocol>; + enabled?: Store; } ): void { const triggers: Array> = []; @@ -56,6 +62,16 @@ export function keepFresh( triggers.push(...triggerEvents); + const enabledParamStores = [query.$enabled]; + if (config.enabled !== undefined) { + enabledParamStores.push(config.enabled); + } + + const $enabled = every({ + predicate: Boolean, + stores: enabledParamStores, + }); + if (protocolCompatibleObjects.length > 0) { const triggersByProtocol = protocolCompatibleObjects.map((trigger) => trigger['@@trigger']() @@ -71,15 +87,15 @@ export function keepFresh( sample({ clock: [ query.finished.success, - sample({ clock: query.$enabled.updates, filter: query.$enabled }), + sample({ clock: $enabled.updates, filter: $enabled }), ], filter: not($alreadySetup), target: [...triggersByProtocol.map(get('setup')), setup], }); sample({ - clock: query.$enabled.updates, - filter: and($alreadySetup, not(query.$enabled)), + clock: $enabled.updates, + filter: and($alreadySetup, not($enabled)), target: [...triggersByProtocol.map(get('teardown')), teardown], }); @@ -103,7 +119,7 @@ export function keepFresh( source: $partialSources, fn: (partialSources, clock) => partialSources.map((partialSource) => partialSource(clock)), - filter: query.$enabled, + filter: $enabled, target: $previousSources, }); @@ -124,17 +140,14 @@ export function keepFresh( triggers.push( sample({ - clock: [ - $nextSources.updates, - query.$enabled.updates.filter({ fn: Boolean }), - ], + clock: [$nextSources.updates, $enabled.updates.filter({ fn: Boolean })], source: [$nextSources, $previousSources] as const, filter: ([next, prev]) => !isEqual(next, prev), }) ); } - const forceFresh = sample({ clock: triggers, filter: query.$enabled }); + const forceFresh = sample({ clock: triggers, filter: $enabled }); sample({ clock: forceFresh,