Skip to content

Commit

Permalink
update and _Query_ with initial data (#375)
Browse files Browse the repository at this point in the history
* Add test cases and fix bug

* Add one more type test and fix introduced bug

* Add missed params

* Fix incorrect import

* TS ignores

* Add more tests and fix bugs about it

* Support _Query_ with initial data in `update` operator types

* Remove unused import
  • Loading branch information
igorkamyshev committed Sep 29, 2023
1 parent 102790c commit e8a1385
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/wild-ears-kneel.md
@@ -0,0 +1,5 @@
---
'@farfetched/core': patch
---

Support _Query_ with initial data in `update` operator types
80 changes: 80 additions & 0 deletions packages/core/src/update/__tests__/update.test-d.ts
@@ -0,0 +1,80 @@
import { type Effect } from 'effector';
import { expectTypeOf } from 'vitest';

import { createMutation } from '../../mutation/create_mutation';
import { createQuery } from '../../query/create_query';
import { update } from '../update';

describe('update', () => {
test('use null if initial data type is not provided, issue #370', () => {
const queryFx: Effect<void, number[]> = {} as any;
const mutationFx: Effect<number, number> = {} as any;

const query = createQuery({
effect: queryFx,
});

const mutation = createMutation({
effect: mutationFx,
});

update(query, {
on: mutation,
by: {
success: ({ query }) => {
expectTypeOf(query).toMatchTypeOf<
| {
result: number[];
params: void;
}
| {
error: Error;
params: void;
}
| null
>();

return {
result: [],
};
},
},
});
});

test('use initial data type in case of not started query, issue #370', () => {
const queryFx: Effect<void, number[]> = {} as any;
const mutationFx: Effect<number, number> = {} as any;

const query = createQuery({
effect: queryFx,
initialData: [],
});

const mutation = createMutation({
effect: mutationFx,
});

update(query, {
on: mutation,
by: {
success: ({ query }) => {
expectTypeOf(query).toMatchTypeOf<
| {
result: number[];
params: void;
}
| {
error: Error;
params: void;
}
| { result: number[] }
>();
return {
result: [],
};
},
},
});
});
});
32 changes: 32 additions & 0 deletions packages/core/src/update/__tests__/update.test.ts
Expand Up @@ -420,4 +420,36 @@ describe('update', () => {
})
);
});

test('use initial data type in case of not started query, issue #370', async () => {
const queryHandler = vi.fn(async (p: string) => [1, Number(p)]);
const mutationHandler = vi.fn(async (x: number) => x);

const query = createQuery({
handler: queryHandler,
initialData: [1],
});

const mutation = createMutation({
handler: mutationHandler,
});

const successHandler = vi.fn(() => ({ result: [], refetch: true }));

update(query, {
on: mutation,
by: {
success: successHandler,
},
});

const scope = fork();

await allSettled(mutation.start, { scope, params: 10 });

expect(queryHandler).not.toBeCalled();
expect(successHandler).toBeCalledWith(
expect.objectContaining({ query: { result: [1] } })
);
});
});
30 changes: 23 additions & 7 deletions packages/core/src/update/update.ts
Expand Up @@ -13,7 +13,7 @@ import {
normalizeSourced,
} from '../libs/patronus';
import { type Mutation } from '../mutation/type';
import { type Query } from '../query/type';
import { type QueryInitialData, type Query } from '../query/type';
import {
type RemoteOperationError,
type RemoteOperationParams,
Expand All @@ -29,7 +29,7 @@ type QueryState<Q extends Query<any, any, any, any>> =
error: RemoteOperationError<Q>;
params: RemoteOperationParams<Q>;
}
| null;
| (QueryInitialData<Q> extends null ? null : { result: QueryInitialData<Q> });

type Refetch<Q extends Query<any, any, any, any>> =
| boolean
Expand Down Expand Up @@ -161,11 +161,15 @@ export function update<
sample({
clock: shouldRefetch,
source: $queryState,
filter: (state, refetch) =>
(typeof refetch === 'object' && 'params' in refetch) ||
(state && 'params' in state),
fn: (state, refetch) => {
if (typeof refetch === 'object' && 'params' in refetch) {
return { params: refetch.params, refresh: true };
}

// @ts-expect-error I do not want to fight with TS here
return { params: state?.params, refresh: true };
},
target: [query.__.lowLevelAPI.revalidate, query.$stale.reinit!],
Expand All @@ -174,8 +178,11 @@ export function update<
sample({
clock: shouldNotRefetch,
source: $queryState,
filter: Boolean,
fn: (state) => ({ params: state.params, refresh: false }),
filter: (state) => state && 'params' in state,
fn: (state: any): { params: any; refresh: false } => ({
params: state.params,
refresh: false,
}),
target: query.__.lowLevelAPI.revalidate,
});
}
Expand All @@ -185,17 +192,26 @@ function queryState<Q extends Query<any, any, any, any>>(
): Store<QueryState<Q>> {
return combine(
{
idle: query.$idle,
result: query.$data,
params: query.__.$latestParams,
error: query.$error,
failed: query.$failed,
},
({ result, params, error, failed }): QueryState<Q> => {
if (!result && !error) {
({ idle, result, params, error, failed }): any => {
if (result == null && error == null) {
return null;
}

return failed ? { error, params: params! } : { result, params: params! };
if (idle) {
return { result };
}

if (failed) {
return { error, params };
}

return { result, params };
}
);
}

0 comments on commit e8a1385

Please sign in to comment.