Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(client): Ensure
getDMMF
gets called only once (#14712)
Problem: when we have a freshly instantiated client (haven't done any queries yet) and we execute multiple queries at the same event loop tick, each one of them will start `getDMMF` request, which could be quite slow. Fixed by caching the results promise first time `getDMMF` is called and returning the same promise for subsequent calls. Fix #14695
- Loading branch information
Showing
4 changed files
with
54 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { callOnce } from './callOnce' | ||
|
||
test('returns the result correctly', async () => { | ||
const wrapper = callOnce(jest.fn().mockResolvedValue('hello')) | ||
await expect(wrapper()).resolves.toBe('hello') | ||
}) | ||
|
||
test('forwards the arguments correctly', async () => { | ||
const wrapper = callOnce((x: number) => Promise.resolve(x + 1)) | ||
await expect(wrapper(2)).resolves.toBe(3) | ||
}) | ||
|
||
test('сalls wrapped function only once before promise resolves', async () => { | ||
const wrapped = jest.fn().mockResolvedValue('hello') | ||
const wrapper = callOnce(wrapped) | ||
void wrapper() | ||
void wrapper() | ||
await wrapper() | ||
|
||
expect(wrapped).toBeCalledTimes(1) | ||
}) | ||
|
||
test('caches the result', async () => { | ||
const wrapped = jest.fn().mockResolvedValue('hello') | ||
const wrapper = callOnce(wrapped) | ||
await wrapper() | ||
await wrapper() | ||
const result = await wrapper() | ||
|
||
expect(wrapped).toBeCalledTimes(1) | ||
expect(result).toBe('hello') | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
type AsyncFn<Args extends unknown[], R> = (...args: Args) => Promise<R> | ||
|
||
/** | ||
* Takes an async function `fn` as a parameters and returns a wrapper function, which ensures | ||
* that `fn` will be called only once: | ||
* | ||
* - If the first call is not finished yet, returns the promise to the same result | ||
* - If the first call is finished, returns the result of this call | ||
* @param fn | ||
* @returns | ||
*/ | ||
export function callOnce<Args extends unknown[], R>(fn: AsyncFn<Args, R>): AsyncFn<Args, R> { | ||
let result: Promise<R> | undefined | ||
return (...args) => (result ??= fn(...args)) | ||
} |