Socket
Socket
Sign inDemoInstall

algoliasearch-helper

Package Overview
Dependencies
Maintainers
3
Versions
147
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

algoliasearch-helper - npm Package Compare versions

Comparing version 2.0.4 to 2.1.0

docs/AlgoliaSearchHelper.html

3

bower.json
{
"name": "algoliasearch-helper",
"version": "2.1.0",
"homepage": "https://github.com/algolia/algoliasearch-helper-js",

@@ -26,4 +27,4 @@ "authors": [

"dependencies": {
"algoliasearch": "3.1.x"
"algoliasearch": "3.x"
}
}
"use strict";
var AlgoliaSearchHelper = require( "./src/algoliasearch.helper" );
var SearchParameters = require( "./src/SearchParameters" );
var SearchResults = require( "./src/SearchResults" );
/**
* The algoliasearch-helper module is a function that instanciate the helper.
* @module algoliasearch-helper
* The algoliasearchHelper module contains everything needed to use the Algoliasearch
* Helper. It is a also a function that instanciate the helper.
* To use the helper, you also need the Algolia JS client v3.
* @example
* //using the UMD build
* var client = algoliasearch('latency', '6be0576ff61c053d5f9a3225e2a90f76');
* var helper = algoliasearchHelper( client, "bestbuy", {
* facets : [ "shipping" ],
* disjunctiveFacets : [ "category" ]
* } );
* helper.on( "result", function( result ) {
* console.log( result );
* } );
* helper.toggleRefine( "Movies & TV Shows" )
* .toggleRefine( "Free shipping" )
* .search();
* @module algoliasearchHelper
* @param {AlgoliaSearch} client an AlgoliaSearch client
* @param {string} index the index name to query
* @param {SearchParameters | object} options an object defining the initial config of the search. It doesn't have to be a {SearchParamaters}, just an object containing the properties you need from it.
* @param {SearchParameters|object} opts an object defining the initial config of the search. It doesn't have to be a {SearchParameters}, just an object containing the properties you need from it.
* @return {AlgoliaSearchHelper}
*/
function helper( client, index, opts ) {
function algoliasearchHelper( client, index, opts ) {
return new AlgoliaSearchHelper( client, index, opts );

@@ -17,6 +36,27 @@ }

* The version currently used
* @member module:algoliasearch-helper.version
* @member module:algoliasearchHelper.version
*/
helper.version = "2.0.4";
algoliasearchHelper.version = "2.1.0";
module.exports = helper;
/**
* Constructor for the Helper.
* @member module:algoliasearchHelper.AlgoliaSearchHelper
* @see AlgoliaSearchHelper
*/
algoliasearchHelper.AlgoliaSearchHelper = AlgoliaSearchHelper;
/**
* Constructor for the object containing all the parameters of the search.
* @member module:algoliasearchHelper.SearchParameters
* @see SearchParameters
*/
algoliasearchHelper.SearchParameters = SearchParameters;
/**
* Constructor for the object containing the results of the search.
* @member module:algoliasearchHelper.SearchResults
* @see SearchResults
*/
algoliasearchHelper.SearchResults = SearchResults;
module.exports = algoliasearchHelper;
{
"name": "algoliasearch-helper",
"version": "2.0.4",
"version": "2.1.0",
"description": "Helper for implementing advanced search features with algolia",

@@ -11,2 +11,3 @@ "main": "index.js",

"dev": "DEBUG=zuul* zuul --no-coverage --local 8090 --ui tape test/run.js",
"dev-coverage": "DEBUG=zuul* zuul --local 8090 --ui tape test/run.js",
"lint": "eslint src index.js; true",

@@ -17,2 +18,3 @@ "watch-lint": " onchange '.eslintrc' 'src/**/*.js' 'index.js' -- npm run lint ",

"doc": "jsdoc -r src index.js -d docs -c .jsdoc --readme README.MD",
"doc:watch" : "onchange 'src/**/*.js' 'index.js' -- npm run doc",
"publish-doc": "git checkout gh-pages && git merge master && npm run build && npm run doc && git commit -a -m 'Update doc' && git push origin gh-pages && git checkout master",

@@ -22,2 +24,7 @@ "test-ci": "echo \"Error: no test specified\" && exit 1",

},
"browserify": {
"transform": [
"envify"
]
},
"author": {

@@ -37,2 +44,3 @@ "name": "Algolia SAS",

"bulkify": "1.1.1",
"envify": "3.4.0",
"eslint": "0.17.1",

@@ -51,3 +59,3 @@ "http-server": "0.8.0",

"dependencies": {
"lodash": "3.5.0"
"lodash": "3.9.x"
},

@@ -54,0 +62,0 @@ "peerDependencies": {

@@ -12,3 +12,2 @@ *Coming from V1 (or js client v2)?* Read the [migration guide](https://github.com/algolia/algoliasearch-helper-js/wiki/Migration-guide-:-V1-to-V2) to the new version of the Helper.

## Features
a
- Search parameters tracking

@@ -15,0 +14,0 @@ - Facets exclusions

@@ -22,3 +22,3 @@ "use strict";

* @param {string} index the index name to query
* @param {SearchParameters | object} options an object defining the initial config of the search. It doesn't have to be a {SearchParamaters}, just an object containing the properties you need from it.
* @param {SearchParameters | object} options an object defining the initial config of the search. It doesn't have to be a {SearchParameters}, just an object containing the properties you need from it.
*/

@@ -28,4 +28,6 @@ function AlgoliaSearchHelper( client, index, options ) {

this.index = index;
this.state = new SearchParameters( options );
this.state = SearchParameters.make( options );
this.lastResults = null;
this._queryId = 0;
this._lastQueryIdReceived = -1;
}

@@ -67,2 +69,12 @@

/**
* Remove all the tag filtering
* @return {AlgoliaSearchHelper}
*/
AlgoliaSearchHelper.prototype.clearTags = function() {
this.state = this.state.clearTags();
this._change();
return this;
};
/**
* Ensure a facet refinement exists

@@ -80,3 +92,16 @@ * @param {string} facet the facet to refine

/**
* Ensure a facet refinement does not exist
* Add a numeric refinement on the given attribute
* @param {string} attribute the attribute on which the numeric filter applies
* @param {string} operator the operator of the filter
* @param {number} value the value of the filter
* @return {AlgoliaSearchHelper}
*/
AlgoliaSearchHelper.prototype.addNumericRefinement = function( attribute, operator, value ) {
this.state = this.state.addNumericRefinement( attribute, operator, value );
this._change();
return this;
};
/**
* Ensure a facet refinement exists
* @param {string} facet the facet to refine

@@ -86,4 +111,4 @@ * @param {string} value the associated value

*/
AlgoliaSearchHelper.prototype.removeDisjunctiveRefine = function( facet, value ) {
this.state = this.state.removeDisjunctiveFacetRefinement( facet, value );
AlgoliaSearchHelper.prototype.addRefine = function( facet, value ) {
this.state = this.state.addFacetRefinement( facet, value );
this._change();

@@ -94,10 +119,9 @@ return this;

/**
* Add a numeric refinement on the given attribute
* @param {string} attribute
* @param {string} operator
* @param {number} value
* Ensure a facet exclude exists
* @param {string} facet the facet to refine
* @param {string} value the associated value
* @return {AlgoliaSearchHelper}
*/
AlgoliaSearchHelper.prototype.addNumericRefinement = function( attribute, operator, value ) {
this.state = this.state.addNumericRefinement( attribute, operator, value );
AlgoliaSearchHelper.prototype.addExclude = function( facet, value ) {
this.state = this.state.addExcludeRefinement( facet, value );
this._change();

@@ -108,6 +132,17 @@ return this;

/**
* Add a tag refinement
* @param {string} tag the tag to add to the filter
* @return {AlgoliaSearchHelper}
*/
AlgoliaSearchHelper.prototype.addTag = function( tag ) {
this.state = this.state.addTagRefinement( tag );
this._change();
return this;
};
/**
* Remove a numeric filter.
* @param {string} attribute
* @param {string} operator
* @param {number} value
* @param {string} attribute the attribute on which the numeric filter applies
* @param {string} operator the operator of the filter
* @param {number} value the value of the filter
* @return {AlgoliaSearchHelper}

@@ -121,4 +156,5 @@ */

/**
* Ensure a facet refinement exists
* Ensure a facet refinement does not exist
* @param {string} facet the facet to refine

@@ -128,4 +164,4 @@ * @param {string} value the associated value

*/
AlgoliaSearchHelper.prototype.addRefine = function( facet, value ) {
this.state = this.state.addFacetRefinement( facet, value );
AlgoliaSearchHelper.prototype.removeDisjunctiveRefine = function( facet, value ) {
this.state = this.state.removeDisjunctiveFacetRefinement( facet, value );
this._change();

@@ -148,3 +184,3 @@ return this;

/**
* Ensure a facet exclude exists
* Ensure a facet exclude does not exist
* @param {string} facet the facet to refine

@@ -154,4 +190,4 @@ * @param {string} value the associated value

*/
AlgoliaSearchHelper.prototype.addExclude = function( facet, value ) {
this.state = this.state.addExcludeRefinement( facet, value );
AlgoliaSearchHelper.prototype.removeExclude = function( facet, value ) {
this.state = this.state.removeExcludeRefinement( facet, value );
this._change();

@@ -162,9 +198,8 @@ return this;

/**
* Ensure a facet exclude does not exist
* @param {string} facet the facet to refine
* @param {string} value the associated value
* Ensure that a tag is not filtering the results
* @param {string} tag tag to remove from the filter
* @return {AlgoliaSearchHelper}
*/
AlgoliaSearchHelper.prototype.removeExclude = function( facet, value ) {
this.state = this.state.removeExcludeRefinement( facet, value );
AlgoliaSearchHelper.prototype.removeTag = function( tag ) {
this.state = this.state.removeTagRefinement( tag );
this._change();

@@ -193,6 +228,6 @@ return this;

AlgoliaSearchHelper.prototype.toggleRefine = function( facet, value ) {
if( this.state.facets.indexOf( facet ) > -1 ) {
if( this.state.isConjunctiveFacet( facet ) ) {
this.state = this.state.toggleFacetRefinement( facet, value );
}
else if( this.state.disjunctiveFacets.indexOf( facet ) > -1 ) {
else if( this.state.isDisjunctiveFacet( facet ) ) {
this.state = this.state.toggleDisjunctiveFacetRefinement( facet, value );

@@ -212,2 +247,13 @@ }

/**
* Toggle tag refinement
* @param {string} tag tag to remove or add
* @return {AlgoliaSearchHelper}
*/
AlgoliaSearchHelper.prototype.toggleTag = function( tag ) {
this.state = this.state.toggleTagRefinement( tag );
this._change();
return this;
};
/**
* Go to next page

@@ -253,2 +299,18 @@ * @return {AlgoliaSearchHelper}

/**
* Update any single parameter of the state/configuration (based on SearchParameters).
* @param {string} parameter name of the parameter to update
* @param {any} value new value of the parameter
* @return {AlgoliaSearchHelper}
*/
AlgoliaSearchHelper.prototype.setQueryParameter = function( parameter, value ) {
var newState = this.state.setQueryParameter( parameter, value );
if( this.state === newState ) return this;
this.state = newState;
this._change();
return this;
};
/**
* Set the whole state ( warning : will erase previous state )

@@ -286,3 +348,3 @@ * @param {SearchParameters} newState the whole new state

/**
* Check the refinement state of a facet
* Check the refinement state of a given value for a facet
* @param {string} facet the facet

@@ -293,6 +355,6 @@ * @param {string} value the associated value

AlgoliaSearchHelper.prototype.isRefined = function( facet, value ) {
if( this.state.facets.indexOf( facet ) > -1 ) {
if( this.state.isConjunctiveFacet( facet ) ) {
return this.state.isFacetRefined( facet, value );
}
else if( this.state.disjunctiveFacets.indexOf( facet ) > -1 ) {
else if( this.state.isDisjunctiveFacet( facet ) ) {
return this.state.isDisjunctiveFacetRefined( facet, value );

@@ -304,2 +366,11 @@ }

/**
* Check if the facet has any disjunctive or conjunctive refinements
* @param {string} facet the facet attribute name
* @return {boolean} true if the facet is facetted by at least one value
*/
AlgoliaSearchHelper.prototype.hasRefinements = function( facet ) {
return this.isRefined( facet );
};
/**
* Check the exclude state of a facet

@@ -325,3 +396,13 @@ * @param {string} facet the facet

/**
* Check if the string is a currently filtering tag
* @param {string} tag tag to check
* @return {boolean}
*/
AlgoliaSearchHelper.prototype.isTagRefined = function( tag ) {
return this.state.isTagRefined( tag );
};
/**
* Get the underlying configured index name
* @return {string}
*/

@@ -334,3 +415,3 @@ AlgoliaSearchHelper.prototype.getIndex = function() {

* Get the currently selected page
* @return Number the current page
* @return {number} the current page
*/

@@ -341,2 +422,66 @@ AlgoliaSearchHelper.prototype.getCurrentPage = function() {

/**
* Get all the filtering tags
* @return {string[]}
*/
AlgoliaSearchHelper.prototype.getTags = function() {
return this.state.tagRefinements;
};
/**
* Get a parameter of the search by its name
* @param {string} parameterName the parameter name
* @return {any} the parameter value
*/
AlgoliaSearchHelper.prototype.getQueryParameter = function( parameterName ) {
return this.state.getQueryParameter( parameterName );
};
/**
* Get the list of refinements for a given attribute.
* @param {string} facetName attribute name used for facetting
* @return {Refinement[]} All Refinement are objects that contain a value, and a type. Numeric also contains an operator.
*/
AlgoliaSearchHelper.prototype.getRefinements = function( facetName ) {
var refinements = [];
if( this.state.isConjunctiveFacet( facetName ) ) {
var conjRefinements = this.state.getConjunctiveRefinements( facetName );
forEach( conjRefinements, function( r ) {
refinements.push( {
value : r,
type : "conjunctive"
} );
} );
}
else if( this.state.isDisjunctiveFacet( facetName ) ) {
var disjRefinements = this.state.getDisjunctiveRefinements( facetName );
forEach( disjRefinements, function( r ) {
refinements.push( {
value : r,
type : "disjunctive"
} );
} );
}
var excludeRefinements = this.state.getExcludeRefinements( facetName );
forEach( excludeRefinements, function( r ) {
refinements.push( {
value : r,
type : "exclude"
} );
} );
var numericRefinements = this.state.getNumericRefinements( facetName );
forEach( numericRefinements, function( value, operator ) {
refinements.push( {
value : value,
operator : operator,
type : "numeric"
} );
} );
return refinements;
};
///////////// PRIVATE

@@ -347,2 +492,3 @@

* @private
* @return {undefined}
*/

@@ -369,3 +515,7 @@ AlgoliaSearchHelper.prototype._search = function() {

this.client.search( queries, bind( this._handleResponse, this, state ) );
this.client.search( queries,
bind( this._handleResponse,
this,
state,
this._queryId++ ) );
};

@@ -378,6 +528,15 @@

* @param {SearchParameters} state state used for to generate the request
* @param {number} queryId id of the current request
* @param {Error} err error if any, null otherwise
* @param {object} content content of the response
* @return {undefined}
*/
AlgoliaSearchHelper.prototype._handleResponse = function( state, err, content ) {
AlgoliaSearchHelper.prototype._handleResponse = function( state, queryId, err, content ) {
if( queryId < this._lastQueryIdReceived ) {
// Outdated answer
return;
}
this._lastQueryIdReceived = queryId;
if ( err ) {

@@ -389,3 +548,2 @@ this.emit( "error", err );

var formattedResponse = this.lastResults = new SearchResults( state, content );
this.emit( "result", formattedResponse, state );

@@ -403,10 +561,15 @@ };

var numericFilters = this._getNumericFilters();
var tagFilters = this._getTagFilters();
var additionalParams = {
facets : facets,
distinct : false
tagFilters : tagFilters,
distinct : this.state.distinct || false
};
if( !this.state.query && facetFilters.length === 0 && numericFilters.length === 0 && tagFilters.length === 0 ) {
additionalParams.distinct = false;
}
if( facetFilters.length > 0 ) {
additionalParams.facetFilters = facetFilters;
additionalParams.distinct = this.state.distinct || false;
}

@@ -430,2 +593,3 @@

var numericFilters = this._getNumericFilters( facet );
var tagFilters = this._getTagFilters();
var additionalParams = {

@@ -438,5 +602,10 @@ hitsPerPage : 1,

facets : facet,
distinct : false
tagFilters : tagFilters,
distinct : this.state.distinct || false
};
if( !this.state.query && facetFilters.length === 0 && numericFilters.length === 0 && tagFilters.length === 0 ) {
additionalParams.distinct = false;
}
if( numericFilters.length > 0 ) {

@@ -448,3 +617,2 @@ additionalParams.numericFilters = numericFilters;

additionalParams.facetFilters = facetFilters;
additionalParams.distinct = this.state.distinct || false;
}

@@ -458,3 +626,4 @@

* @private
* @return {array.<string>} the numeric filters in the algolia format
* @param {string} [facetName] the name of the attribute for which the filters should be excluded
* @return {string[]} the numeric filters in the algolia format
*/

@@ -474,4 +643,19 @@ AlgoliaSearchHelper.prototype._getNumericFilters = function( facetName ) {

/**
* Return the tags filters depending
* @private
* @return {string}
*/
AlgoliaSearchHelper.prototype._getTagFilters = function() {
if( this.state.tagFilters ) {
return this.state.tagFilters;
}
return this.state.tagRefinements.join( "," );
};
/**
* Test if there are some disjunctive refinements on the facet
* @private
* @param {string} facet the attribute to test
* @return {boolean}
*/

@@ -487,3 +671,3 @@ AlgoliaSearchHelper.prototype._hasDisjunctiveRefinements = function( facet ) {

* @private
* @param {string} facet if set, the current disjunctive facet
* @param {string} [facet] if set, the current disjunctive facet
* @return {array.<string>}

@@ -490,0 +674,0 @@ */

@@ -6,15 +6,23 @@ "use strict";

var reduce = require( "lodash/collection/reduce" );
var filter = require( "lodash/collection/filter" );
var omit = require( "lodash/object/omit" );
var isEmpty = require( "lodash/lang/isEmpty" );
var isUndefined = require( "lodash/lang/isUndefined" );
var isString = require( "lodash/lang/isString" );
var isFunction = require( "lodash/lang/isFunction" );
var extend = require( "../functions/extend" );
var deepFreeze = require( "../functions/deepFreeze" );
var RefinementList = require( "./RefinementList" );
/**
* @typedef FacetList
* @type {Array.<string>}
*
* @typedef OperatorList
* @type {Object.<string, number>}
* @typedef {string[]} SearchParameters.FacetList
*/
/**
* @typedef {Object.<string, number>} SearchParameters.OperatorList
*/
/**
* SearchParameters is the data structure that contains all the informations

@@ -29,7 +37,12 @@ * usable for making a search to Algolia API. It doesn't do the search itself,

* get it from events generated by the {Helper}.
* If need be, instanciate the Helper from the factory function SearchParameters.make
* @constructor
* @classdesc contains all the parameters of a search
* @param {object|SearchParameters} newParameters existing parameters or partial object for the properties of a new SearchParameters
* @see SearchParameters.make
*/
var SearchParameters = function( newParameters ) {
var params = newParameters || {};
//Query

@@ -41,2 +54,3 @@ /**

this.query = params.query || "";
//Facets

@@ -54,22 +68,37 @@ /**

//Refinements
/** @member {Object.<string, FacetList>}*/
/** @member {Object.<string, SearchParameters.FacetList>}*/
this.facetsRefinements = params.facetsRefinements || {};
/** @member {Object.<string, FacetList>}*/
/** @member {Object.<string, SearchParameters.FacetList>}*/
this.facetsExcludes = params.facetsExcludes || {};
/** @member {Object.<string, FacetList>}*/
/** @member {Object.<string, SearchParameters.FacetList>}*/
this.disjunctiveFacetsRefinements = params.disjunctiveFacetsRefinements || {};
/**
* @member {Object.<string, OperatorList>}
* @member {Object.<string, SearchParameters.OperatorList>}
*/
this.numericRefinements = params.numericRefinements || {};
/**
* Contains the tags used to refine the query
* Associated property in the query : tagFilters
* @see https://www.algolia.com/doc#tagFilters
* @member {string[]}
*/
this.tagRefinements = params.tagRefinements || [];
/**
* Contains the tag filters in the raw format of the Algolia API. Setting this
* parameter is not compatible with the of the add/remove/toggle methods of the
* tag api.
* @member {string}
*/
this.tagFilters = params.tagFilters;
//Misc. parameters
/** @member {number} */
this.hitsPerPage = params.hitsPerPage || 20;
this.hitsPerPage = params.hitsPerPage;
/**
* @member {number}
**/
this.maxValuesPerFacet = params.maxValuesPerFacet || 10;
this.maxValuesPerFacet = params.maxValuesPerFacet;
/** @member {number} */
this.page = params.page || 0;
/**

@@ -170,7 +199,2 @@ * Possible values : prefixAll, prefixLast, prefixNone

/**
* @see https://www.algolia.com/doc#tagFilters
* @member {string}
*/
this.tagFilters = params.tagFilters;
/**
* @see https://www.algolia.com/doc#distinct

@@ -207,2 +231,39 @@ * @member {boolean}

/**
* Factory for SearchParameters
* @param {object|SearchParameters} newParameters existing parameters or partial object for the properties of a new SearchParameters
* @return {SearchParameters} frozen instance of SearchParameters
*/
SearchParameters.make = function makeSearchParameters( newParameters ) {
var instance = new SearchParameters( newParameters );
return deepFreeze( instance );
};
/**
* Validates the new parameters based on the previous state
* @param {SearchParameters} currentState the current state
* @param {object|SearchParameters} parameters the new parameters to set
* @return {Error|null} Error if the modification is invalid, null otherwise
*/
SearchParameters.validate = function( currentState, parameters ) {
var params = parameters || {};
var ks = keys( params );
var unknownKeys = filter( ks, function( k ) {
return !currentState.hasOwnProperty( k );
} );
if( unknownKeys.length === 1 ) return new Error( "Property " + unknownKeys[0] + " is not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" );
if( unknownKeys.length > 1 ) return new Error( "Properties " + unknownKeys.join( " " ) + " are not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" );
if( currentState.tagFilters && params.tagRefinements && params.tagRefinements.length > 0 ) {
return new Error( "[Tags] Can't switch from the managed tag API to the advanced API. It is probably an error, if it's really what you want, you should first clear the tags with clearTags method." );
}
if( currentState.tagRefinements.length > 0 && params.tagFilters ) {
return new Error( "[Tags] Can't switch from the advanced tag API to the managed API. It is probably an error, if it's not, you should first clear the tags with clearTags method." );
}
return null;
};
SearchParameters.prototype = {

@@ -214,15 +275,32 @@ constructor : SearchParameters,

* @method
* @param {string} [name] - If given, name of the facet / attribute on which we want to remove all refinements
* @return {AlgoliaSearchHelper}
* @param {string|SearchParameters.clearCallback} [attribute] optionnal string or function
* - If not given, means to clear all the filters.
* - If `string`, means to clear all refinements for the `attribute` named filter.
* - If `function`, means to clear all the refinements that return truthy values.
* @return {SearchParameters}
*/
clearRefinements : function clearRefinements( name ) {
return this.mutateMe( function( m ) {
m.page = 0;
m._clearNumericRefinements( name );
m._clearFacetRefinements( name );
m._clearExcludeRefinements( name );
m._clearDisjunctiveFacetRefinements( name );
clearRefinements : function clearRefinements( attribute ) {
return this.setQueryParameters( {
page : 0,
numericRefinements : this._clearNumericRefinements( attribute ),
facetsRefinements : RefinementList.clearRefinement( this.facetsRefinements, attribute, "conjunctiveFacet" ),
facetsExcludes : RefinementList.clearRefinement( this.facetsExcludes, attribute, "exclude" ),
disjunctiveFacetsRefinements : RefinementList.clearRefinement( this.disjunctiveFacetsRefinements, attribute, "disjunctiveFacet" )
} );
},
/**
* Remove all the refined tags from the SearchParameters
* @method
* @return {SearchParameters}
*/
clearTags : function clearTags() {
if( this.tagFilters === undefined && this.tagRefinements.length === 0 ) return this;
return this.setQueryParameters( {
page : 0,
tagFilters : undefined,
tagRefinements : []
} );
},
/**
* Query setter

@@ -234,5 +312,7 @@ * @method

setQuery : function setQuery( newQuery ) {
return this.mutateMe( function( m ) {
m.query = newQuery;
m.page = 0;
if( newQuery === this.query ) return this;
return this.setQueryParameters( {
query : newQuery,
page : 0
} );

@@ -247,4 +327,6 @@ },

setPage : function setPage( newPage ) {
return this.mutateMe( function( mutable ) {
mutable.page = newPage;
if( newPage === this.page ) return this;
return this.setQueryParameters( {
page : newPage
} );

@@ -260,4 +342,4 @@ },

setFacets : function setFacets( facets ) {
return this.mutateMe( function( m ) {
m.facets = facets;
return this.setQueryParameters( {
facets : facets
} );

@@ -273,4 +355,4 @@ },

setDisjunctiveFacets : function setDisjunctiveFacets( facets ) {
return this.mutateMe( function( m ) {
m.disjunctiveFacets = facets;
return this.setQueryParameters( {
disjunctiveFacets : facets
} );

@@ -286,8 +368,9 @@ },

setHitsPerPage : function setHitsPerPage( n ) {
return this.mutateMe( function( m ) {
m.hitsPerPage = n;
m.page = 0;
if( this.hitsPerPage === n ) return this;
return this.setQueryParameters( {
hitsPerPage : n,
page : 0
} );
},
/**

@@ -297,9 +380,11 @@ * typoTolerance setter

* @method
* @param {string} s string new value of typoTolerance ("true", "false", "min" or "strict")
* @param {string} typoTolerance new value of typoTolerance ("true", "false", "min" or "strict")
* @return {SearchParameters}
*/
setTypoTolerance : function setTypoTolerance( s ) {
return this.mutateMe( function( m ) {
m.typoTolerance = s;
m.page = 0;
setTypoTolerance : function setTypoTolerance( typoTolerance ) {
if( this.typoTolerance === typoTolerance ) return this;
return this.setQueryParameters( {
typoTolerance : typoTolerance,
page : 0
} );

@@ -316,13 +401,41 @@ },

* @param {number} value value of the filter
* @return {SearchParameters}
*/
addNumericRefinement : function( attribute, operator, value ) {
return this.mutateMe( function( m ) {
m.page = 0;
if( !m.numericRefinements[ attribute ] ) {
m.numericRefinements[ attribute ] = {};
}
m.numericRefinements[ attribute ][ operator ] = value;
if( this.isNumericRefined( attribute, operator, value ) ) return this;
var mod = extend( {}, this.numericRefinements );
mod[ attribute ] = extend( {}, mod[ attribute ] );
mod[ attribute ][ operator ] = value;
return this.setQueryParameters( {
page : 0,
numericRefinements : mod
} );
},
/**
* Get the list of conjunctive refinements for a single facet
* @param {string} facetName name of the attribute used for facetting
* @return {string[]} list of refinements
*/
getConjunctiveRefinements : function( facetName ) {
return this.facetsRefinements[ facetName ] || [];
},
/**
* Get the list of disjunctive refinements for a single facet
* @param {string} facetName name of the attribute used for facetting
* @return {string[]} list of refinements
*/
getDisjunctiveRefinements : function( facetName ) {
return this.disjunctiveFacetsRefinements[ facetName ] || [];
},
/**
* Get the list of exclude refinements for a single facet
* @param {string} facetName name of the attribute used for facetting
* @return {string[]} list of refinements
*/
getExcludeRefinements : function( facetName ) {
return this.facetsExcludes[ facetName ] || [];
},
/**
* Remove a numeric filter

@@ -332,18 +445,23 @@ * @method

* @param {string} operator operator of the filter ( possible values : =, >, >=, <, <=, != )
* @return {SearchParameters}
*/
removeNumericRefinement : function( attribute, operator ) {
return this.mutateMe( function( m ) {
if( m.numericRefinements[ attribute ] ) {
m.page = 0;
var value = m.numericRefinements[ attribute ][ operator ];
if( !isUndefined( value ) ) {
delete m.numericRefinements[ attribute ][ operator ];
if( isEmpty( m.numericRefinements[ attribute ] ) ) {
delete m.numericRefinements[ attribute ];
}
}
}
if( !this.isNumericRefined( attribute, operator ) ) return this;
return this.setQueryParameters( {
page : 0,
numericRefinements : this._clearNumericRefinements( function( value, key ) {
return key === attribute && value.op === operator;
} )
} );
},
/**
* Get the list of numeric refinements for a single facet
* @param {string} facetName name of the attribute used for facetting
* @return {SearchParameters.OperatorList[]} list of refinements
*/
getNumericRefinements : function( facetName ) {
return this.numericRefinements[ facetName ] || [];
},
/**
* Return the current refinement for the ( attribute, operator )

@@ -361,15 +479,25 @@ * @param {string} attribute of the record

* @private
* @param {string} [attribute] -
* @param {string|SearchParameters.clearCallback} [attribute] optionnal string or function
* - If not given, means to clear all the filters.
* - If `string`, means to clear all refinements for the `attribute` named filter.
* - If `function`, means to clear all the refinements that return truthy values.
* @return {Object.<string, OperatorList>}
*/
_clearNumericRefinements : function _clearNumericRefinements( attribute ) {
if ( isUndefined( attribute ) ) {
this.numericRefinements = {};
return {};
}
else if ( isString( attribute ) ) {
if ( !isUndefined( this.numericRefinements[ attribute ] ) ) {
delete this.numericRefinements[ attribute ];
}
return omit( this.numericRefinements, attribute );
}
else if ( isFunction( attribute ) ) {
return reduce( this.numericRefinements, function( memo, operators, key ) {
var operatorList = omit( operators, function( value, operator ) {
return attribute( { val : value, op : operator }, key, "numeric" );
} );
if( !isEmpty( operatorList ) ) memo[ key ] = operatorList;
return memo;
}, {} );
}
},

@@ -384,12 +512,6 @@ /**

addFacetRefinement : function addFacetRefinement( facet, value ) {
if( this.isFacetRefined( facet, value ) ) {
return this;
}
return this.mutateMe( function( m ) {
m.page = 0;
if( !m.facetsRefinements[ facet ] ) {
m.facetsRefinements[ facet ] = [];
}
m.facetsRefinements[ facet ].push( value );
if( RefinementList.isRefined( this.facetsRefinements, facet, value ) ) return this;
return this.setQueryParameters( {
page : 0,
facetsRefinements : RefinementList.addRefinement( this.facetsRefinements, facet, value )
} );

@@ -405,8 +527,6 @@ },

addExcludeRefinement : function addExcludeRefinement( facet, value ) {
return this.mutateMe( function( m ) {
m.page = 0;
if( !m.facetsExcludes[ facet ] ) {
m.facetsExcludes[ facet ] = [];
}
m.facetsExcludes[ facet ].push( value );
if( RefinementList.isRefined( this.facetsExcludes, facet, value ) ) return this;
return this.setQueryParameters( {
page : 0,
facetsExcludes : RefinementList.addRefinement( this.facetsExcludes, facet, value )
} );

@@ -422,11 +542,24 @@ },

addDisjunctiveFacetRefinement : function addDisjunctiveFacetRefinement( facet, value ) {
return this.mutateMe( function( m ) {
m.page = 0;
if( !m.disjunctiveFacetsRefinements[ facet ] ) {
m.disjunctiveFacetsRefinements[ facet ] = [];
}
m.disjunctiveFacetsRefinements[ facet ].push( value );
if( RefinementList.isRefined( this.disjunctiveFacetsRefinements, facet, value ) ) return this;
return this.setQueryParameters( {
page : 0,
disjunctiveFacetsRefinements : RefinementList.addRefinement( this.disjunctiveFacetsRefinements, facet, value )
} );
},
/**
* addTagRefinement adds a tag to the list used to filter the results
* @param {string} tag tag to be added
* @return {SearchParameters}
*/
addTagRefinement : function addTagRefinement( tag ) {
if( this.isTagRefined( tag ) ) return this;
var modification = {
page : 0,
tagRefinements : this.tagRefinements.concat( tag )
};
return this.setQueryParameters( modification );
},
/**
* Remove a refinement set on facet. If a value is provided, it will clear the

@@ -436,21 +569,12 @@ * refinement for the given value, otherwise it will clear all the refinement

* @method
* @param {string} facet
* @param {string} value
* @param {string} facet name of the attribute used for facetting
* @param {string} value value used to filter
* @return {SearchParameters}
*/
removeFacetRefinement : function removeFacetRefinement( facet, value ) {
return this.mutateMe( function( m ) {
m.page = 0;
if( value ) {
var idx = m.facetsRefinements[ facet ].indexOf( value );
if( idx > -1 ) {
m.facetsRefinements[ facet ].splice( idx, 1 );
if( m.facetsRefinements[ facet ].length === 0 ) {
delete m.facetsRefinements[ facet ];
}
}
}
else {
m._clearFacetRefinements( facet );
}
if( !RefinementList.isRefined( this.facetsRefinements, facet, value ) ) return this;
return this.setQueryParameters( {
page : 0,
facetsRefinements : RefinementList.removeRefinement( this.facetsRefinements, facet, value )
} );

@@ -461,18 +585,12 @@ },

* @method
* @param {string} facet
* @param {string} value
* @param {string} facet name of the attribute used for facetting
* @param {string} value value used to filter
* @return {SearchParameters}
*/
removeExcludeRefinement : function removeExcludeRefinement( facet, value ) {
return this.mutateMe( function( m ) {
if( m.facetsExcludes[ facet ] ) {
m.page = 0;
var idx = m.facetsExcludes[ facet ].indexOf( value );
if( idx > -1 ) {
m.facetsExcludes[ facet ].splice( idx, 1 );
if( m.facetsExcludes[ facet ].length === 0 ) {
delete m.facetsExcludes[ facet ];
}
}
}
if( !RefinementList.isRefined( this.facetsExcludes, facet, value ) ) return this;
return this.setQueryParameters( {
page : 0,
facetsExcludes : RefinementList.removeRefinement( this.facetsExcludes, facet, value )
} );

@@ -483,73 +601,55 @@ },

* @method
* @param {string} facet
* @param {string} value
* @param {string} facet name of the attribute used for facetting
* @param {string} value value used to filter
* @return {SearchParameters}
*/
removeDisjunctiveFacetRefinement : function removeDisjunctiveFacetRefinement( facet, value ) {
return this.mutateMe( function( m ) {
if( m.disjunctiveFacetsRefinements[ facet ] ) {
m.page = 0;
var idx = m.disjunctiveFacetsRefinements[ facet ].indexOf( value );
if( idx > -1 ) {
m.disjunctiveFacetsRefinements[ facet ].splice( idx, 1 );
if( m.disjunctiveFacetsRefinements[facet].length === 0 ) {
delete m.disjunctiveFacetsRefinements[ facet ];
}
}
}
if( !RefinementList.isRefined( this.disjunctiveFacetsRefinements, facet, value ) ) return this;
return this.setQueryParameters( {
page : 0,
disjunctiveFacetsRefinements : RefinementList.removeRefinement( this.disjunctiveFacetsRefinements, facet, value )
} );
},
/**
* Clear the facet refinements
* Remove a tag from the list of tag refinements
* @method
* @private
* @param {string} [facet] -
* - If not given, means to clear the refinement of all facets.
* - If `string`, means to clear the refinement for the `facet` named facet.
* @param {string} tag the tag to remove
* @return {SearchParameters}
*/
_clearFacetRefinements : function _clearFacetRefinements( facet ) {
if ( isUndefined( facet ) ) {
this.facetsRefinements = {};
}
else if ( isString( facet ) ) {
if ( !isUndefined( this.facetsRefinements[ facet ] ) ) {
delete this.facetsRefinements[ facet ];
}
}
removeTagRefinement : function removeTagRefinement( tag ) {
if( !this.isTagRefined( tag ) ) return this;
var modification = {
page : 0,
tagRefinements : filter( this.tagRefinements, function( t ) { return t !== tag; } )
};
return this.setQueryParameters( modification );
},
/**
* Clear the exclude refinements
* Switch the refinement applied over a facet/value
* @method
* @private
* @param {string} [facet] -
* - If not given, means to clear all the excludes of all facets.
* - If `string`, means to clear all the excludes for the `facet` named facet.
* @param {string} facet name of the attribute used for facetting
* @param {value} value value used for filtering
* @return {SearchParameters}
*/
_clearExcludeRefinements : function _clearExcludeRefinements( facet ) {
if ( isUndefined( facet ) ) {
this.facetsExcludes = {};
}
else if ( isString( facet ) ) {
if ( !isUndefined( this.facetsExcludes[ facet ] ) ) {
delete this.facetsExcludes[ facet ];
}
}
toggleFacetRefinement : function toggleFacetRefinement( facet, value ) {
return this.setQueryParameters( {
page : 0,
facetsRefinements : RefinementList.toggleRefinement( this.facetsRefinements, facet, value )
} );
},
/**
* Clear the disjunctive refinements
* Switch the refinement applied over a facet/value
* @method
* @private
* @param {string} [facet] -
* - If not given, means to clear all the refinements of all disjunctive facets.
* - If `string`, means to clear all the refinements for the `facet` named facet.
* @param {string} facet name of the attribute used for facetting
* @param {value} value value used for filtering
* @return {SearchParameters}
*/
_clearDisjunctiveFacetRefinements : function _clearDisjunctiveFacetRefinements( facet ) {
if ( isUndefined( facet ) ) {
this.disjunctiveFacetsRefinements = {};
}
else if ( isString( facet ) ) {
if ( !isUndefined( this.disjunctiveFacetsRefinements[ facet ] ) ) {
delete this.disjunctiveFacetsRefinements[ facet ];
}
}
toggleExcludeFacetRefinement : function toggleExcludeFacetRefinement( facet, value ) {
return this.setQueryParameters( {
page : 0,
facetsExcludes : RefinementList.toggleRefinement( this.facetsExcludes, facet, value )
} );
},

@@ -559,85 +659,116 @@ /**

* @method
* @param {string} facet
* @param {value} value
* @param {string} facet name of the attribute used for facetting
* @param {value} value value used for filtering
* @return {SearchParameters}
*/
toggleFacetRefinement : function toggleFacetRefinement( facet, value ) {
if( this.isFacetRefined( facet, value ) ) {
return this.removeFacetRefinement( facet, value );
}
else {
return this.addFacetRefinement( facet, value );
}
toggleDisjunctiveFacetRefinement : function toggleDisjunctiveFacetRefinement( facet, value ) {
return this.setQueryParameters( {
page : 0,
disjunctiveFacetsRefinements : RefinementList.toggleRefinement( this.disjunctiveFacetsRefinements, facet, value )
} );
},
/**
* Switch the refinement applied over a facet/value
* Switch the tag refinement
* @method
* @param {string} facet
* @param {value} value
* @param {string} tag the tag to remove or add
* @return {SearchParameters}
*/
toggleExcludeFacetRefinement : function toggleExcludeFacetRefinement( facet, value ) {
if( this.isExcludeRefined( facet, value ) ) {
return this.removeExcludeRefinement( facet, value );
toggleTagRefinement : function toggleTagRefinement( tag ) {
if( this.isTagRefined( tag ) ) {
return this.removeTagRefinement( tag );
}
else {
return this.addExcludeRefinement( facet, value );
return this.addTagRefinement( tag );
}
},
/**
* Switch the refinement applied over a facet/value
* Test if the facet name is from one of the disjunctive facets
* @method
* @param {string} facet
* @param {value} value
* @return {SearchParameters}
* @param {string} facet facet name to test
* @return {boolean}
*/
toggleDisjunctiveFacetRefinement : function toggleDisjunctiveFacetRefinement( facet, value ) {
if( this.isDisjunctiveFacetRefined( facet, value ) ) {
return this.removeDisjunctiveFacetRefinement( facet, value );
}
else {
return this.addDisjunctiveFacetRefinement( facet, value );
}
isDisjunctiveFacet : function( facet ) {
return this.disjunctiveFacets.indexOf( facet ) > -1;
},
/**
* Returns true if the couple (facet, value) is refined
* Test if the facet name is from one of the conjunctive/normal facets
* @method
* @param {string} facet
* @param {string} value
* @param {string} facet facet name to test
* @return {boolean}
*/
isConjunctiveFacet : function( facet ) {
return this.facets.indexOf( facet ) > -1;
},
/**
* Returns true if the facet is refined, either for a specific value or in
* general.
* @method
* @param {string} facet name of the attribute for used for facetting
* @param {string} value, optionnal value. If passed will test that this value
* is filtering the given facet.
* @return {boolean} returns true if refined
*/
isFacetRefined : function isFacetRefined( facet, value ) {
return this.facetsRefinements[ facet ] &&
this.facetsRefinements[ facet ].indexOf( value ) !== -1;
return RefinementList.isRefined( this.facetsRefinements, facet, value );
},
/**
* Returns true if the couple (facet, value) is excluded
* Returns true if the facet contains exclusions or if a specific value is
* excluded
* @method
* @param {string} facet
* @param {string} value
* @return {boolean}
* @param {string} facet name of the attribute for used for facetting
* @param {string} value, optionnal value. If passed will test that this value
* is filtering the given facet.
* @return {boolean} returns true if refined
*/
isExcludeRefined : function isExcludeRefined( facet, value ) {
return this.facetsExcludes[ facet ] &&
this.facetsExcludes[ facet ].indexOf( value ) !== -1;
return RefinementList.isRefined( this.facetsExcludes, facet, value );
},
/**
* Returns true if the couple (facet, value) is refined
* Returns true if the facet contains a refinement, or if a value passed is a
* refinement for the facet.
* @method
* @param {string} facet
* @param {string} value
* @param {string} facet name of the attribute for used for facetting
* @param {string} value optionnal, will test if the value is used for refinement
* if there is one, otherwise will test if the facet contains any refinement
* @return {boolean}
*/
isDisjunctiveFacetRefined : function isDisjunctiveFacetRefined( facet, value ) {
return this.disjunctiveFacetsRefinements[ facet ] &&
this.disjunctiveFacetsRefinements[ facet ].indexOf( value ) !== -1;
return RefinementList.isRefined( this.disjunctiveFacetsRefinements, facet, value );
},
/**
* Test if the triple attribute operator value is already refined.
* @method
* @param {string} attribute attribute for which the refinement is applied
* @param {string} operator operator of the refinement
* @param {string} value value of the refinement
* @return {boolean} true if it is refined
*/
isNumericRefined : function isNumericRefined( attribute, operator, value ) {
if( isUndefined( value ) ) {
return this.numericRefinements[ attribute ] &&
!isUndefined( this.numericRefinements[ attribute ][ operator ] );
}
return this.numericRefinements[ attribute ] &&
!( isUndefined( this.numericRefinements[ attribute ][ operator ] ) ) &&
this.numericRefinements[ attribute ][ operator ] === value;
},
/**
* Returns true if the tag refined, false otherwise
* @method
* @param {string} tag the tag to check
* @return {boolean}
*/
isTagRefined : function isTagRefined( tag ) {
return this.tagRefinements.indexOf( tag ) !== -1;
},
/**
* Returns the list of all disjunctive facets refined
* @method
* @param {string} facet
* @param {value} value
* @param {string} facet name of the attribute used for facetting
* @param {value} value value used for filtering
* @return {string[]}
*/
getRefinedDisjunctiveFacets : function getRefinedDisjunctiveFacets() {
// attributes used for numeric filter can also be disjunctive
var disjunctiveNumericRefinedFacets = intersection(

@@ -655,10 +786,6 @@ keys( this.numericRefinements ),

getUnrefinedDisjunctiveFacets : function() {
var unrefinedFacets = [];
var refinedFacets = this.getRefinedDisjunctiveFacets();
forEach( this.disjunctiveFacets, function( f ) {
if( refinedFacets.indexOf( f ) === -1 ) {
unrefinedFacets.push( f );
}
return filter( this.disjunctiveFacets, function( f ) {
return refinedFacets.indexOf( f ) === -1;
} );
return unrefinedFacets;
},

@@ -668,3 +795,3 @@ managedParameters : [

"facetsExcludes", "disjunctiveFacetsRefinements",
"numericRefinements"
"numericRefinements", "tagRefinements"
],

@@ -682,13 +809,72 @@ getQueryParams : function getQueryParams() {

/**
* Let the user retrieve any parameter value from the SearchParameters
* @param {string} paramName name of the parameter
* @return {any} the value of the parameter
*/
getQueryParameter : function getQueryParameter( paramName ) {
if( !this.hasOwnProperty( paramName ) ) throw new Error( "Parameter '" + paramName + "' is not an attribute of SearchParameters (http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html)" );
return this[ paramName ];
},
/**
* Let the user set a specific value for a given parameter. Will return the
* same instance if the parameter is invalid or if the value is the same as the
* previous one.
* @method
* @param {string} parameter the parameter name
* @param {any} value the value to be set, must be compliant with the definition of the attribute on the object
* @return {SearchParameters} the updated state
*/
setQueryParameter : function setParameter( parameter, value ) {
if( this[ parameter ] === value ) return this;
var modification = {};
modification[ parameter ] = value;
return this.setQueryParameters( modification );
},
/**
* Let the user set any of the parameters with a plain object.
* It won't let the user define custom properties.
* @method
* @param {object} params all the keys and the values to be updated
* @return {SearchParameters} a new updated instance
*/
setQueryParameters : function setQueryParameters( params ) {
var error = SearchParameters.validate( this, params );
if( error ) {
throw error;
}
return this.mutateMe( function merge( newInstance ) {
var ks = keys( params );
forEach( ks, function( k ) {
newInstance[ k ] = params[ k ];
} );
return newInstance;
} );
},
/**
* Helper function to make it easier to build new instances from a mutating
* function
* @private
* @param {function} fn newMutableState -> previousState -> () function that will
* change the value of the newMutable to the desired state
* @return {SearchParameters} a new instance with the specified modifications applied
*/
mutateMe : function mutateMe( fn ) {
var newState = new ( this.constructor )( this );
fn( newState );
return Object.freeze( newState );
fn( newState, this );
return deepFreeze( newState );
}
};
/**
* Callback used for clearRefinement method
* @callback SearchParameters.clearCallback
* @param {OperatorList|FacetList} value
* @param {string} key
* @param {string} type numeric, disjunctiveFacet, conjunctiveFacet or exclude
* depending on the type of facet
* @return {boolean}
*/
module.exports = SearchParameters;
"use strict";
var forEach = require( "lodash/collection/forEach" );
var compact = require( "lodash/array/compact" );
var sum = require( "lodash/collection/sum" );
var find = require( "lodash/collection/find" );

@@ -9,3 +10,3 @@

/**
* @typedef Facet
* @typedef SearchResults.Facet
* @type {object}

@@ -79,3 +80,3 @@ * @property {string} name name of the attribute in the record

*/
this.processingTimeMS = mainSubResponse.processingTimeMS;
this.processingTimeMS = sum( algoliaResponse.results, "processingTimeMS" );
/**

@@ -173,3 +174,3 @@ * disjunctive facets results

* @param {string} name name of the attribute facetted
* @return {Facet} the facet object
* @return {SearchResults.Facet} the facet object
*/

@@ -176,0 +177,0 @@ SearchResults.prototype.getFacetByName = function( name ) {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc