var inherits = require('inherits'); var IndexCore = require('./IndexCore.js'); var deprecate = require('./deprecate.js'); var deprecatedMessage = require('./deprecatedMessage.js'); var exitPromise = require('./exitPromise.js'); var errors = require('./errors'); var deprecateForwardToSlaves = deprecate( function() {}, deprecatedMessage('forwardToSlaves', 'forwardToReplicas') ); module.exports = Index; function Index() { IndexCore.apply(this, arguments); } inherits(Index, IndexCore); /* * Add an object in this index * * @param content contains the javascript object to add inside the index * @param objectID (optional) an objectID you want to attribute to this object * (if the attribute already exist the old object will be overwrite) * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that contains 3 elements: createAt, taskId and objectID */ Index.prototype.addObject = function(content, objectID, callback) { var indexObj = this; if (arguments.length === 1 || typeof objectID === 'function') { callback = objectID; objectID = undefined; } return this.as._jsonRequest({ method: objectID !== undefined ? 'PUT' : // update or create 'POST', // create (API generates an objectID) url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + // create (objectID !== undefined ? '/' + encodeURIComponent(objectID) : ''), // update or create body: content, hostType: 'write', callback: callback }); }; /* * Add several objects * * @param objects contains an array of objects to add * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that updateAt and taskID */ Index.prototype.addObjects = function(objects, callback) { var isArray = require('isarray'); var usage = 'Usage: index.addObjects(arrayOfObjects[, callback])'; if (!isArray(objects)) { throw new Error(usage); } var indexObj = this; var postObj = { requests: [] }; for (var i = 0; i < objects.length; ++i) { var request = { action: 'addObject', body: objects[i] }; postObj.requests.push(request); } return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', body: postObj, hostType: 'write', callback: callback }); }; /* * Update partially an object (only update attributes passed in argument) * * @param partialObject contains the javascript attributes to override, the * object must contains an objectID attribute * @param createIfNotExists (optional) if false, avoid an automatic creation of the object * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that contains 3 elements: createAt, taskId and objectID */ Index.prototype.partialUpdateObject = function(partialObject, createIfNotExists, callback) { if (arguments.length === 1 || typeof createIfNotExists === 'function') { callback = createIfNotExists; createIfNotExists = undefined; } var indexObj = this; var url = '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial'; if (createIfNotExists === false) { url += '?createIfNotExists=false'; } return this.as._jsonRequest({ method: 'POST', url: url, body: partialObject, hostType: 'write', callback: callback }); }; /* * Partially Override the content of several objects * * @param objects contains an array of objects to update (each object must contains a objectID attribute) * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that updateAt and taskID */ Index.prototype.partialUpdateObjects = function(objects, createIfNotExists, callback) { if (arguments.length === 1 || typeof createIfNotExists === 'function') { callback = createIfNotExists; createIfNotExists = true; } var isArray = require('isarray'); var usage = 'Usage: index.partialUpdateObjects(arrayOfObjects[, callback])'; if (!isArray(objects)) { throw new Error(usage); } var indexObj = this; var postObj = { requests: [] }; for (var i = 0; i < objects.length; ++i) { var request = { action: createIfNotExists === true ? 'partialUpdateObject' : 'partialUpdateObjectNoCreate', objectID: objects[i].objectID, body: objects[i] }; postObj.requests.push(request); } return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', body: postObj, hostType: 'write', callback: callback }); }; /* * Override the content of object * * @param object contains the javascript object to save, the object must contains an objectID attribute * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that updateAt and taskID */ Index.prototype.saveObject = function(object, callback) { var indexObj = this; return this.as._jsonRequest({ method: 'PUT', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID), body: object, hostType: 'write', callback: callback }); }; /* * Override the content of several objects * * @param objects contains an array of objects to update (each object must contains a objectID attribute) * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that updateAt and taskID */ Index.prototype.saveObjects = function(objects, callback) { var isArray = require('isarray'); var usage = 'Usage: index.saveObjects(arrayOfObjects[, callback])'; if (!isArray(objects)) { throw new Error(usage); } var indexObj = this; var postObj = { requests: [] }; for (var i = 0; i < objects.length; ++i) { var request = { action: 'updateObject', objectID: objects[i].objectID, body: objects[i] }; postObj.requests.push(request); } return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', body: postObj, hostType: 'write', callback: callback }); }; /* * Delete an object from the index * * @param objectID the unique identifier of object to delete * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that contains 3 elements: createAt, taskId and objectID */ Index.prototype.deleteObject = function(objectID, callback) { if (typeof objectID === 'function' || typeof objectID !== 'string' && typeof objectID !== 'number') { var err = new errors.AlgoliaSearchError( objectID && typeof objectID !== 'function' ? 'ObjectID must be a string' : 'Cannot delete an object without an objectID' ); callback = objectID; if (typeof callback === 'function') { return callback(err); } return this.as._promise.reject(err); } var indexObj = this; return this.as._jsonRequest({ method: 'DELETE', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID), hostType: 'write', callback: callback }); }; /* * Delete several objects from an index * * @param objectIDs contains an array of objectID to delete * @param callback (optional) the result callback called with two arguments: * error: null or Error('message') * content: the server answer that contains 3 elements: createAt, taskId and objectID */ Index.prototype.deleteObjects = function(objectIDs, callback) { var isArray = require('isarray'); var map = require('./map.js'); var usage = 'Usage: index.deleteObjects(arrayOfObjectIDs[, callback])'; if (!isArray(objectIDs)) { throw new Error(usage); } var indexObj = this; var postObj = { requests: map(objectIDs, function prepareRequest(objectID) { return { action: 'deleteObject', objectID: objectID, body: { objectID: objectID } }; }) }; return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch', body: postObj, hostType: 'write', callback: callback }); }; /* * Delete all objects matching a query * * @param query the query string * @param params the optional query parameters * @param callback (optional) the result callback called with one argument * error: null or Error('message') * @deprecated see index.deleteBy */ Index.prototype.deleteByQuery = deprecate(function(query, params, callback) { var clone = require('./clone.js'); var map = require('./map.js'); var indexObj = this; var client = indexObj.as; if (arguments.length === 1 || typeof params === 'function') { callback = params; params = {}; } else { params = clone(params); } params.attributesToRetrieve = 'objectID'; params.hitsPerPage = 1000; params.distinct = false; // when deleting, we should never use cache to get the // search results this.clearCache(); // there's a problem in how we use the promise chain, // see how waitTask is done var promise = this .search(query, params) .then(stopOrDelete); function stopOrDelete(searchContent) { // stop here if (searchContent.nbHits === 0) { // return indexObj.as._request.resolve(); return searchContent; } // continue and do a recursive call var objectIDs = map(searchContent.hits, function getObjectID(object) { return object.objectID; }); return indexObj .deleteObjects(objectIDs) .then(waitTask) .then(doDeleteByQuery); } function waitTask(deleteObjectsContent) { return indexObj.waitTask(deleteObjectsContent.taskID); } function doDeleteByQuery() { return indexObj.deleteByQuery(query, params); } if (!callback) { return promise; } promise.then(success, failure); function success() { exitPromise(function exit() { callback(null); }, client._setTimeout || setTimeout); } function failure(err) { exitPromise(function exit() { callback(err); }, client._setTimeout || setTimeout); } }, deprecatedMessage('index.deleteByQuery()', 'index.deleteBy()')); /** * Delete all objects matching a query * * the query parameters that can be used are: * - filters (numeric, facet, tag) * - geo * * you can not send an empty query or filters * * @param params the optional query parameters * @param callback (optional) the result callback called with one argument * error: null or Error('message') */ Index.prototype.deleteBy = function(params, callback) { var indexObj = this; return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/deleteByQuery', body: {params: indexObj.as._getSearchParams(params, '')}, hostType: 'write', callback: callback }); }; /* * Browse all content from an index using events. Basically this will do * .browse() -> .browseFrom -> .browseFrom -> .. until all the results are returned * * @param {string} query - The full text query * @param {Object} [queryParameters] - Any search query parameter * @return {EventEmitter} * @example * var browser = index.browseAll('cool songs', { * tagFilters: 'public,comments', * hitsPerPage: 500 * }); * * browser.on('result', function resultCallback(content) { * console.log(content.hits); * }); * * // if any error occurs, you get it * browser.on('error', function(err) { * throw err; * }); * * // when you have browsed the whole index, you get this event * browser.on('end', function() { * console.log('finished'); * }); * * // at any point if you want to stop the browsing process, you can stop it manually * // otherwise it will go on and on * browser.stop(); * * @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation} */ Index.prototype.browseAll = function(query, queryParameters) { if (typeof query === 'object') { queryParameters = query; query = undefined; } var merge = require('./merge.js'); var IndexBrowser = require('./IndexBrowser'); var browser = new IndexBrowser(); var client = this.as; var index = this; var params = client._getSearchParams( merge({}, queryParameters || {}, { query: query }), '' ); // start browsing browseLoop(); function browseLoop(cursor) { if (browser._stopped) { return; } var body; if (cursor !== undefined) { body = { cursor: cursor }; } else { body = { params: params }; } client._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(index.indexName) + '/browse', hostType: 'read', body: body, callback: browseCallback }); } function browseCallback(err, content) { if (browser._stopped) { return; } if (err) { browser._error(err); return; } browser._result(content); // no cursor means we are finished browsing if (content.cursor === undefined) { browser._end(); return; } browseLoop(content.cursor); } return browser; }; /* * Get a Typeahead.js adapter * @param searchParams contains an object with query parameters (see search for details) */ Index.prototype.ttAdapter = deprecate(function(params) { var self = this; return function ttAdapter(query, syncCb, asyncCb) { var cb; if (typeof asyncCb === 'function') { // typeahead 0.11 cb = asyncCb; } else { // pre typeahead 0.11 cb = syncCb; } self.search(query, params, function searchDone(err, content) { if (err) { cb(err); return; } cb(content.hits); }); }; }, 'ttAdapter is not necessary anymore and will be removed in the next version,\n' + 'have a look at autocomplete.js (https://github.com/algolia/autocomplete.js)'); /* * Wait the publication of a task on the server. * All server task are asynchronous and you can check with this method that the task is published. * * @param taskID the id of the task returned by server * @param callback the result callback with with two arguments: * error: null or Error('message') * content: the server answer that contains the list of results */ Index.prototype.waitTask = function(taskID, callback) { // wait minimum 100ms before retrying var baseDelay = 100; // wait maximum 5s before retrying var maxDelay = 5000; var loop = 0; // waitTask() must be handled differently from other methods, // it's a recursive method using a timeout var indexObj = this; var client = indexObj.as; var promise = retryLoop(); function retryLoop() { return client._jsonRequest({ method: 'GET', hostType: 'read', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/task/' + taskID }).then(function success(content) { loop++; var delay = baseDelay * loop * loop; if (delay > maxDelay) { delay = maxDelay; } if (content.status !== 'published') { return client._promise.delay(delay).then(retryLoop); } return content; }); } if (!callback) { return promise; } promise.then(successCb, failureCb); function successCb(content) { exitPromise(function exit() { callback(null, content); }, client._setTimeout || setTimeout); } function failureCb(err) { exitPromise(function exit() { callback(err); }, client._setTimeout || setTimeout); } }; /* * This function deletes the index content. Settings and index specific API keys are kept untouched. * * @param callback (optional) the result callback called with two arguments * error: null or Error('message') * content: the settings object or the error message if a failure occured */ Index.prototype.clearIndex = function(callback) { var indexObj = this; return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear', hostType: 'write', callback: callback }); }; /* * Get settings of this index * * @param opts an object of options to add * @param opts.advanced get more settings like nbShards (useful for Enterprise) * @param callback (optional) the result callback called with two arguments * error: null or Error('message') * content: the settings object or the error message if a failure occurred */ Index.prototype.getSettings = function(opts, callback) { if (arguments.length === 1 && typeof opts === 'function') { callback = opts; opts = {}; } opts = opts || {}; var indexName = encodeURIComponent(this.indexName); return this.as._jsonRequest({ method: 'GET', url: '/1/indexes/' + indexName + '/settings?getVersion=2' + (opts.advanced ? '&advanced=' + opts.advanced : ''), hostType: 'read', callback: callback }); }; Index.prototype.searchSynonyms = function(params, callback) { if (typeof params === 'function') { callback = params; params = {}; } else if (params === undefined) { params = {}; } return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/search', body: params, hostType: 'read', callback: callback }); }; function exportData(method, _hitsPerPage, callback) { function search(page, _previous) { var options = { page: page || 0, hitsPerPage: _hitsPerPage || 100 }; var previous = _previous || []; return method(options).then(function(result) { var hits = result.hits; var nbHits = result.nbHits; var current = hits.map(function(s) { delete s._highlightResult; return s; }); var synonyms = previous.concat(current); if (synonyms.length < nbHits) { return search(options.page + 1, synonyms); } return synonyms; }); } return search().then(function(data) { if (typeof callback === 'function') { callback(data); return undefined; } return data; }); } /** * Retrieve all the synonyms in an index * @param [number=100] hitsPerPage The amount of synonyms to retrieve per batch * @param [function] callback will be called after all synonyms are retrieved */ Index.prototype.exportSynonyms = function(hitsPerPage, callback) { return exportData(this.searchSynonyms.bind(this), hitsPerPage, callback); }; Index.prototype.saveSynonym = function(synonym, opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; return this.as._jsonRequest({ method: 'PUT', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(synonym.objectID) + '?forwardToReplicas=' + forwardToReplicas, body: synonym, hostType: 'write', callback: callback }); }; Index.prototype.getSynonym = function(objectID, callback) { return this.as._jsonRequest({ method: 'GET', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID), hostType: 'read', callback: callback }); }; Index.prototype.deleteSynonym = function(objectID, opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; return this.as._jsonRequest({ method: 'DELETE', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID) + '?forwardToReplicas=' + forwardToReplicas, hostType: 'write', callback: callback }); }; Index.prototype.clearSynonyms = function(opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/clear' + '?forwardToReplicas=' + forwardToReplicas, hostType: 'write', callback: callback }); }; Index.prototype.batchSynonyms = function(synonyms, opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/batch' + '?forwardToReplicas=' + forwardToReplicas + '&replaceExistingSynonyms=' + (opts.replaceExistingSynonyms ? 'true' : 'false'), hostType: 'write', body: synonyms, callback: callback }); }; Index.prototype.searchRules = function(params, callback) { if (typeof params === 'function') { callback = params; params = {}; } else if (params === undefined) { params = {}; } return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/search', body: params, hostType: 'read', callback: callback }); }; /** * Retrieve all the query rules in an index * @param [number=100] hitsPerPage The amount of query rules to retrieve per batch * @param [function] callback will be called after all query rules are retrieved * error: null or Error('message') */ Index.prototype.exportRules = function(hitsPerPage, callback) { return exportData(this.searchRules.bind(this), hitsPerPage, callback); }; Index.prototype.saveRule = function(rule, opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } if (!rule.objectID) { throw new errors.AlgoliaSearchError('Missing or empty objectID field for rule'); } var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; return this.as._jsonRequest({ method: 'PUT', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(rule.objectID) + '?forwardToReplicas=' + forwardToReplicas, body: rule, hostType: 'write', callback: callback }); }; Index.prototype.getRule = function(objectID, callback) { return this.as._jsonRequest({ method: 'GET', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID), hostType: 'read', callback: callback }); }; Index.prototype.deleteRule = function(objectID, opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; return this.as._jsonRequest({ method: 'DELETE', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/' + encodeURIComponent(objectID) + '?forwardToReplicas=' + forwardToReplicas, hostType: 'write', callback: callback }); }; Index.prototype.clearRules = function(opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/clear' + '?forwardToReplicas=' + forwardToReplicas, hostType: 'write', callback: callback }); }; Index.prototype.batchRules = function(rules, opts, callback) { if (typeof opts === 'function') { callback = opts; opts = {}; } else if (opts === undefined) { opts = {}; } var forwardToReplicas = opts.forwardToReplicas === true ? 'true' : 'false'; return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/rules/batch' + '?forwardToReplicas=' + forwardToReplicas + '&clearExistingRules=' + (opts.clearExistingRules === true ? 'true' : 'false'), hostType: 'write', body: rules, callback: callback }); }; /* * Set settings for this index * * @param settigns the settings object that can contains : * - minWordSizefor1Typo: (integer) the minimum number of characters to accept one typo (default = 3). * - minWordSizefor2Typos: (integer) the minimum number of characters to accept two typos (default = 7). * - hitsPerPage: (integer) the number of hits per page (default = 10). * - attributesToRetrieve: (array of strings) default list of attributes to retrieve in objects. * If set to null, all attributes are retrieved. * - attributesToHighlight: (array of strings) default list of attributes to highlight. * If set to null, all indexed attributes are highlighted. * - attributesToSnippet**: (array of strings) default list of attributes to snippet alongside the number * of words to return (syntax is attributeName:nbWords). * By default no snippet is computed. If set to null, no snippet is computed. * - attributesToIndex: (array of strings) the list of fields you want to index. * If set to null, all textual and numerical attributes of your objects are indexed, * but you should update it to get optimal results. * This parameter has two important uses: * - Limit the attributes to index: For example if you store a binary image in base64, * you want to store it and be able to * retrieve it but you don't want to search in the base64 string. * - Control part of the ranking*: (see the ranking parameter for full explanation) * Matches in attributes at the beginning of * the list will be considered more important than matches in attributes further down the list. * In one attribute, matching text at the beginning of the attribute will be * considered more important than text after, you can disable * this behavior if you add your attribute inside `unordered(AttributeName)`, * for example attributesToIndex: ["title", "unordered(text)"]. * - attributesForFaceting: (array of strings) The list of fields you want to use for faceting. * All strings in the attribute selected for faceting are extracted and added as a facet. * If set to null, no attribute is used for faceting. * - attributeForDistinct: (string) The attribute name used for the Distinct feature. * This feature is similar to the SQL "distinct" keyword: when enabled * in query with the distinct=1 parameter, all hits containing a duplicate * value for this attribute are removed from results. * For example, if the chosen attribute is show_name and several hits have * the same value for show_name, then only the best one is kept and others are removed. * - ranking: (array of strings) controls the way results are sorted. * We have six available criteria: * - typo: sort according to number of typos, * - geo: sort according to decreassing distance when performing a geo-location based search, * - proximity: sort according to the proximity of query words in hits, * - attribute: sort according to the order of attributes defined by attributesToIndex, * - exact: * - if the user query contains one word: sort objects having an attribute * that is exactly the query word before others. * For example if you search for the "V" TV show, you want to find it * with the "V" query and avoid to have all popular TV * show starting by the v letter before it. * - if the user query contains multiple words: sort according to the * number of words that matched exactly (and not as a prefix). * - custom: sort according to a user defined formula set in **customRanking** attribute. * The standard order is ["typo", "geo", "proximity", "attribute", "exact", "custom"] * - customRanking: (array of strings) lets you specify part of the ranking. * The syntax of this condition is an array of strings containing attributes * prefixed by asc (ascending order) or desc (descending order) operator. * For example `"customRanking" => ["desc(population)", "asc(name)"]` * - queryType: Select how the query words are interpreted, it can be one of the following value: * - prefixAll: all query words are interpreted as prefixes, * - prefixLast: only the last word is interpreted as a prefix (default behavior), * - prefixNone: no query word is interpreted as a prefix. This option is not recommended. * - highlightPreTag: (string) Specify the string that is inserted before * the highlighted parts in the query result (default to ""). * - highlightPostTag: (string) Specify the string that is inserted after * the highlighted parts in the query result (default to ""). * - optionalWords: (array of strings) Specify a list of words that should * be considered as optional when found in the query. * @param callback (optional) the result callback called with two arguments * error: null or Error('message') * content: the server answer or the error message if a failure occured */ Index.prototype.setSettings = function(settings, opts, callback) { if (arguments.length === 1 || typeof opts === 'function') { callback = opts; opts = {}; } if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves(); var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false'; var indexObj = this; return this.as._jsonRequest({ method: 'PUT', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings?forwardToReplicas=' + forwardToReplicas, hostType: 'write', body: settings, callback: callback }); }; /* * @deprecated see client.listApiKeys() */ Index.prototype.listUserKeys = deprecate(function(callback) { return this.listApiKeys(callback); }, deprecatedMessage('index.listUserKeys()', 'client.listApiKeys()')); /* * List all existing API keys to this index * * @param callback the result callback called with two arguments * error: null or Error('message') * content: the server answer with API keys belonging to the index * * @deprecated see client.listApiKeys() */ Index.prototype.listApiKeys = deprecate(function(callback) { var indexObj = this; return this.as._jsonRequest({ method: 'GET', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys', hostType: 'read', callback: callback }); }, deprecatedMessage('index.listApiKeys()', 'client.listApiKeys()')); /* * @deprecated see client.getApiKey() */ Index.prototype.getUserKeyACL = deprecate(function(key, callback) { return this.getApiKey(key, callback); }, deprecatedMessage('index.getUserKeyACL()', 'client.getApiKey()')); /* * Get an API key from this index * * @param key * @param callback the result callback called with two arguments * error: null or Error('message') * content: the server answer with the right API key * * @deprecated see client.getApiKey() */ Index.prototype.getApiKey = deprecate(function(key, callback) { var indexObj = this; return this.as._jsonRequest({ method: 'GET', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, hostType: 'read', callback: callback }); }, deprecatedMessage('index.getApiKey()', 'client.getApiKey()')); /* * @deprecated see client.deleteApiKey() */ Index.prototype.deleteUserKey = deprecate(function(key, callback) { return this.deleteApiKey(key, callback); }, deprecatedMessage('index.deleteUserKey()', 'client.deleteApiKey()')); /* * Delete an existing API key associated to this index * * @param key * @param callback the result callback called with two arguments * error: null or Error('message') * content: the server answer with the deletion date * * @deprecated see client.deleteApiKey() */ Index.prototype.deleteApiKey = deprecate(function(key, callback) { var indexObj = this; return this.as._jsonRequest({ method: 'DELETE', url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key, hostType: 'write', callback: callback }); }, deprecatedMessage('index.deleteApiKey()', 'client.deleteApiKey()')); /* * @deprecated see client.addApiKey() */ Index.prototype.addUserKey = deprecate(function(acls, params, callback) { return this.addApiKey(acls, params, callback); }, deprecatedMessage('index.addUserKey()', 'client.addApiKey()')); /* * Add a new API key to this index * * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that * can contains the following values: * - search: allow to search (https and http) * - addObject: allows to add/update an object in the index (https only) * - deleteObject : allows to delete an existing object (https only) * - deleteIndex : allows to delete index content (https only) * - settings : allows to get index settings (https only) * - editSettings : allows to change index settings (https only) * @param {Object} [params] - Optionnal parameters to set for the key * @param {number} params.validity - Number of seconds after which the key will * be automatically removed (0 means no time limit for this key) * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call * @param {string} params.description - A description for your key * @param {string[]} params.referers - A list of authorized referers * @param {Object} params.queryParameters - Force the key to use specific query parameters * @param {Function} callback - The result callback called with two arguments * error: null or Error('message') * content: the server answer with the added API key * @return {Promise|undefined} Returns a promise if no callback given * @example * index.addUserKey(['search'], { * validity: 300, * maxQueriesPerIPPerHour: 2000, * maxHitsPerQuery: 3, * description: 'Eat three fruits', * referers: ['*.algolia.com'], * queryParameters: { * tagFilters: ['public'], * } * }) * @see {@link https://www.algolia.com/doc/rest_api#AddIndexKey|Algolia REST API Documentation} * * @deprecated see client.addApiKey() */ Index.prototype.addApiKey = deprecate(function(acls, params, callback) { var isArray = require('isarray'); var usage = 'Usage: index.addApiKey(arrayOfAcls[, params, callback])'; if (!isArray(acls)) { throw new Error(usage); } if (arguments.length === 1 || typeof params === 'function') { callback = params; params = null; } var postObj = { acl: acls }; if (params) { postObj.validity = params.validity; postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; postObj.maxHitsPerQuery = params.maxHitsPerQuery; postObj.description = params.description; if (params.queryParameters) { postObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); } postObj.referers = params.referers; } return this.as._jsonRequest({ method: 'POST', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys', body: postObj, hostType: 'write', callback: callback }); }, deprecatedMessage('index.addApiKey()', 'client.addApiKey()')); /** * @deprecated use client.addApiKey() */ Index.prototype.addUserKeyWithValidity = deprecate(function deprecatedAddUserKeyWithValidity(acls, params, callback) { return this.addApiKey(acls, params, callback); }, deprecatedMessage('index.addUserKeyWithValidity()', 'client.addApiKey()')); /* * @deprecated see client.updateApiKey() */ Index.prototype.updateUserKey = deprecate(function(key, acls, params, callback) { return this.updateApiKey(key, acls, params, callback); }, deprecatedMessage('index.updateUserKey()', 'client.updateApiKey()')); /** * Update an existing API key of this index * @param {string} key - The key to update * @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that * can contains the following values: * - search: allow to search (https and http) * - addObject: allows to add/update an object in the index (https only) * - deleteObject : allows to delete an existing object (https only) * - deleteIndex : allows to delete index content (https only) * - settings : allows to get index settings (https only) * - editSettings : allows to change index settings (https only) * @param {Object} [params] - Optionnal parameters to set for the key * @param {number} params.validity - Number of seconds after which the key will * be automatically removed (0 means no time limit for this key) * @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour * @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call * @param {string} params.description - A description for your key * @param {string[]} params.referers - A list of authorized referers * @param {Object} params.queryParameters - Force the key to use specific query parameters * @param {Function} callback - The result callback called with two arguments * error: null or Error('message') * content: the server answer with user keys list * @return {Promise|undefined} Returns a promise if no callback given * @example * index.updateApiKey('APIKEY', ['search'], { * validity: 300, * maxQueriesPerIPPerHour: 2000, * maxHitsPerQuery: 3, * description: 'Eat three fruits', * referers: ['*.algolia.com'], * queryParameters: { * tagFilters: ['public'], * } * }) * @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation} * * @deprecated see client.updateApiKey() */ Index.prototype.updateApiKey = deprecate(function(key, acls, params, callback) { var isArray = require('isarray'); var usage = 'Usage: index.updateApiKey(key, arrayOfAcls[, params, callback])'; if (!isArray(acls)) { throw new Error(usage); } if (arguments.length === 2 || typeof params === 'function') { callback = params; params = null; } var putObj = { acl: acls }; if (params) { putObj.validity = params.validity; putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour; putObj.maxHitsPerQuery = params.maxHitsPerQuery; putObj.description = params.description; if (params.queryParameters) { putObj.queryParameters = this.as._getSearchParams(params.queryParameters, ''); } putObj.referers = params.referers; } return this.as._jsonRequest({ method: 'PUT', url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys/' + key, body: putObj, hostType: 'write', callback: callback }); }, deprecatedMessage('index.updateApiKey()', 'client.updateApiKey()'));