Skip to content

Commit 40a30b6

Browse files
authored
feat: support undefined and null as find params to stop query (#34)
1 parent 2c996de commit 40a30b6

File tree

2 files changed

+187
-18
lines changed

2 files changed

+187
-18
lines changed

src/useFind.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ function loadServiceEventHandlers<
1010
M,
1111
>(
1212
service: FeathersService<CustomApplication, ServiceTypes<CustomApplication>[T]>,
13-
params: Ref<Params>,
13+
params: Ref<Params | undefined | null>,
1414
data: Ref<M[]>,
1515
): () => void {
1616
const onCreated = (item: M): void => {
17-
// ignore items which are not matching the query
18-
if (!sift(params.value.query)(item)) {
17+
// ignore items not matching the query or when no params are set
18+
if (!params.value || !sift(params.value.query)(item)) {
1919
return;
2020
}
2121

@@ -27,8 +27,8 @@ function loadServiceEventHandlers<
2727
};
2828

2929
const onItemChanged = (changedItem: M): void => {
30-
// ignore items not matching the query
31-
if (!sift(params.value.query)(changedItem)) {
30+
// ignore items not matching the query or when no params are set
31+
if (!params.value || !sift(params.value.query)(changedItem)) {
3232
// remove item from the list if they have been on it before
3333
data.value = data.value.filter((item) => getId(item) !== getId(changedItem));
3434
return;
@@ -77,13 +77,13 @@ export type UseFindFunc<CustomApplication> = <
7777
M = ServiceModel<CustomApplication, T>,
7878
>(
7979
serviceName: T,
80-
params?: Ref<Params>,
80+
params?: Ref<Params | undefined | null>,
8181
) => UseFind<M>;
8282

8383
export default <CustomApplication extends Application>(feathers: CustomApplication) =>
8484
<T extends keyof ServiceTypes<CustomApplication>, M = ServiceModel<CustomApplication, T>>(
8585
serviceName: T,
86-
params: Ref<Params> = ref({ paginate: false, query: {} }),
86+
params: Ref<Params | undefined | null> = ref({ paginate: false, query: {} }),
8787
{ disableUnloadingEventHandlers } = { disableUnloadingEventHandlers: false },
8888
): UseFind<M> => {
8989
// type cast is fine here (source: https://github.com/vuejs/vue-next/issues/2136#issuecomment-693524663)
@@ -95,19 +95,22 @@ export default <CustomApplication extends Application>(feathers: CustomApplicati
9595

9696
const find = async () => {
9797
isLoading.value = true;
98+
if (!params.value) {
99+
data.value = [];
100+
isLoading.value = false;
101+
return;
102+
}
103+
98104
// TODO: the typecast below is necessary due to the prerelease state of feathers v5. The problem there is
99105
// that the AdapterService interface is not yet updated and is not compatible with the ServiceMethods interface.
100106
const res = await (service as unknown as ServiceMethods<M>).find(params.value);
101107
data.value = Array.isArray(res) ? res : [res];
102108
isLoading.value = false;
103109
};
104110

105-
watch(
106-
() => params.value.query,
107-
() => {
108-
void find();
109-
},
110-
);
111+
watch(params, () => {
112+
void find();
113+
});
111114

112115
const connectListener = () => {
113116
void find();

test/useFind.test.ts

Lines changed: 171 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Application } from '@feathersjs/feathers';
1+
import { Application, Params } from '@feathersjs/feathers';
22
import { nextTick, ref } from 'vue';
33

44
import useFindOriginal, { UseFind } from '~/useFind';
@@ -142,11 +142,16 @@ describe('Find composition', () => {
142142
});
143143

144144
it('should reload data after changing the params', async () => {
145-
expect.assertions(2);
145+
expect.assertions(3);
146146

147147
// given
148148
const findParams = ref({ query: { zug: 'start' } });
149-
const serviceFind = jest.fn(() => Promise.resolve([]));
149+
const serviceFind = jest.fn((params: Params) => {
150+
if (params.query && params.query.zug === 'start') {
151+
return [additionalTestModel];
152+
}
153+
return [testModel];
154+
});
150155
const feathersMock = {
151156
service: () => ({
152157
find: serviceFind,
@@ -157,12 +162,17 @@ describe('Find composition', () => {
157162
off: jest.fn(),
158163
} as unknown as Application;
159164
const useFind = useFindOriginal(feathersMock);
165+
let findComposition = null as UseFind<TestModel> | null;
160166
mountComposition(() => {
161-
useFind('testModels', findParams);
167+
findComposition = useFind('testModels', findParams);
162168
});
163169

170+
// before then to ensure that the previous loading procedure is completed
171+
await nextTick();
172+
expect(findComposition && findComposition.data.value).toStrictEqual([additionalTestModel]);
173+
164174
// when
165-
findParams.value.query = { zug: 'change' };
175+
findParams.value = { query: { zug: 'change' } };
166176
await nextTick();
167177

168178
// then
@@ -175,6 +185,162 @@ describe('Find composition', () => {
175185
);
176186
});
177187

188+
it('should un-load data after params changes to ref of undefined', async () => {
189+
expect.assertions(5);
190+
191+
// given
192+
const findParams = ref<Params | undefined>({ query: { zug: 'start' } });
193+
const serviceFind = jest.fn(() => Promise.resolve([testModel]));
194+
const feathersMock = {
195+
service: () => ({
196+
find: serviceFind,
197+
on: jest.fn(),
198+
off: jest.fn(),
199+
}),
200+
on: jest.fn(),
201+
off: jest.fn(),
202+
} as unknown as Application;
203+
const useFind = useFindOriginal(feathersMock);
204+
let findComposition = null as UseFind<TestModel> | null;
205+
mountComposition(() => {
206+
findComposition = useFind('testModels', findParams);
207+
});
208+
209+
// before then to ensure that the previous loading procedure is completed
210+
await nextTick();
211+
expect(findComposition && findComposition.data.value).toStrictEqual([testModel]);
212+
213+
// when
214+
findParams.value = undefined;
215+
await nextTick();
216+
217+
// then
218+
expect(serviceFind).toHaveBeenCalledTimes(1);
219+
expect(findComposition).toBeTruthy();
220+
expect(findComposition && findComposition.isLoading.value).toBeFalsy();
221+
expect(findComposition && findComposition.data.value).toStrictEqual([]);
222+
});
223+
224+
it('should un-load data after params changes to ref of null', async () => {
225+
expect.assertions(5);
226+
227+
// given
228+
const findParams = ref<Params | null>({ query: { zug: 'start' } });
229+
const serviceFind = jest.fn(() => Promise.resolve([testModel]));
230+
const feathersMock = {
231+
service: () => ({
232+
find: serviceFind,
233+
on: jest.fn(),
234+
off: jest.fn(),
235+
}),
236+
on: jest.fn(),
237+
off: jest.fn(),
238+
} as unknown as Application;
239+
const useFind = useFindOriginal(feathersMock);
240+
let findComposition = null as UseFind<TestModel> | null;
241+
mountComposition(() => {
242+
findComposition = useFind('testModels', findParams);
243+
});
244+
245+
// before then to ensure that the previous loading procedure is completed
246+
await nextTick();
247+
expect(findComposition && findComposition.data.value).toStrictEqual([testModel]);
248+
249+
// when
250+
findParams.value = null;
251+
await nextTick();
252+
253+
// then
254+
expect(serviceFind).toHaveBeenCalledTimes(1);
255+
expect(findComposition).toBeTruthy();
256+
expect(findComposition && findComposition.isLoading.value).toBeFalsy();
257+
expect(findComposition && findComposition.data.value).toStrictEqual([]);
258+
});
259+
260+
it('should return empty data when params is ref of undefined and load data after changing to valid params', async () => {
261+
expect.assertions(6);
262+
263+
// given
264+
const findParams = ref<Params | undefined>();
265+
const serviceFind = jest.fn((params: Params) => {
266+
if (params.query && params.query.zug === 'start') {
267+
return [additionalTestModel];
268+
}
269+
return [testModel];
270+
});
271+
const feathersMock = {
272+
service: () => ({
273+
find: serviceFind,
274+
on: jest.fn(),
275+
off: jest.fn(),
276+
}),
277+
on: jest.fn(),
278+
off: jest.fn(),
279+
} as unknown as Application;
280+
const useFind = useFindOriginal(feathersMock);
281+
let findComposition = null as UseFind<TestModel> | null;
282+
mountComposition(() => {
283+
findComposition = useFind('testModels', findParams);
284+
});
285+
286+
// before then to ensure that the previous loading procedure is completed
287+
await nextTick();
288+
expect(findComposition && findComposition.isLoading.value).toBeFalsy();
289+
expect(findComposition && findComposition.data.value).toStrictEqual([]);
290+
291+
// when
292+
findParams.value = { query: { zug: 'start' } };
293+
await nextTick();
294+
295+
// then
296+
expect(serviceFind).toHaveBeenCalledTimes(1);
297+
expect(findComposition).toBeTruthy();
298+
expect(findComposition && findComposition.isLoading.value).toBeFalsy();
299+
expect(findComposition && findComposition.data.value).toStrictEqual([additionalTestModel]);
300+
});
301+
302+
it('should return empty data when params is ref of null and load data after changing to valid params', async () => {
303+
expect.assertions(6);
304+
305+
// given
306+
const findParams = ref<Params | null>(null);
307+
const serviceFind = jest.fn((params: Params) => {
308+
if (params.query && params.query.zug === 'start') {
309+
return [additionalTestModel];
310+
}
311+
return [testModel];
312+
});
313+
const feathersMock = {
314+
service: () => ({
315+
find: serviceFind,
316+
on: jest.fn(),
317+
off: jest.fn(),
318+
}),
319+
on: jest.fn(),
320+
off: jest.fn(),
321+
} as unknown as Application;
322+
const useFind = useFindOriginal(feathersMock);
323+
let findComposition = null as UseFind<TestModel> | null;
324+
mountComposition(() => {
325+
findComposition = useFind('testModels', findParams);
326+
});
327+
328+
// before then to ensure that the previous loading procedure is completed
329+
await nextTick();
330+
expect(findComposition && findComposition.isLoading.value).toBeFalsy();
331+
expect(findComposition && findComposition.data.value).toStrictEqual([]);
332+
333+
// when
334+
findParams.value = { query: { zug: 'start' } };
335+
await nextTick();
336+
337+
// then
338+
expect(serviceFind).toHaveBeenCalledTimes(1);
339+
expect(findComposition).toBeTruthy();
340+
expect(findComposition && findComposition.isLoading.value).toBeFalsy();
341+
expect(findComposition && findComposition.data.value).toStrictEqual([additionalTestModel]);
342+
});
343+
178344
describe('Event Handlers', () => {
179345
it('should listen to "create" events', () => {
180346
expect.assertions(2);

0 commit comments

Comments
 (0)