Skip to content

Commit

Permalink
fix(umd): batch requests when using plugins via UMD (#902)
Browse files Browse the repository at this point in the history
* wip

* e2e test

* remove e2e

* new test to clarify that execute isn't referentially equal

* back to status quo

* fix the issue

* fix unit test

* move algolia marker to outside createRequester

* docs

* make ts happy again

* Apply suggestions from code review

Co-authored-by: Sarah Dayan <[email protected]>

* make requester id required for batching

* Update packages/autocomplete-preset-algolia/src/requester/createRequester.ts

Co-authored-by: Sarah Dayan <[email protected]>

* extended test

Co-authored-by: Youcef Mammar <[email protected]>
Co-authored-by: Sarah Dayan <[email protected]>
  • Loading branch information
3 people authored Feb 23, 2022
1 parent aa7caa9 commit 1aa3dde
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 11 deletions.
2 changes: 1 addition & 1 deletion bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
{
"path": "packages/autocomplete-js/dist/umd/index.production.js",
"maxSize": "16.5 kB"
"maxSize": "16.75 kB"
},
{
"path": "packages/autocomplete-preset-algolia/dist/umd/index.production.js",
Expand Down
9 changes: 6 additions & 3 deletions packages/autocomplete-core/src/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ function isRequesterDescription<TItem extends BaseItem>(
type PackedDescription<TItem extends BaseItem> = {
searchClient: SearchClient;
execute: Execute<TItem>;
requesterId?: string;
items: RequestDescriptionPreResolved<TItem>['requests'];
};

type RequestDescriptionPreResolved<TItem extends BaseItem> = Pick<
RequesterDescription<TItem>,
'execute' | 'searchClient' | 'transformResponse'
'execute' | 'requesterId' | 'searchClient' | 'transformResponse'
> & {
requests: Array<{
query: MultipleQueriesQuery;
Expand Down Expand Up @@ -90,15 +91,16 @@ export function resolve<TItem extends BaseItem>(
return acc;
}

const { searchClient, execute, requests } = current;
const { searchClient, execute, requesterId, requests } = current;

const container = acc.find<PackedDescription<TItem>>(
(item): item is PackedDescription<TItem> => {
return (
isDescription(current) &&
isDescription(item) &&
item.searchClient === searchClient &&
item.execute === execute
Boolean(requesterId) &&
item.requesterId === requesterId
);
}
);
Expand All @@ -108,6 +110,7 @@ export function resolve<TItem extends BaseItem>(
} else {
const request: PackedDescription<TItem> = {
execute,
requesterId,
items: requests,
searchClient,
};
Expand Down
121 changes: 121 additions & 0 deletions packages/autocomplete-js/src/__tests__/requester.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
createRequester,
fetchAlgoliaResults,
} from '@algolia/autocomplete-preset-algolia';
import { fireEvent, waitFor, within } from '@testing-library/dom';

import {
Expand Down Expand Up @@ -346,6 +350,123 @@ describe('requester', () => {
});
});

test('batches calls across requesters with same id', async () => {
const container = document.createElement('div');
const panelContainer = document.createElement('div');

document.body.appendChild(panelContainer);

const searchClient = createSearchClient({
search: jest.fn((requests) =>
Promise.resolve(
createMultiSearchResponse<{ label: string }>(
...requests.map(({ indexName, params: { query } }) => ({
hits: [{ objectID: '1', label: 'Hit 1' }],
index: indexName,
query,
}))
)
)
),
});

const getResults1 = (params) =>
createRequester(
fetchAlgoliaResults,
'custom-requester-id'
)({
transformResponse: (response) => response.hits,
})(params);

const getResults2 = (params) =>
createRequester(
fetchAlgoliaResults,
'custom-requester-id'
)({
transformResponse: (response) => response.hits,
})(params);

const getResults3 = (params) =>
createRequester(
fetchAlgoliaResults,
'different-requester-id'
)({
transformResponse: (response) => response.hits,
})(params);

const templates = {
item({ item }) {
return JSON.stringify(item);
},
};

autocomplete({
container,
panelContainer,
getSources({ query }) {
return [
{
sourceId: 'hits',
getItems() {
return getResults1({
searchClient,
queries: [
{
indexName: 'indexName',
query,
},
],
});
},
templates,
},
{
sourceId: 'hits-merged',
getItems() {
return getResults2({
searchClient,
queries: [
{
indexName: 'indexName',
query,
},
],
});
},
templates,
},
{
sourceId: 'hits-separate',
getItems() {
return getResults3({
searchClient,
queries: [
{
indexName: 'indexName',
query,
},
],
});
},
templates,
},
];
},
});

const input = container.querySelector<HTMLInputElement>('.aa-Input');

fireEvent.input(input, { target: { value: 'a' } });

await waitFor(() => {
expect(
panelContainer.querySelector<HTMLElement>('.aa-Panel')
).toBeInTheDocument();

expect(searchClient.search).toHaveBeenCalledTimes(2);
});
});

test('transforms the response before forwarding it to the state', async () => {
const container = document.createElement('div');
const panelContainer = document.createElement('div');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('getAlgoliaFacets', () => {

expect(description).toEqual({
execute: expect.any(Function),
requesterId: 'algolia',
transformResponse: expect.any(Function),
searchClient,
queries: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('getAlgoliaResults', () => {

expect(description).toEqual({
execute: expect.any(Function),
requesterId: 'algolia',
transformResponse: expect.any(Function),
searchClient,
queries: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {

import { userAgents } from '../userAgents';

export const createAlgoliaRequester = createRequester((params) =>
fetchAlgoliaResults({
...params,
userAgents,
})
export const createAlgoliaRequester = createRequester(
(params) =>
fetchAlgoliaResults({
...params,
userAgents,
}),
'algolia'
);
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ describe('createRequester', () => {

expect(description).toEqual({
execute: expect.any(Function),
requesterId: undefined,
transformResponse,
searchClient,
queries: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('getAlgoliaFacets', () => {

expect(description).toEqual({
execute: expect.any(Function),
requesterId: 'algolia',
transformResponse: expect.any(Function),
searchClient,
queries: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe('getAlgoliaResults', () => {

expect(description).toEqual({
execute: expect.any(Function),
requesterId: 'algolia',
transformResponse: expect.any(Function),
searchClient,
queries: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ import { fetchAlgoliaResults } from '../search';

import { createRequester } from './createRequester';

export const createAlgoliaRequester = createRequester(fetchAlgoliaResults);
export const createAlgoliaRequester = createRequester(
fetchAlgoliaResults,
'algolia'
);
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,33 @@ export type RequestParams<THit> = FetcherParams & {
};

export type RequesterDescription<THit> = {
/**
* The search client used for this request. Multiple queries with the same client are batched (if `requesterId` is also the same).
*/
searchClient: SearchClient;
/**
* Identifies requesters to confirm their queries should be batched.
* This ensures that requesters with the same client but different
* post-processing functions don't get batched.
* When falsy, batching is disabled.
* For example, the Algolia requesters use "algolia".
*/
requesterId?: string;
/**
* The search parameters used for this query.
*/
queries: MultipleQueriesQuery[];
/**
* Transforms the response of this search before returning it to the caller.
*/
transformResponse: TransformResponse<THit>;
/**
* Post-processing function for multi-queries.
*/
execute: Execute<THit>;
};

export function createRequester(fetcher: Fetcher) {
export function createRequester(fetcher: Fetcher, requesterId?: string) {
function execute<THit>(fetcherParams: ExecuteParams<THit>) {
return fetcher<THit>({
searchClient: fetcherParams.searchClient,
Expand All @@ -108,6 +128,7 @@ export function createRequester(fetcher: Fetcher) {
requestParams: RequestParams<TTHit>
): RequesterDescription<TTHit> {
return {
requesterId,
execute,
...requesterParams,
...requestParams,
Expand Down

0 comments on commit 1aa3dde

Please sign in to comment.