UNPKG

7.56 kBJavaScriptView Raw
1var _ = require("underscore");
2var DataLayer = require("./DataLayer");
3var helpers = require("../helpers");
4
5// https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/api-reference.html
6// http://joelabrahamsson.com/elasticsearch-101/
7
8
9function isFound(result){return result.found;}
10
11module.exports = DataLayer.extend("ElasticLayer", {
12
13
14 parseArguments: function(args){
15 switch(args.length){
16 case 0: return false;
17 case 1:
18 if(typeof args[0] !== "function") return false;
19 else return [undefined,{},args[0]];
20 case 2:
21 if(typeof args[1] !== "function") return false;
22 else return [args[0],{}, args[1]];
23 case 3:
24 if(typeof args[2] !== "function") return false;
25 else return [args[0],args[1], args[2]];
26 default: return false;
27 }
28 },
29
30 create: function(obj, options, cb){
31 var self = this;
32 var data = _.pick(obj, _.without( this.publicFields || _.keys(this.fields), this.primaryKey));
33 var query = {
34 index: this.indexName,
35 type: options.type || this.defaultType,
36 body: data
37 }
38
39 if(obj.hasOwnProperty(this.primaryKey)){
40 query.id = obj[this.primaryKey];
41 }
42
43 this.elastic.index(query, function(err, result){
44 if(err) return cb(err);
45 obj[self.primaryKey] = result._id;
46 cb(null, obj);
47 });
48 },
49
50 find: function(pattern, options, cb){
51 var self = this;
52 if(!pattern){
53 this.elastic.search({index: this.indexName}, function(err, response){
54 if(err) return cb(err);
55 cb(null, response.hits.hits.map(function(result){
56 return _.extend(result._source, _.object([[self.primaryKey, result._id]]));
57 }));
58 });
59 }
60 else if(typeof pattern === "string" || typeof pattern === "number"){
61 this.elastic.get({
62 index: this.indexName,
63 type: options.type || this.defaultType,
64 id: pattern
65 }, function(err, result){
66 if(err) return cb(err);
67 if(!result) return cb(null, null);
68 var object = result._source;
69 object[self.primaryKey] = result._id;
70 cb(null, object);
71 });
72 }
73 else if(Array.isArray(pattern)){
74 if(_.every(pattern, function(val){ return typeof val === "string" || typeof val === "number" })){
75 this.elastic.mget({
76 index: this.indexName,
77 type: options.type || this.defaultType,
78 body: { ids: pattern }
79 }, function(err, response){
80 if(err) return cb(err);
81 cb(null, response.docs.map(function(result){
82 if(!isFound(result)) return null;
83 return _.extend(result._source, _.object([[self.primaryKey, result._id]]));
84 }));
85 });
86 }
87 else{
88 var query = [];
89 for(var i=0;i<pattern.length;i++){
90 if(pattern[i].type){
91 query.push(_.extend({index: this.indexName}, pattern[i]));
92 }
93 else{
94 query.push({index: this.indexName});
95 query.push(pattern);
96 }
97 }
98 this.elastic.msearch({ body: query }, function(err, responses){
99 if(err) return cb(err);
100 cb(null, responses.responses.map(function(response){
101 return response.hits.hits.map(function(result){
102 return _.extend(result._source, _.object([[self.primaryKey, result._id]]));
103 });
104 }));
105 });
106 }
107 }
108 else if(_.isObject(pattern)){
109 var query = {index: this.indexName};
110 if(options.type) query.type = options.type;
111 query.body = pattern;
112 this.elastic.search(query, function(err, response){
113 if(err) return cb(err);
114 cb(null, response.hits.hits.map(function(result){
115 return _.extend(result._source, _.object([[self.primaryKey, result._id]]));
116 }));
117 });
118 }
119 },
120
121 findOne: function(){
122 // TODO
123 },
124
125 count: function(pattern, options, cb){
126 var countQuery = { index: this.indexName };
127 if(options.type) countQuery.type = options.type;
128 if(pattern) countQuery.body = pattern;
129 this.elastic.count(countQuery, function(err, result){
130 if(err) return cb(err);
131 cb(null, result.count);
132 });
133 },
134 update: function(pattern, options, cb){
135 var self = this;
136 if(Array.isArray(pattern)){
137 if(_.every(pattern, function(doc){return doc.hasOwnProperty(self.primaryKey);})){
138 helpers.chain([
139 function(cb){self.find(_.pluck(pattern, self.primaryKey), options, function(err, objects){
140 if(err) return cb(err);
141 cb(null, objects.map(function(object, index){
142 if(object === null) return null;
143 return _.extend(object, _.pick(pattern[index], self.publicFields || _.keys(self.fields) ) );
144 }));
145 })},
146 function(results, cb){
147 helpers.amap(results, function(object, cb){ self.update(object, options, cb); }, cb);
148 }
149 ])(cb);
150 }
151 else{
152 cb("Error - cant handle updates");
153 }
154 }
155 else if(_.isObject(pattern)){
156 var query = {index: this.indexName};
157 if(options.type) query.type = options.type;
158 else query.type = this.defaultType;
159 if(pattern.hasOwnProperty(this.primaryKey)){
160 query.id = pattern[this.primaryKey];
161 var props = _.pick(pattern, this.publicFields || _.keys(this.fields));
162 query.body = {doc: _.omit(props, [this.primaryKey])};
163 this.elastic.update(query, function(err, result){
164 if(err) return cb(err);
165 cb(null, _.extend(query.body.doc, _.object([[self.primaryKey, result._id]])) );
166 });
167 }
168
169 else{
170 helpers.chain([
171 options.where? function(cb){self.find(options.where, options, cb)} : function(cb){self.find(null, options, cb);},
172 function(results, cb){
173 helpers.amap(results, function(object, cb){
174 self.update(_.extend(object, _.pick(pattern, self.publicFields || _.keys(self.fields))), options, cb);
175 }, cb);
176 }
177 ])(cb);
178 }
179 }
180 },
181
182 delete: function(pattern, options, cb){
183
184 if(typeof pattern === "string" || typeof pattern === "number"){
185 this.elastic.delete({
186 index: this.indexName,
187 type: options.type || this.defaultType,
188 id: pattern
189 }, cb);
190 }
191 else if(pattern.hasOwnProperty(this.primaryKey)){
192 this.elastic.delete({
193 index: this.indexName,
194 type: options.type,
195 id: pattern[this.primaryKey]
196 }, cb);
197 }
198
199 else{
200 var query = _.extend(_.clone(pattern), { index: this.indexName });
201 query.type = options.type || this.defaultType;
202 query.body = pattern;
203
204 this.elastic.deleteByQuery(query, cb);
205 }
206
207
208
209 },
210
211
212}, {
213
214 setupDatabase: function(self, env, name){
215 var Prototype = this;
216 self.setupNode = function(cb){ Prototype.setupStore(self, env, function(err){
217 if(err) return cb(err);
218 env.i.do("log.sys", "DataLayer:elasticsearch", name);
219 cb();
220 }); }
221 },
222
223
224 setupStore: function(instance, env, cb){
225 instance.elastic = env.engines.elastic;
226 cb();
227 },
228
229 extend: function(name, props, statics){
230 this.setMethods(this.prototype, props);
231 return DataLayer.extend.apply(this, arguments);
232 }
233});
234
235
236