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

Commit

Permalink
Merge pull request #90 from algolia/feature/mergeSearchParameters
Browse files Browse the repository at this point in the history
FIX #76 #84 Modify search parameters easily
  • Loading branch information
bobylito committed Jun 2, 2015
2 parents 4d33784 + ed5c746 commit 795f9ca
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
CHANGELOG

UNRELEASED
* FEATURE : Ability to modify any parameter of the state easily (#76 #84)
* FEATURE : #69 Ability to know if a facet is refined, whatever the value

2.0.4
Expand Down
148 changes: 128 additions & 20 deletions dist/algoliasearch.helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4522,36 +4522,78 @@ SearchParameters.prototype = {
}
},
/**
* Returns true if the couple (facet, value) is refined
* Test if the facet name is from one of the disjunctive facets
* @method
* @param {string} facet
* @param {string} value
* @return {boolean}
* @param {string} facet facet name to test
* @return boolean
*/
isDisjunctiveFacet : function( facet ) {
return this.disjunctiveFacets.indexOf( facet ) > -1;
},
/**
* Test if the facet name is from one of the conjunctive/normal facets
* @method
* @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 ] &&
var containsRefinements = this.facetsRefinements[ facet ] &&
this.facetsRefinements[ facet ].length > 0;
if( value === undefined ) {
return containsRefinements;
}

return containsRefinements &&
this.facetsRefinements[ facet ].indexOf( value ) !== -1;
},
/**
* 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 ] &&
var containsRefinements = this.facetsExcludes[ facet ] &&
this.facetsExcludes[ facet ].length > 0;
if( value === undefined ) {
return containsRefinements;
}

return containsRefinements &&
this.facetsExcludes[ facet ].indexOf( value ) !== -1;
},
/**
* 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 ] &&
var containsRefinements = this.disjunctiveFacetsRefinements[ facet ] &&
this.disjunctiveFacetsRefinements[ facet ].length > 0;
if( value === undefined ) {
return containsRefinements;
}

return containsRefinements &&
this.disjunctiveFacetsRefinements[ facet ].indexOf( value ) !== -1;
},
/**
Expand Down Expand Up @@ -4607,6 +4649,47 @@ SearchParameters.prototype = {
var newState = new ( this.constructor )( this );
fn( newState );
return Object.freeze( newState );
},
/**
* 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 ) {
var k = keys( this );
if( k.indexOf( parameter ) === -1 ) {
throw new Error( "Property " + k + " is not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" );
}
if( this[ parameter ] === value ) return this;

return this.mutateMe( function updateParameter( newState ) {
newState[ parameter ] = value;
return newState;
} );
},
/**
* 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 ) {
return this.mutateMe( function merge( newInstance ) {
var ks = keys( params );
forEach( ks, function( k ) {
if( !newInstance.hasOwnProperty( k ) ) {
throw new Error( "Property " + k + " is not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" );
}

newInstance[ k ] = params[ k ];
} );
return newInstance;
} );
}
};

Expand Down Expand Up @@ -4974,10 +5057,10 @@ AlgoliaSearchHelper.prototype.toggleExclude = function( facet, value ) {
* @return {AlgoliaSearchHelper}
*/
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 );
}
else {
Expand Down Expand Up @@ -5031,6 +5114,22 @@ AlgoliaSearchHelper.prototype.setIndex = function( name ) {
return this;
};

/**
* 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 )
* @param {SearchParameters} newState the whole new state
Expand Down Expand Up @@ -5064,21 +5163,30 @@ AlgoliaSearchHelper.prototype.overrideStateWithoutTriggeringChangeEvent = functi
};

/**
* Check the refinement state of a facet
* Check the refinement state of a given value for a facet
* @param {string} facet the facet
* @param {string} value the associated value
* @return {boolean} true if refined
*/
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 );
}
return false;
};

/**
* 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
* @param {string} facet the facet
Expand Down Expand Up @@ -5303,4 +5411,4 @@ module.exports = function extend( out ) {
};

},{}]},{},[1])(1)
});
});
41 changes: 41 additions & 0 deletions src/SearchParameters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,47 @@ SearchParameters.prototype = {
var newState = new ( this.constructor )( this );
fn( newState );
return Object.freeze( newState );
},
/**
* 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 ) {
var k = keys( this );
if( k.indexOf( parameter ) === -1 ) {
throw new Error( "Property " + k + " is not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" );
}
if( this[ parameter ] === value ) return this;

return this.mutateMe( function updateParameter( newState ) {
newState[ parameter ] = value;
return newState;
} );
},
/**
* 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 ) {
return this.mutateMe( function merge( newInstance ) {
var ks = keys( params );
forEach( ks, function( k ) {
if( !newInstance.hasOwnProperty( k ) ) {
throw new Error( "Property " + k + " is not defined on SearchParameters (see http://algolia.github.io/algoliasearch-helper-js/docs/SearchParameters.html )" );
}

newInstance[ k ] = params[ k ];
} );
return newInstance;
} );
}
};

Expand Down
16 changes: 16 additions & 0 deletions src/algoliasearch.helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,22 @@ AlgoliaSearchHelper.prototype.setIndex = function( name ) {
return this;
};

/**
* 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 )
* @param {SearchParameters} newState the whole new state
Expand Down
54 changes: 54 additions & 0 deletions test/spec/SearchParameters.setQueryParameter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use strict";
var test = require( "tape" );
var SearchParameters = require( "../../src/SearchParameters" );

test( "setqueryparameter should update existing parameter", function( t ) {
var sp = new SearchParameters( {
facets : ["facet"]
} );

var newValue = [];
var newsp = sp.setQueryParameter( "facets", newValue );

t.equal( newsp.facets, newValue, "update of an existing parameter" );

t.end();
} );

test( "setqueryparameter should add non-existing parameter", function( t ) {
var sp = new SearchParameters( {
facets : ["facet"]
} );

var newValue = [ "attributesToHighlight" ];
var newsp = sp.setQueryParameter( "attributesToHighlight", newValue );

t.equal( newsp.attributesToHighlight, newValue, "add new parameter" );

t.end();
} );

test( "setQueryParameter should not create a new instance if the update is non effective", function( t ) {
var sp = new SearchParameters( {
facets : ["facet"],
maxValuesPerFacet : 10
} );

var newValue = 10;
var newsp = sp.setQueryParameter( "maxValuesPerFacet", newValue );

t.equal( newsp, sp, "No change should result in the same instance" );

t.end();
} );

test( "setQueryParameter should throw an error when trying to add an unknown parameter", function( t ) {
var sp = new SearchParameters( {
facets : ["facet"]
} );

t.throws( sp.setQueryParameter.bind( sp, "unknown", "" ),
"Unknown parameter should throw an exception" );

t.end();
} );
43 changes: 43 additions & 0 deletions test/spec/SearchParameters.setQueryParameters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use strict";
var test = require( "tape" );
var SearchParameters = require( "../../src/SearchParameters" );

test( "setQueryParameters should be able to mix an actual state with a new set of parameters", function( t ) {
var originalSP = new SearchParameters( {
facets : [ "a", "b" ],
ignorePlurals : false,
attributesToHighlight : ""
} );

var params = {
facets : [ "a", "c" ],
attributesToHighlight : [ "city", "country" ],
replaceSynonymsInHighlight : true
};
var newSP = originalSP.setQueryParameters( params );

t.equal( newSP.facets, params.facets, "Facets should be updated (existing parameter)" );
t.equal( newSP.attributesToHighlight, newSP.attributesToHighlight, "attributesToHighlight should be updated (existing parameter)" );
t.equal( newSP.replaceSynonymsInHighlight, newSP.replaceSynonymsInHighlight, "replaceSynonymsInHighlight should be updated (new parameter)" );
t.equal( newSP.ignorePlurals, originalSP.ignorePlurals, "ignorePlurals should be the same as the original" );

t.end();
} );

test( "setQueryParameters should not add unknown properties", function( t ) {
var originalSP = new SearchParameters( {
facets : [ "a", "b" ],
ignorePlurals : false,
attributesToHighlight : ""
} );

var params = {
unknow1 : [ "a", "c" ],
facet : [ "city", "country" ]
};

t.throws( originalSP.setQueryParameters.bind( originalSP, params ),
"The new searchParameters should be strictly equal" );

t.end();
} );
Loading

0 comments on commit 795f9ca

Please sign in to comment.