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

Commit 4635dd5

Browse files
Eunjae LeeHaroenv
andauthored
feat(answers): add findAnswers (#804)
* 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>
1 parent 22d8ed4 commit 4635dd5

File tree

5 files changed

+287
-113
lines changed

5 files changed

+287
-113
lines changed

index.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import algoliasearch, {
1616
import {
1717
SearchOptions as SearchOptionsV4,
1818
SearchResponse as SearchResponseV4,
19+
FindAnswersResponse
1920
// @ts-ignore
2021
} from '@algolia/client-search';
2122
import { EventEmitter } from 'events';
@@ -171,6 +172,20 @@ declare namespace algoliasearchHelper {
171172
) => void
172173
): void;
173174

175+
/**
176+
* Start the search for answers with the parameters set in the state.
177+
* This method returns a promise.
178+
* @param {Object} options - the options for answers API call
179+
* @param {string[]} options.attributesForPrediction - Attributes to use for predictions. If empty, `searchableAttributes` is used instead.
180+
* @param {string[]} options.queryLanguages - The languages in the query. Currently only supports ['en'].
181+
* @param {number} options.nbHits - Maximum number of answers to retrieve from the Answers Engine. Cannot be greater than 1000.
182+
*/
183+
findAnswers<TObject>(options: {
184+
attributesForPrediction: string[];
185+
queryLanguages: string[];
186+
nbHits: number;
187+
}): Promise<FindAnswersResponse<TObject>>;
188+
174189
/**
175190
* Search for facet values based on an query and the name of a faceted attribute. This
176191
* triggers a search and will return a promise. On top of using the query, it also sends

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
"index.d.ts"
4040
],
4141
"devDependencies": {
42-
"@types/algoliasearch": "3.30.12",
42+
"@types/algoliasearch": "3.34.11",
4343
"algolia-frontend-components": "0.0.35",
44-
"algoliasearch": "4.0.0-beta.14",
44+
"algoliasearch": "4.8.3",
4545
"babel-core": "6.26.3",
4646
"babel-loader": "6.4.1",
4747
"babel-preset-es2015": "6.24.1",

src/algoliasearch.helper.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ var requestBuilder = require('./requestBuilder');
88
var events = require('events');
99
var inherits = require('./functions/inherits');
1010
var objectHasKeys = require('./functions/objectHasKeys');
11+
var omit = require('./functions/omit');
12+
var merge = require('./functions/merge');
1113

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

@@ -248,6 +250,49 @@ AlgoliaSearchHelper.prototype.searchOnce = function(options, cb) {
248250
});
249251
};
250252

253+
/**
254+
* Start the search for answers with the parameters set in the state.
255+
* This method returns a promise.
256+
* @param {Object} options - the options for answers API call
257+
* @param {string[]} options.attributesForPrediction - Attributes to use for predictions. If empty, `searchableAttributes` is used instead.
258+
* @param {string[]} options.queryLanguages - The languages in the query. Currently only supports ['en'].
259+
* @param {number} options.nbHits - Maximum number of answers to retrieve from the Answers Engine. Cannot be greater than 1000.
260+
*
261+
* @return {promise} the answer results
262+
*/
263+
AlgoliaSearchHelper.prototype.findAnswers = function(options) {
264+
var state = this.state;
265+
var derivedHelper = this.derivedHelpers[0];
266+
if (!derivedHelper) {
267+
return Promise.resolve([]);
268+
}
269+
var derivedState = derivedHelper.getModifiedState(state);
270+
var data = merge(
271+
{
272+
attributesForPrediction: options.attributesForPrediction,
273+
nbHits: options.nbHits
274+
},
275+
{
276+
params: omit(requestBuilder._getHitsSearchParams(derivedState), [
277+
'attributesToSnippet',
278+
'hitsPerPage',
279+
'restrictSearchableAttributes',
280+
'snippetEllipsisText' // FIXME remove this line once the engine is fixed.
281+
])
282+
}
283+
);
284+
285+
var errorMessage = 'search for answers was called, but this client does not have a function client.initIndex(index).findAnswers';
286+
if (typeof this.client.initIndex !== 'function') {
287+
throw new Error(errorMessage);
288+
}
289+
var index = this.client.initIndex(derivedState.index);
290+
if (typeof index.findAnswers !== 'function') {
291+
throw new Error(errorMessage);
292+
}
293+
return index.findAnswers(derivedState.query, options.queryLanguages, data);
294+
};
295+
251296
/**
252297
* Structure of each result when using
253298
* [`searchForFacetValues()`](reference.html#AlgoliaSearchHelper#searchForFacetValues)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
'use strict';
2+
3+
var algoliasearchHelper = require('../../../index');
4+
5+
function makeFakeFindAnswersResponse() {
6+
return {
7+
exhaustiveFacetsCount: true,
8+
facetHits: [],
9+
processingTimeMS: 3
10+
};
11+
}
12+
13+
function setupTestEnvironment(helperOptions) {
14+
var findAnswers = jest.fn(function() {
15+
return Promise.resolve([makeFakeFindAnswersResponse()]);
16+
});
17+
18+
var fakeClient = {
19+
initIndex: function() {
20+
return {
21+
findAnswers: findAnswers
22+
};
23+
}
24+
};
25+
26+
var helper = algoliasearchHelper(fakeClient, 'index', helperOptions);
27+
28+
return {
29+
findAnswers: findAnswers,
30+
helper: helper
31+
};
32+
}
33+
34+
test('returns an empty array with no derived helper', function() {
35+
var env = setupTestEnvironment();
36+
var helper = env.helper;
37+
var findAnswers = env.findAnswers;
38+
39+
return helper
40+
.findAnswers({
41+
attributesForPrediction: ['description'],
42+
queryLanguages: ['en'],
43+
nbHits: 1
44+
})
45+
.then(function(result) {
46+
expect(findAnswers).toHaveBeenCalledTimes(0);
47+
expect(result).toEqual([]);
48+
});
49+
});
50+
51+
test('returns a correct result with one derivation', function() {
52+
var env = setupTestEnvironment();
53+
var helper = env.helper;
54+
var findAnswers = env.findAnswers;
55+
56+
helper.derive(function(state) {
57+
return state;
58+
});
59+
60+
return helper
61+
.findAnswers({
62+
attributesForPrediction: ['description'],
63+
queryLanguages: ['en'],
64+
nbHits: 1
65+
})
66+
.then(function(result) {
67+
expect(findAnswers).toHaveBeenCalledTimes(1);
68+
expect(result).toEqual([makeFakeFindAnswersResponse()]);
69+
});
70+
});
71+
72+
test('runs findAnswers with facets', function() {
73+
var env = setupTestEnvironment({facets: ['facet1']});
74+
var helper = env.helper;
75+
var findAnswers = env.findAnswers;
76+
helper.addFacetRefinement('facet1', 'facetValue');
77+
78+
helper.derive(function(state) {
79+
return state;
80+
});
81+
82+
helper.setQuery('hello');
83+
84+
return helper
85+
.findAnswers({
86+
attributesForPrediction: ['description'],
87+
queryLanguages: ['en'],
88+
nbHits: 1
89+
})
90+
.then(function() {
91+
expect(findAnswers).toHaveBeenCalledTimes(1);
92+
expect(findAnswers).toHaveBeenCalledWith('hello', ['en'], {
93+
attributesForPrediction: ['description'],
94+
nbHits: 1,
95+
params: {
96+
facetFilters: ['facet1:facetValue'],
97+
facets: ['facet1'],
98+
query: 'hello',
99+
tagFilters: ''
100+
}
101+
});
102+
});
103+
});

0 commit comments

Comments
 (0)