Skip to content

Commit

Permalink
feat(index): resolve parent SearchParameters (#3937)
Browse files Browse the repository at this point in the history
* feat(resolveSearchParameters): implementation

* feat(index): expose the parent

* feat(index): resolve and shallow merge search parameters

* chore(stories): remove index specific search parameters

* test(index): use correct index name
  • Loading branch information
samouss authored and Haroenv committed Oct 23, 2019
1 parent f22b9e2 commit 2611da5
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 8 deletions.
64 changes: 64 additions & 0 deletions src/lib/utils/__tests__/resolveSearchParameters-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { createInitOptions } from '../../../../test/mock/createWidget';
import index from '../../../widgets/index/index';
import resolve from '../resolveSearchParameters';

describe('mergeSearchParameters', () => {
describe('1 level', () => {
it('resolves the `SearchParameters` from the level 0', () => {
const level0 = index({ indexName: 'level_0_index_name' });

level0.init(createInitOptions());

const actual = resolve(level0);

expect(actual).toEqual([level0.getHelper()!.state]);
});
});

describe('2 levels', () => {
const level0 = index({ indexName: 'level_0_index_name' });
const level1 = index({ indexName: 'level_1_index_name' });

level0.addWidgets([level1]);
level0.init(createInitOptions());

it('resolves the `SearchParameters` from the level 0', () => {
expect(resolve(level0)).toEqual([level0.getHelper()!.state]);
});

it('resolves the `SearchParameters` from the level 1', () => {
expect(resolve(level1)).toEqual([
level0.getHelper()!.state,
level1.getHelper()!.state,
]);
});
});

describe('3 levels', () => {
const level0 = index({ indexName: 'level_0_index_name' });
const level1 = index({ indexName: 'level_1_index_name' });
const level2 = index({ indexName: 'level_2_index_name' });

level0.addWidgets([level1.addWidgets([level2])]);
level0.init(createInitOptions());

it('resolves the `SearchParameters` from the level 0', () => {
expect(resolve(level0)).toEqual([level0.getHelper()!.state]);
});

it('resolves the `SearchParameters` from the level 1', () => {
expect(resolve(level1)).toEqual([
level0.getHelper()!.state,
level1.getHelper()!.state,
]);
});

it('resolves the `SearchParameters` from the level 2', () => {
expect(resolve(level2)).toEqual([
level0.getHelper()!.state,
level1.getHelper()!.state,
level2.getHelper()!.state,
]);
});
});
});
1 change: 1 addition & 0 deletions src/lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export { default as escape } from './escape';
export { default as find } from './find';
export { default as findIndex } from './findIndex';
export { default as mergeDeep } from './mergeDeep';
export { default as resolveSearchParameters } from './resolveSearchParameters';
export { warning, deprecate } from './logger';
export {
createDocumentationLink,
Expand Down
16 changes: 16 additions & 0 deletions src/lib/utils/resolveSearchParameters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Index } from '../../widgets/index/index';
import { SearchParameters } from '../../types';

const resolveSearchParameters = (current: Index): SearchParameters[] => {
let parent = current.getParent();
let states = [current.getHelper()!.state];

while (parent !== null) {
states = [parent.getHelper()!.state].concat(states);
parent = parent.getParent();
}

return states;
};

export default resolveSearchParameters;
122 changes: 122 additions & 0 deletions src/widgets/index/__tests__/index-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,108 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index/js/"
);
});

it('inherits from the parent states for the queries', () => {
const level0 = index({ indexName: 'level_0_index_name' });
const level1 = index({ indexName: 'level_1_index_name' });
const level2 = index({ indexName: 'level_2_index_name' });
const searchClient = createSearchClient();
const mainHelper = algoliasearchHelper(searchClient, '', {});
const instantSearchInstance = createInstantSearch({
mainHelper,
});

level0.addWidgets([
createWidget({
getConfiguration() {
return {
hitsPerPage: 5,
};
},
}),

createSearchBox({
getConfiguration() {
return {
query: 'Apple',
};
},
}),

createPagination({
getConfiguration() {
return {
page: 1,
};
},
}),

level1.addWidgets([
createSearchBox({
getConfiguration() {
return {
query: 'Apple iPhone',
};
},
}),

createPagination({
getConfiguration() {
return {
page: 2,
};
},
}),

level2.addWidgets([
createSearchBox({
getConfiguration() {
return {
query: 'Apple iPhone XS',
};
},
}),
]),
]),
]);

level0.init(
createInitOptions({
instantSearchInstance,
})
);

level0.getHelper()!.search();

expect(searchClient.search).toHaveBeenCalledWith(
expect.arrayContaining([
{
indexName: 'level_0_index_name',
params: expect.objectContaining({
hitsPerPage: 5,
query: 'Apple',
page: 1,
}),
},
{
indexName: 'level_1_index_name',
params: expect.objectContaining({
hitsPerPage: 5,
query: 'Apple iPhone',
page: 2,
}),
},
{
indexName: 'level_2_index_name',
params: expect.objectContaining({
hitsPerPage: 5,
query: 'Apple iPhone XS',
page: 2,
}),
},
])
);
});

