Skip to content

Commit

Permalink
chore: address feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
israx committed Jan 17, 2024
1 parent b46967d commit 4ce72c3
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 60 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"tslint-config-airbnb": "^5.8.0",
"typedoc": "^0.17.0",
"typescript": "^4.3.5",
"typescript-coverage-report": "^0.8.0",
"typescript-coverage-report": "^0.6.4",
"uuid-validate": "^0.0.3",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.7.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { AuthConfig } from '@aws-amplify/core';
import {
assertTokenProviderConfig,
decodeJWT,
deDupeAsyncRequests,
deDupeAsyncFunction,
} from '@aws-amplify/core/internals/utils';
import { initiateAuth } from '../utils/clients/CognitoIdentityProvider';
import { getRegion } from '../utils/clients/CognitoIdentityProvider/utils';
import { assertAuthTokensWithRefreshToken } from '../utils/types';
import { AuthError } from '../../../errors/AuthError';
import { getUserContextData } from './userContextData';

const refreshAuthTokensCallback: TokenRefresher = async ({
const refreshAuthTokensFunction: TokenRefresher = async ({
tokens,
authConfig,
username,
Expand Down Expand Up @@ -74,4 +74,4 @@ const refreshAuthTokensCallback: TokenRefresher = async ({
};
};

export const refreshAuthTokens = deDupeAsyncRequests(refreshAuthTokensCallback);
export const refreshAuthTokens = deDupeAsyncFunction(refreshAuthTokensFunction);
56 changes: 28 additions & 28 deletions packages/core/__tests__/utils/deDupeAsyncRequests.test.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
import { deDupeAsyncRequests } from '../../src/utils/deDupeAsyncRequests';
import { deDupeAsyncFunction } from '../../src/utils/deDupeAsyncFunction';

describe('test debounce callback', () => {
describe('dedupeAsyncFunction()', () => {
const numberOfConcurrentCalls = 10;
const mockServiceCallback = jest.fn();
const mockServiceFunction = jest.fn();
const mockReturnValue = { id: 1 };

beforeEach(() => {
mockServiceCallback.mockImplementation(async () => {});
mockServiceFunction.mockImplementation(async () => mockReturnValue);
});
afterEach(() => {
mockServiceCallback.mockClear();
mockServiceFunction.mockClear();
});

it('should allow to invoke the callback when there is no concurrent calls', async () => {
const debouncedCallback = deDupeAsyncRequests(mockServiceCallback);
it('should invoke the mockServiceFunction', async () => {
const deDupedFunction = deDupeAsyncFunction(mockServiceFunction);

debouncedCallback();
expect(mockServiceCallback).toHaveBeenCalledTimes(1);
deDupedFunction();
expect(mockServiceFunction).toHaveBeenCalledTimes(1);
});

it('should invoke the callback one time during concurrent sync calls', () => {
const debouncedCallback = deDupeAsyncRequests(mockServiceCallback);
it('should invoke the mockServiceFunction one time during concurrent sync calls', () => {
const deDupedFunction = deDupeAsyncFunction(mockServiceFunction);
for (let i = 0; i < numberOfConcurrentCalls; i++) {
debouncedCallback();
deDupedFunction();
}
expect(mockServiceCallback).toHaveBeenCalledTimes(1);
expect(mockServiceFunction).toHaveBeenCalledTimes(1);
});

it('should allow to invoke the callback again after the promise has being resolved', async () => {
const debouncedCallback = deDupeAsyncRequests(mockServiceCallback);
it('should return a value once the mockServiceFunction is resolved', async () => {
const deDupedFunction = deDupeAsyncFunction(mockServiceFunction);
expect(await deDupedFunction()).toEqual(mockReturnValue);
expect(mockServiceFunction).toHaveBeenCalledTimes(1);
});

it('should allow to invoke the mockServiceFunction again after the promise has being resolved', async () => {
const deDupedFunction = deDupeAsyncFunction(mockServiceFunction);
for (let i = 0; i < numberOfConcurrentCalls; i++) {
debouncedCallback();
expect(deDupedFunction()).toBeInstanceOf(Promise);
}

await debouncedCallback();
// resolves the promise
expect(await deDupedFunction()).toEqual(mockReturnValue);

debouncedCallback();
expect(mockServiceCallback).toHaveBeenCalledTimes(2);
});
// should allow to call the mockServiceFunction again
deDupedFunction();

it('should return a value once the callback is resolved', async () => {
const mockReturnValue = { id: 1 };

mockServiceCallback.mockImplementation(async () => mockReturnValue);
const debouncedCallback = deDupeAsyncRequests(mockServiceCallback);
const result = await debouncedCallback();
expect(result).toEqual(mockReturnValue);
expect(mockServiceCallback).toHaveBeenCalledTimes(1);
expect(mockServiceFunction).toHaveBeenCalledTimes(2);
});
});
2 changes: 1 addition & 1 deletion packages/core/src/libraryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export {
retry,
urlSafeDecode,
urlSafeEncode,
deDupeAsyncRequests,
deDupeAsyncFunction,
} from './utils';
export { parseAWSExports } from './parseAWSExports';
export { LegacyConfig } from './singleton/types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// this will make the tsc-complience-test to pass
// this will make the tsc-compliance-test to pass
type Awaited<T> = T extends null | undefined
? T // special case for `null | undefined` when not in `--strictNullChecks` mode
: T extends object & { then(onfulfilled: infer F, ...args: infer _): any } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
Expand All @@ -10,33 +10,29 @@ type Awaited<T> = T extends null | undefined
: never // the argument to `then` was not callable
: T; //
/**
* returns inflight promise if there hasn't been resolved yet
* returns in-flight promise if there is one
*
* @param callback - callback to be deDup.
* @param callback - callback to be deduped.
* @returns - the return type of the callback
*/
export const deDupeAsyncRequests = <A extends any[], R>(
callback: (...args: A) => Promise<R>
export const deDupeAsyncFunction = <A extends any[], R>(
fun: (...args: A) => Promise<R>
) => {
let inflightPromise: Promise<Awaited<R>> | undefined;
return async (...args: A): Promise<Awaited<R>> => {
if (inflightPromise) return inflightPromise;

if (!inflightPromise) {
inflightPromise = new Promise(async (resolve, reject) => {
try {
const result = await callback(...args);
resolve(result);
} catch (error) {
reject(error);
}
});
}
inflightPromise = new Promise(async (resolve, reject) => {
try {
const result = await fun(...args);
resolve(result);
} catch (error) {
reject(error);
} finally {
inflightPromise = undefined;
}
});

try {
return await inflightPromise;
} finally {
inflightPromise = undefined;
}
return await inflightPromise;
};
};
2 changes: 1 addition & 1 deletion packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ export {
export { urlSafeDecode } from './urlSafeDecode';
export { urlSafeEncode } from './urlSafeEncode';
export { deepFreeze } from './deepFreeze';
export { deDupeAsyncRequests } from './deDupeAsyncRequests';
export { deDupeAsyncFunction } from './deDupeAsyncFunction';
12 changes: 6 additions & 6 deletions yarn.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4ce72c3

Please sign in to comment.