Skip to content

Commit

Permalink
fix(utils/query): Add try-catch block to handle exceptions in query f…
Browse files Browse the repository at this point in the history
…unction execution

The try-catch block is added to the execution of the query function in order to handle exceptions that might occur before returning the observable. This ensures that any errors thrown during the execution are caught and properly handled, preventing the process from terminating prematurely.

Updated test-case to validate exceptions in query client
  • Loading branch information
odinr committed Aug 27, 2024
1 parent 00d5e9c commit be2e925
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 24 deletions.
25 changes: 25 additions & 0 deletions .changeset/curly-roses-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
'@equinor/fusion-query': patch
---

Added try catch block to execution of query function, since the method might throw an exception before returning the observable.

```ts
const queryClient = new Query({
client: {
() => {
throw new Error('this would terminate the process before');
return new Observable((subscriber) => {
throw new Error('this worked before');
});
},
},
key: (value) => value,

queryClient.query().subscribe({
error: (error) => {
// before changes this would not be called since stream would be terminated.
console.log(error.message); // this would print 'this would terminate the process before'
},
});
```
32 changes: 19 additions & 13 deletions packages/utils/query/src/client/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,25 @@ export const handleExecution =
}),
);

// Execute the fetch operation, passing the AbortSignal to allow for cancellation.
return from(fetch(request.args, controller.signal)).pipe(
map((value) =>
actions.execute.success({
...request,
status: 'complete',
completed: Date.now(),
value,
}),
),
catchError((err) => of(actions.execute.failure(err, transaction))),
takeUntil(cancel$), // Complete the observable chain if a cancel action is received.
);
try {
return from(fetch(request.args, controller.signal)).pipe(
map((value) =>
actions.execute.success({
...request,
status: 'complete',
completed: Date.now(),
value,
}),
),
catchError((err) => of(actions.execute.failure(err, transaction))),
takeUntil(cancel$), // Complete the observable chain if a cancel action is received.
);
} catch (err) {
// Normally errors thrown during the execution of the fetch function are caught by the `catchError` operator.
// However, if the fetch function itself throws an error, it will be caught here.
// This can happen if the fetch function is not a function or if it throws synchronously.
return of(actions.execute.failure(err as Error, transaction));
}
}),
);

Expand Down
21 changes: 10 additions & 11 deletions packages/utils/query/tests/Query.query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ describe('Query query', () => {

it('should handle errors', async () => {
// Mock a function that always throws an error when called
const fn = vi.fn(async (_: string) => {
throw Error('error');
const fn = vi.fn((arg: string) => {
if (fn.mock.calls.length === 1) {
throw Error('error');
}
return Promise.resolve(arg);
});
// Initialize the Query client with the mocked function that throws an error
const queryClient = new Query({
Expand All @@ -68,15 +71,11 @@ describe('Query query', () => {
},
key: (value) => value, // Use the input value as the query key
});
try {
// Attempt to perform a query that is expected to fail
await lastValueFrom(queryClient.query('foo'));
} catch (e) {
// Verify that the caught exception is an instance of Error
expect(e).toBeInstanceOf(Error);
// Verify that the error message is what was thrown by the mocked function
expect(e.message).toBe('error');
}

await expect(lastValueFrom(queryClient.query('foo'))).rejects.toThrowError('error');
await expect(lastValueFrom(queryClient.query('foo'))).resolves.toMatchObject({
value: 'foo',
});
});

it('should cancel requests when no longer subscribed', async () => {
Expand Down

0 comments on commit be2e925

Please sign in to comment.