it('uses the internal state for the SFFV queries', () => {
const instance = index({ indexName: 'index_name' });
const searchClient = createSearchClient();
Expand Down Expand Up @@ -839,6 +941,26 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index/js/"
expect(instance.getWidgets()).toHaveLength(2);
});

it('removes the internal parent', () => {
const topLevelInstance = index({ indexName: 'top_level_index_name' });
const subLevelInstance = index({ indexName: 'sub_level_index_name' });
const instantSearchInstance = createInstantSearch();

topLevelInstance.addWidgets([subLevelInstance]);

topLevelInstance.init(
createInitOptions({
instantSearchInstance,
})
);

expect(subLevelInstance.getHelper()).toBeDefined();

subLevelInstance.dispose(createDisposeOptions());

expect(subLevelInstance.getHelper()).toBe(null);
});

it('removes the internal Helper', () => {
const instance = index({ indexName: 'index_name' });
const instantSearchInstance = createInstantSearch();
Expand Down
20 changes: 18 additions & 2 deletions src/widgets/index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '../../types';
import {
createDocumentationMessageGenerator,
resolveSearchParameters,
enhanceConfiguration,
} from '../../lib/utils';

Expand All @@ -25,6 +26,7 @@ type IndexProps = {

export type Index = Widget & {
getHelper(): Helper | null;
getParent(): Index | null;
getWidgets(): Widget[];
addWidgets(widgets: Widget[]): Index;
removeWidgets(widgets: Widget[]): Index;
Expand All @@ -38,6 +40,7 @@ const index = (props: IndexProps): Index => {

let localWidgets: Widget[] = [];
let localInstantSearchInstance: InstantSearch | null = null;
let localParent: Index | null = null;
let helper: Helper | null = null;
let derivedHelper: DerivedHelper | null = null;

Expand All @@ -50,6 +53,10 @@ const index = (props: IndexProps): Index => {
return helper;
},

getParent() {
return localParent;
},

getWidgets() {
return localWidgets;
},
Expand Down Expand Up @@ -156,6 +163,7 @@ const index = (props: IndexProps): Index => {

init({ instantSearchInstance, parent }) {
localInstantSearchInstance = instantSearchInstance;
localParent = parent;

// The `mainHelper` is already defined at this point. The instance is created
// inside InstantSearch at the `start` method, which occurs before the `init`
Expand Down Expand Up @@ -199,8 +207,15 @@ const index = (props: IndexProps): Index => {
};

derivedHelper = mainHelper.derive(() => {
// @TODO: resolve the root and merge the SearchParameters
return helper!.state;
const parameters = resolveSearchParameters(this);

// @TODO: replace this dummy merge with the correct function
return parameters.reduce((previous, current) =>
algoliasearchHelper.SearchParameters.make({
...previous,
...current,
})
);
});

// We have to use `!` at the moment because `dervive` is not correctly typed.
Expand Down Expand Up @@ -274,6 +289,7 @@ const index = (props: IndexProps): Index => {
});

localInstantSearchInstance = null;
localParent = null;
helper = null;

derivedHelper!.detach();
Expand Down
6 changes: 0 additions & 6 deletions stories/index.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ storiesOf('Index', module)
.index({ indexName: 'instant_search_price_asc' })
.addWidgets([
instantsearch.widgets.configure({
// @TODO: remove once we support inheritance of SearchParameters
attributesToSnippet: ['description'],
hitsPerPage: 2,
}),
instantsearch.widgets.hits({
Expand All @@ -50,8 +48,6 @@ storiesOf('Index', module)
.index({ indexName: 'instant_search_rating_asc' })
.addWidgets([
instantsearch.widgets.configure({
// @TODO: remove once we support inheritance of SearchParameters
attributesToSnippet: ['description'],
hitsPerPage: 1,
}),
instantsearch.widgets.hits({
Expand Down Expand Up @@ -87,8 +83,6 @@ storiesOf('Index', module)
.index({ indexName: 'instant_search_price_asc' })
.addWidgets([
instantsearch.widgets.configure({
// @TODO: remove once we support inheritance of SearchParameters
attributesToSnippet: ['description'],
hitsPerPage: 2,
}),
instantsearch.widgets.hits({
Expand Down

0 comments on commit 2611da5

Please sign in to comment.