Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
fix(connectAutoComplete): allow usage with hits from a single index (#75
Browse files Browse the repository at this point in the history
)

* fix(connectAutoComplete): allow usage with hits from a single index

fixes #74

* fix(connectAutoComplete): use single/multi index API

* fix eslint
  • Loading branch information
Haroenv authored and mthuret committed May 2, 2017
1 parent 552d0a9 commit 8b3b358
Show file tree
Hide file tree
Showing 2 changed files with 213 additions and 84 deletions.
85 changes: 61 additions & 24 deletions packages/react-instantsearch/src/connectors/connectAutoComplete.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,62 @@
import createConnector from '../core/createConnector';
import { omit } from 'lodash';
import {
cleanUpValue,
refineValue,
getCurrentRefinementValue,
} from '../core/indexUtils';

const getId = () => 'query';

function getCurrentRefinement(props, searchState) {
function getCurrentRefinement(props, searchState, context) {
const id = getId();
if (typeof searchState[id] !== 'undefined') {
return searchState[id];
}
if (typeof props.defaultRefinement !== 'undefined') {
return props.defaultRefinement;
return getCurrentRefinementValue(
props,
searchState,
context,
id,
'',
currentRefinement => {
if (currentRefinement) {
return currentRefinement;
}
return '';
}
);
}

function getHits(searchResults) {
if (searchResults.results) {
if (
searchResults.results.hits &&
Array.isArray(searchResults.results.hits)
) {
return searchResults.results.hits;
} else {
return Object.keys(searchResults.results).reduce(
(hits, index) => [
...hits,
{
index,
hits: searchResults.results[index].hits,
},
],
[]
);
}
} else {
return [];
}
return '';
}

function refine(props, searchState, nextRefinement, context) {
const id = getId();
const nextValue = { [id]: nextRefinement };
const resetPage = true;
return refineValue(searchState, nextValue, context, resetPage);
}

function cleanUp(props, searchState, context) {
return cleanUpValue(searchState, context, getId());
}

/**
Expand All @@ -32,35 +77,27 @@ export default createConnector({
displayName: 'AlgoliaAutoComplete',

getProvidedProps(props, searchState, searchResults) {
const hits = [];
if (searchResults.results) {
Object.keys(searchResults.results).forEach(index => {
hits.push({ index, hits: searchResults.results[index].hits });
});
}
return {
hits,
currentRefinement: getCurrentRefinement(props, searchState),
hits: getHits(searchResults),
currentRefinement: getCurrentRefinement(props, searchState, this.context),
};
},

refine(props, searchState, nextCurrentRefinement) {
const id = getId();
return {
...searchState,
[id]: nextCurrentRefinement,
};
refine(props, searchState, nextRefinement) {
return refine(props, searchState, nextRefinement, this.context);
},

cleanUp(props, searchState) {
return omit(searchState, getId());
return cleanUp(props, searchState, this.context);
},

/* connectAutoComplete needs to be considered as a widget to trigger a search if no others widgets are used.
* To be considered as a widget you need either getSearchParameters, getMetadata or getTransitionState
* See createConnector.js
* */
getSearchParameters(searchParameters, props, searchState) {
return searchParameters.setQuery(getCurrentRefinement(props, searchState));
return searchParameters.setQuery(
getCurrentRefinement(props, searchState, this.context)
);
},
});
212 changes: 152 additions & 60 deletions packages/react-instantsearch/src/connectors/connectAutoComplete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,74 +5,166 @@ import { SearchParameters } from 'algoliasearch-helper';

jest.mock('../core/createConnector');

const { getSearchParameters, refine } = connect;

