From a577866932a6b1ae0c482d2f4c67b3155b96af20 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Mon, 23 Apr 2012 02:30:16 +0100 Subject: [PATCH] [#61,backend/elasticearch][s]: refactor plus support for setting request headers (e.g. Authorization) plus can set backend url on initialization. * support for headers went into new _makeRequest method on backend base class * support for setting backend url on initialization (rather than depending on it being on Dataset/Document objects) * move upsert and delete methods out into distinct methods from being inside backbone sync The two last of these pave the way for use of ElasticSearch backend standalone (both independent from Recline and independent of Backbone) --- src/backend/base.js | 26 ++++++++ src/backend/elasticsearch.js | 115 ++++++++++++++++++++++++----------- 2 files changed, 104 insertions(+), 37 deletions(-) diff --git a/src/backend/base.js b/src/backend/base.js index 1b06dc01..94cccf4f 100644 --- a/src/backend/base.js +++ b/src/backend/base.js @@ -99,6 +99,32 @@ this.recline.Backend = this.recline.Backend || {}; query: function(model, queryObj) { }, + // ### _makeRequest + // + // Just $.ajax but in any headers in the 'headers' attribute of this + // Backend instance. Example: + // + //
+    // var jqxhr = this._makeRequest({
+    //   url: the-url
+    // });
+    // 
+ _makeRequest: function(data) { + var headers = this.get('headers'); + var extras = {}; + if (headers) { + extras = { + beforeSend: function(req) { + _.each(headers, function(value, key) { + req.setRequestHeader(key, value); + }); + } + }; + } + var data = _.extend(extras, data); + return $.ajax(data); + }, + // convenience method to convert simple set of documents / rows to a QueryResult _docsToQueryResult: function(rows) { var hits = _.map(rows, function(row) { diff --git a/src/backend/elasticsearch.js b/src/backend/elasticsearch.js index 03448277..546c0c8a 100644 --- a/src/backend/elasticsearch.js +++ b/src/backend/elasticsearch.js @@ -6,37 +6,39 @@ this.recline.Backend = this.recline.Backend || {}; // // Connecting to [ElasticSearch](http://www.elasticsearch.org/). // - // To use this backend ensure your Dataset has one of the following - // attributes (first one found is used): + // Usage: + // + //
+  // var backend = new recline.Backend.ElasticSearch({
+  //   // optional as can also be provided by Dataset/Document
+  //   url: {url to ElasticSearch endpoint i.e. ES 'type/table' url - more info below}
+  //   // optional
+  //   headers: {dict of headers to add to each request}
+  // });
+  //
+  // @param {String} url: url for ElasticSearch type/table, e.g. for ES running
+  // on localhost:9200 with index // twitter and type tweet it would be:
+  // 
+  // 
http://localhost:9200/twitter/tweet
+ // + // This url is optional since the ES endpoint url may be specified on the the + // dataset (and on a Document by the document having a dataset attribute) by + // having one of the following (see also `_getESUrl` function): // //
   // elasticsearch_url
   // webstore_url
   // url
   // 
- // - // This should point to the ES type url. E.G. for ES running on - // localhost:9200 with index twitter and type tweet it would be - // - //
http://localhost:9200/twitter/tweet
my.ElasticSearch = my.Base.extend({ __type__: 'elasticsearch', readonly: false, - _getESUrl: function(dataset) { - var out = dataset.get('elasticsearch_url'); - if (out) return out; - out = dataset.get('webstore_url'); - if (out) return out; - out = dataset.get('url'); - return out; - }, sync: function(method, model, options) { var self = this; if (method === "read") { if (model.__type__ == 'Dataset') { - var base = self._getESUrl(model); - var schemaUrl = base + '/_mapping'; - var jqxhr = $.ajax({ + var schemaUrl = self._getESUrl(model) + '/_mapping'; + var jqxhr = this._makeRequest({ url: schemaUrl, dataType: 'jsonp' }); @@ -57,36 +59,75 @@ this.recline.Backend = this.recline.Backend || {}; return dfd.promise(); } else if (model.__type__ == 'Document') { var base = this._getESUrl(model.dataset) + '/' + model.id; - return $.ajax({ + return this._makeRequest({ url: base, dataType: 'json' }); } } else if (method === 'update') { if (model.__type__ == 'Document') { - var data = JSON.stringify(model.toJSON()); - var base = this._getESUrl(model.dataset); - if (model.id) { - base += '/' + model.id; - } - return $.ajax({ - url: base, - type: 'POST', - data: data, - dataType: 'json' - }); + return this.upsert(model.toJSON(), this._getESUrl(model.dataset)); } } else if (method === 'delete') { if (model.__type__ == 'Document') { - var base = this._getESUrl(model.dataset) + '/' + model.id; - return $.ajax({ - url: base, - type: 'DELETE', - dataType: 'json' - }); + var url = this._getESUrl(model.dataset); + return this.delete(model.id, url); } } }, + + // ### upsert + // + // create / update a document to ElasticSearch backend + // + // @param {Object} doc an object to insert to the index. + // @param {string} url (optional) url for ElasticSearch endpoint (if not + // defined called this._getESUrl() + upsert: function(doc, url) { + var data = JSON.stringify(doc); + url = url ? url : this._getESUrl(); + if (doc.id) { + url += '/' + doc.id; + } + return this._makeRequest({ + url: url, + type: 'POST', + data: data, + dataType: 'json' + }); + }, + + // ### delete + // + // Delete a document from the ElasticSearch backend. + // + // @param {Object} id id of object to delete + // @param {string} url (optional) url for ElasticSearch endpoint (if not + // provided called this._getESUrl() + delete: function(id, url) { + url = url ? url : this._getESUrl(); + url += '/' + id; + return this._makeRequest({ + url: url, + type: 'DELETE', + dataType: 'json' + }); + }, + + // ### _getESUrl + // + // get url to ElasticSearch endpoint (see above) + _getESUrl: function(dataset) { + if (dataset) { + var out = dataset.get('elasticsearch_url'); + if (out) return out; + out = dataset.get('webstore_url'); + if (out) return out; + out = dataset.get('url'); + return out; + } + return this.get('url'); + }, _normalizeQuery: function(queryObj) { var out = queryObj.toJSON ? queryObj.toJSON() : _.extend({}, queryObj); if (out.q !== undefined && out.q.trim() === '') { @@ -123,7 +164,7 @@ this.recline.Backend = this.recline.Backend || {}; var queryNormalized = this._normalizeQuery(queryObj); var data = {source: JSON.stringify(queryNormalized)}; var base = this._getESUrl(model); - var jqxhr = $.ajax({ + var jqxhr = this._makeRequest({ url: base + '/_search', data: data, dataType: 'jsonp'