Skip to content

Commit 2611da5

Browse files
samoussHaroenv
authored andcommitted
feat(index): resolve parent SearchParameters (#3937)
* 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
1 parent f22b9e2 commit 2611da5

File tree

6 files changed

+221
-8
lines changed

6 files changed

+221
-8
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { createInitOptions } from '../../../../test/mock/createWidget';
2+
import index from '../../../widgets/index/index';
3+
import resolve from '../resolveSearchParameters';
4+
5+
describe('mergeSearchParameters', () => {
6+
describe('1 level', () => {
7+
it('resolves the `SearchParameters` from the level 0', () => {
8+
const level0 = index({ indexName: 'level_0_index_name' });
9+
10+
level0.init(createInitOptions());
11+
12+
const actual = resolve(level0);
13+
14+
expect(actual).toEqual([level0.getHelper()!.state]);
15+
});
16+
});
17+
18+
describe('2 levels', () => {
19+
const level0 = index({ indexName: 'level_0_index_name' });
20+
const level1 = index({ indexName: 'level_1_index_name' });
21+
22+
level0.addWidgets([level1]);
23+
level0.init(createInitOptions());
24+
25+
it('resolves the `SearchParameters` from the level 0', () => {
26+
expect(resolve(level0)).toEqual([level0.getHelper()!.state]);
27+
});
28+
29+
it('resolves the `SearchParameters` from the level 1', () => {
30+
expect(resolve(level1)).toEqual([
31+
level0.getHelper()!.state,
32+
level1.getHelper()!.state,
33+
]);
34+
});
35+
});
36+
37+
describe('3 levels', () => {
38+
const level0 = index({ indexName: 'level_0_index_name' });
39+
const level1 = index({ indexName: 'level_1_index_name' });
40+
const level2 = index({ indexName: 'level_2_index_name' });
41+
42+
level0.addWidgets([level1.addWidgets([level2])]);
43+
level0.init(createInitOptions());
44+
45+
it('resolves the `SearchParameters` from the level 0', () => {
46+
expect(resolve(level0)).toEqual([level0.getHelper()!.state]);
47+
});
48+
49+
it('resolves the `SearchParameters` from the level 1', () => {
50+
expect(resolve(level1)).toEqual([
51+
level0.getHelper()!.state,
52+
level1.getHelper()!.state,
53+
]);
54+
});
55+
56+
it('resolves the `SearchParameters` from the level 2', () => {
57+
expect(resolve(level2)).toEqual([
58+
level0.getHelper()!.state,
59+
level1.getHelper()!.state,
60+
level2.getHelper()!.state,
61+
]);
62+
});
63+
});
64+
});

src/lib/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export { default as escape } from './escape';
2222
export { default as find } from './find';
2323
export { default as findIndex } from './findIndex';
2424
export { default as mergeDeep } from './mergeDeep';
25+
export { default as resolveSearchParameters } from './resolveSearchParameters';
2526
export { warning, deprecate } from './logger';
2627
export {
2728
createDocumentationLink,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Index } from '../../widgets/index/index';
2+
import { SearchParameters } from '../../types';
3+
4+
const resolveSearchParameters = (current: Index): SearchParameters[] => {
5+
let parent = current.getParent();
6+
let states = [current.getHelper()!.state];
7+
8+
while (parent !== null) {
9+
states = [parent.getHelper()!.state].concat(states);
10+
parent = parent.getParent();
11+
}
12+
13+
return states;
14+
};
15+
16+
export default resolveSearchParameters;

src/widgets/index/__tests__/index-test.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,108 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index/js/"
582582
);
583583
});
584584

585+
it('inherits from the parent states for the queries', () => {
586+
const level0 = index({ indexName: 'level_0_index_name' });
587+
const level1 = index({ indexName: 'level_1_index_name' });
588+
const level2 = index({ indexName: 'level_2_index_name' });
589+
const searchClient = createSearchClient();
590+
const mainHelper = algoliasearchHelper(searchClient, '', {});
591+
const instantSearchInstance = createInstantSearch({
592+
mainHelper,
593+
});
594+
595+
level0.addWidgets([
596+
createWidget({
597+
getConfiguration() {
598+
return {
599+
hitsPerPage: 5,
600+
};
601+
},
602+
}),
603+
604+
createSearchBox({
605+
getConfiguration() {
606+
return {
607+
query: 'Apple',
608+
};
609+
},
610+
}),
611+
612+
createPagination({
613+
getConfiguration() {
614+
return {
615+
page: 1,
616+
};
617+
},
618+
}),
619+
620+
level1.addWidgets([
621+
createSearchBox({
622+
getConfiguration() {
623+
return {
624+
query: 'Apple iPhone',
625+
};
626+
},
627+
}),
628+
629+
createPagination({
630+
getConfiguration() {
631+
return {
632+
page: 2,
633+
};
634+
},
635+
}),
636+
637+
level2.addWidgets([
638+
createSearchBox({
639+
getConfiguration() {
640+
return {
641+
query: 'Apple iPhone XS',
642+
};
643+
},
644+
}),
645+
]),
646+
]),
647+
]);
648+
649+
level0.init(
650+
createInitOptions({
651+
instantSearchInstance,
652+
})
653+
);
654+
655+
level0.getHelper()!.search();
656+
657+
expect(searchClient.search).toHaveBeenCalledWith(
658+
expect.arrayContaining([
659+
{
660+
indexName: 'level_0_index_name',
661+
params: expect.objectContaining({
662+
hitsPerPage: 5,
663+
query: 'Apple',
664+
page: 1,
665+
}),
666+
},
667+
{
668+
indexName: 'level_1_index_name',
669+
params: expect.objectContaining({
670+
hitsPerPage: 5,
671+
query: 'Apple iPhone',
672+
page: 2,
673+
}),
674+
},
675+
{
676+
indexName: 'level_2_index_name',
677+
params: expect.objectContaining({
678+
hitsPerPage: 5,
679+
query: 'Apple iPhone XS',
680+
page: 2,
681+
}),
682+
},
683+
])
684+
);
685+
});
686+
585687
it('uses the internal state for the SFFV queries', () => {
586688
const instance = index({ indexName: 'index_name' });
587689
const searchClient = createSearchClient();
@@ -839,6 +941,26 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index/js/"
839941
expect(instance.getWidgets()).toHaveLength(2);
840942
});
841943