describe('connectAutoComplete', () => {
const context = {};
const getProvidedProps = connect.getProvidedProps.bind(context);
it('provides current hits to the component', () => {
const firstHits = [{}];
const secondHits = [{}];
let props = getProvidedProps(
{},
{},
{
results: { first: { hits: firstHits }, second: { hits: secondHits } },
}
);
expect(props).toEqual({
hits: [
{ hits: firstHits, index: 'first' },
{ hits: secondHits, index: 'second' },
],
currentRefinement: '',
});
describe('single index', () => {
const context = { context: { ais: { mainTargetedIndex: 'index' } } };
const getProvidedProps = connect.getProvidedProps.bind(context);
const refine = connect.refine.bind(context);
const getSearchParameters = connect.getSearchParameters.bind(context);
const cleanUp = connect.cleanUp.bind(context);
it('provides current hits to the component', () => {
const hits = [{}];
let props = getProvidedProps(
{},
{},
{
results: { hits },
}
);
expect(props).toEqual({
hits,
currentRefinement: '',
});

props = getProvidedProps(
{},
{ query: 'query' },
{
results: { hits },
}
);
expect(props).toEqual({
hits,
currentRefinement: 'query',
});

props = getProvidedProps(
{},
{ query: 'query' },
{
results: { first: { hits: firstHits }, second: { hits: secondHits } },
}
);
expect(props).toEqual({
hits: [
{ hits: firstHits, index: 'first' },
{ hits: secondHits, index: 'second' },
],
currentRefinement: 'query',
props = getProvidedProps(
{ defaultRefinement: 'query' },
{},
{
results: { hits },
}
);
expect(props).toEqual({
hits,
currentRefinement: 'query',
});
});
it('refines the query parameter', () => {
const params = getSearchParameters(
new SearchParameters(),
{},
{ query: 'bar' }
);
expect(params.query).toBe('bar');
});

props = getProvidedProps(
{ defaultRefinement: 'query' },
{},
{
results: { first: { hits: firstHits }, second: { hits: secondHits } },
}
);
expect(props).toEqual({
hits: [
{ hits: firstHits, index: 'first' },
{ hits: secondHits, index: 'second' },
],
currentRefinement: 'query',
it("calling refine updates the widget's search state", () => {
const nextState = refine({}, { otherKey: 'val' }, 'yep');
expect(nextState).toEqual({
otherKey: 'val',
query: 'yep',
page: 1,
});
});
it('should return the right searchState when clean up', () => {
const searchState = cleanUp(
{},
{
query: { searchState: 'searchState' },
another: { searchState: 'searchState' },
}
);
expect(searchState).toEqual({ another: { searchState: 'searchState' } });
});
});
describe('multi index', () => {
const context = {
context: {
ais: { mainTargetedIndex: 'first' },
multiIndexContext: { targetedIndex: 'first' },
},
};
const getProvidedProps = connect.getProvidedProps.bind(context);
const getSearchParameters = connect.getSearchParameters.bind(context);
const refine = connect.refine.bind(context);
const cleanUp = connect.cleanUp.bind(context);
it('provides current hits to the component', () => {
const firstHits = [{}];
const secondHits = [{}];
let props = getProvidedProps(
{},
{},
{
results: { first: { hits: firstHits }, second: { hits: secondHits } },
}
);
expect(props).toEqual({
hits: [
{ hits: firstHits, index: 'first' },
{ hits: secondHits, index: 'second' },
],
currentRefinement: '',
});

it('refines the query parameter', () => {
const params = getSearchParameters(
new SearchParameters(),
{},
{ query: 'bar' }
);
expect(params.query).toBe('bar');
});
props = getProvidedProps(
{},
{ indices: { first: { query: 'query' } } },
{
results: { first: { hits: firstHits }, second: { hits: secondHits } },
}
);
expect(props).toEqual({
hits: [
{ hits: firstHits, index: 'first' },
{ hits: secondHits, index: 'second' },
],
currentRefinement: 'query',
});

it("calling refine updates the widget's search state", () => {
const nextState = refine({}, { otherKey: 'val' }, 'yep');
expect(nextState).toEqual({
otherKey: 'val',
query: 'yep',
props = getProvidedProps(
{ defaultRefinement: 'query' },
{},
{
results: { first: { hits: firstHits }, second: { hits: secondHits } },
}
);
expect(props).toEqual({
hits: [
{ hits: firstHits, index: 'first' },
{ hits: secondHits, index: 'second' },
],
currentRefinement: 'query',
});
});
it('refines the query parameter', () => {
const params = getSearchParameters(
new SearchParameters(),
{},
{ indices: { first: { query: 'bar' } } }
);
expect(params.query).toBe('bar');
});

it("calling refine updates the widget's search state", () => {
const nextState = refine({}, { otherKey: 'val' }, 'yep');
expect(nextState).toEqual({
otherKey: 'val',
indices: { first: { query: 'yep', page: 1 } },
});
});
it('should return the right searchState when clean up', () => {
const searchState = cleanUp(
{},
{
indices: { first: { query: '' } },
another: { searchState: 'searchState' },
}
);
expect(searchState).toEqual({
indices: { first: {} },
another: { searchState: 'searchState' },
});
});
});
});

0 comments on commit 8b3b358

Please sign in to comment.