Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

Commit

Permalink
feat(answers): add findAnswers (#804)
Browse files Browse the repository at this point in the history
* feat(answers): add searchForAnswers WIP

* update parameters

* add a FIXME comment

* accept options as an object

* add jsdoc and typings

* add test cases

* fix lint error

* better types

* clean up error message

* Update src/algoliasearch.helper.js

Co-authored-by: Haroen Viaene <hello@haroen.me>

* remove jsdoc

* fix type

Co-authored-by: Haroen Viaene <hello@haroen.me>
  • Loading branch information
Eunjae Lee and Haroenv committed Dec 23, 2020
1 parent 22d8ed4 commit 4635dd5
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 113 deletions.
15 changes: 15 additions & 0 deletions index.d.ts
Expand Up @@ -16,6 +16,7 @@ import algoliasearch, {
import {
SearchOptions as SearchOptionsV4,
SearchResponse as SearchResponseV4,
FindAnswersResponse
// @ts-ignore
} from '@algolia/client-search';
import { EventEmitter } from 'events';
Expand Down Expand Up @@ -171,6 +172,20 @@ declare namespace algoliasearchHelper {
) => void
): void;

/**
* Start the search for answers with the parameters set in the state.
* This method returns a promise.
* @param {Object} options - the options for answers API call
* @param {string[]} options.attributesForPrediction - Attributes to use for predictions. If empty, `searchableAttributes` is used instead.
* @param {string[]} options.queryLanguages - The languages in the query. Currently only supports ['en'].
* @param {number} options.nbHits - Maximum number of answers to retrieve from the Answers Engine. Cannot be greater than 1000.
*/
findAnswers<TObject>(options: {
attributesForPrediction: string[];
queryLanguages: string[];
nbHits: number;
}): Promise<FindAnswersResponse<TObject>>;

/**
* Search for facet values based on an query and the name of a faceted attribute. This
* triggers a search and will return a promise. On top of using the query, it also sends
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -39,9 +39,9 @@
"index.d.ts"
],
"devDependencies": {
"@types/algoliasearch": "3.30.12",
"@types/algoliasearch": "3.34.11",
"algolia-frontend-components": "0.0.35",
"algoliasearch": "4.0.0-beta.14",
"algoliasearch": "4.8.3",
"babel-core": "6.26.3",
"babel-loader": "6.4.1",
"babel-preset-es2015": "6.24.1",
Expand Down
45 changes: 45 additions & 0 deletions src/algoliasearch.helper.js
Expand Up @@ -8,6 +8,8 @@ var requestBuilder = require('./requestBuilder');
var events = require('events');
var inherits = require('./functions/inherits');
var objectHasKeys = require('./functions/objectHasKeys');
var omit = require('./functions/omit');
var merge = require('./functions/merge');

var version = require('./version');

Expand Down Expand Up @@ -248,6 +250,49 @@ AlgoliaSearchHelper.prototype.searchOnce = function(options, cb) {
});
};

/**
* Start the search for answers with the parameters set in the state.
* This method returns a promise.
* @param {Object} options - the options for answers API call
* @param {string[]} options.attributesForPrediction - Attributes to use for predictions. If empty, `searchableAttributes` is used instead.
* @param {string[]} options.queryLanguages - The languages in the query. Currently only supports ['en'].
* @param {number} options.nbHits - Maximum number of answers to retrieve from the Answers Engine. Cannot be greater than 1000.
*
* @return {promise} the answer results
*/
AlgoliaSearchHelper.prototype.findAnswers = function(options) {
var state = this.state;
var derivedHelper = this.derivedHelpers[0];
if (!derivedHelper) {
return Promise.resolve([]);
}
var derivedState = derivedHelper.getModifiedState(state);
var data = merge(
{
attributesForPrediction: options.attributesForPrediction,
nbHits: options.nbHits
},
{
params: omit(requestBuilder._getHitsSearchParams(derivedState), [
'attributesToSnippet',
'hitsPerPage',
'restrictSearchableAttributes',
'snippetEllipsisText' // FIXME remove this line once the engine is fixed.
])
}
);

var errorMessage = 'search for answers was called, but this client does not have a function client.initIndex(index).findAnswers';
if (typeof this.client.initIndex !== 'function') {
throw new Error(errorMessage);
}
var index = this.client.initIndex(derivedState.index);
if (typeof index.findAnswers !== 'function') {
throw new Error(errorMessage);
}
return index.findAnswers(derivedState.query, options.queryLanguages, data);
};

/**
* Structure of each result when using
* [`searchForFacetValues()`](reference.html#AlgoliaSearchHelper#searchForFacetValues)
Expand Down
103 changes: 103 additions & 0 deletions test/spec/algoliasearch.helper/findAnswers.js
@@ -0,0 +1,103 @@
'use strict';

var algoliasearchHelper = require('../../../index');

function makeFakeFindAnswersResponse() {
return {
exhaustiveFacetsCount: true,
facetHits: [],
processingTimeMS: 3
};
}

function setupTestEnvironment(helperOptions) {
var findAnswers = jest.fn(function() {
return Promise.resolve([makeFakeFindAnswersResponse()]);
});

var fakeClient = {
initIndex: function() {
return {
findAnswers: findAnswers
};
}
};

var helper = algoliasearchHelper(fakeClient, 'index', helperOptions);

return {
findAnswers: findAnswers,
helper: helper
};
}

test('returns an empty array with no derived helper', function() {
var env = setupTestEnvironment();
var helper = env.helper;
var findAnswers = env.findAnswers;

return helper
.findAnswers({
attributesForPrediction: ['description'],
queryLanguages: ['en'],
nbHits: 1
})
.then(function(result) {
expect(findAnswers).toHaveBeenCalledTimes(0);
expect(result).toEqual([]);
});
});

test('returns a correct result with one derivation', function() {
var env = setupTestEnvironment();
var helper = env.helper;
var findAnswers = env.findAnswers;

helper.derive(function(state) {
return state;
});

return helper
.findAnswers({
attributesForPrediction: ['description'],
queryLanguages: ['en'],
nbHits: 1
})
.then(function(result) {
expect(findAnswers).toHaveBeenCalledTimes(1);
expect(result).toEqual([makeFakeFindAnswersResponse()]);
});
});

test('runs findAnswers with facets', function() {
var env = setupTestEnvironment({facets: ['facet1']});
var helper = env.helper;
var findAnswers = env.findAnswers;
helper.addFacetRefinement('facet1', 'facetValue');

helper.derive(function(state) {
return state;
});

helper.setQuery('hello');

return helper
.findAnswers({
attributesForPrediction: ['description'],
queryLanguages: ['en'],
nbHits: 1
})
.then(function() {
expect(findAnswers).toHaveBeenCalledTimes(1);
expect(findAnswers).toHaveBeenCalledWith('hello', ['en'], {
attributesForPrediction: ['description'],
nbHits: 1,
params: {
facetFilters: ['facet1:facetValue'],
facets: ['facet1'],
query: 'hello',
tagFilters: ''
}
});
});
});

0 comments on commit 4635dd5

Please sign in to comment.