944+
it('removes the internal parent', () => {
945+
const topLevelInstance = index({ indexName: 'top_level_index_name' });
946+
const subLevelInstance = index({ indexName: 'sub_level_index_name' });
947+
const instantSearchInstance = createInstantSearch();
948+
949+
topLevelInstance.addWidgets([subLevelInstance]);
950+
951+
topLevelInstance.init(
952+
createInitOptions({
953+
instantSearchInstance,
954+
})
955+
);
956+
957+
expect(subLevelInstance.getHelper()).toBeDefined();
958+
959+
subLevelInstance.dispose(createDisposeOptions());
960+
961+
expect(subLevelInstance.getHelper()).toBe(null);
962+
});
963+
842964
it('removes the internal Helper', () => {
843965
const instance = index({ indexName: 'index_name' });
844966
const instantSearchInstance = createInstantSearch();

src/widgets/index/index.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '../../types';
1313
import {
1414
createDocumentationMessageGenerator,
15+
resolveSearchParameters,
1516
enhanceConfiguration,
1617
} from '../../lib/utils';
1718

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

2627
export type Index = Widget & {
2728
getHelper(): Helper | null;
29+
getParent(): Index | null;
2830
getWidgets(): Widget[];
2931
addWidgets(widgets: Widget[]): Index;
3032
removeWidgets(widgets: Widget[]): Index;
@@ -38,6 +40,7 @@ const index = (props: IndexProps): Index => {
3840

3941
let localWidgets: Widget[] = [];
4042
let localInstantSearchInstance: InstantSearch | null = null;
43+
let localParent: Index | null = null;
4144
let helper: Helper | null = null;
4245
let derivedHelper: DerivedHelper | null = null;
4346

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

56+
getParent() {
57+
return localParent;
58+
},
59+
5360
getWidgets() {
5461
return localWidgets;
5562
},
@@ -156,6 +163,7 @@ const index = (props: IndexProps): Index => {
156163

157164
init({ instantSearchInstance, parent }) {
158165
localInstantSearchInstance = instantSearchInstance;
166+
localParent = parent;
159167

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

201209
derivedHelper = mainHelper.derive(() => {
202-
// @TODO: resolve the root and merge the SearchParameters
203-
return helper!.state;
210+
const parameters = resolveSearchParameters(this);
211+
212+
// @TODO: replace this dummy merge with the correct function
213+
return parameters.reduce((previous, current) =>
214+
algoliasearchHelper.SearchParameters.make({
215+
...previous,
216+
...current,
217+
})
218+
);
204219
});
205220

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

276291
localInstantSearchInstance = null;
292+
localParent = null;
277293
helper = null;
278294

279295
derivedHelper!.detach();

stories/index.stories.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ storiesOf('Index', module)
3131
.index({ indexName: 'instant_search_price_asc' })
3232
.addWidgets([
3333
instantsearch.widgets.configure({
34-
// @TODO: remove once we support inheritance of SearchParameters
35-
attributesToSnippet: ['description'],
3634
hitsPerPage: 2,
3735
}),
3836
instantsearch.widgets.hits({
@@ -50,8 +48,6 @@ storiesOf('Index', module)
5048
.index({ indexName: 'instant_search_rating_asc' })
5149
.addWidgets([
5250
instantsearch.widgets.configure({
53-
// @TODO: remove once we support inheritance of SearchParameters
54-
attributesToSnippet: ['description'],
5551
hitsPerPage: 1,
5652
}),
5753
instantsearch.widgets.hits({
@@ -87,8 +83,6 @@ storiesOf('Index', module)
8783
.index({ indexName: 'instant_search_price_asc' })
8884
.addWidgets([
8985
instantsearch.widgets.configure({
90-
// @TODO: remove once we support inheritance of SearchParameters
91-
attributesToSnippet: ['description'],
9286
hitsPerPage: 2,
9387
}),
9488
instantsearch.widgets.hits({

0 commit comments

Comments
 (0)