1 | var _ = require("underscore");
|
2 | var DataLayer = require("./DataLayer");
|
3 | var helpers = require("../helpers");
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | function isFound(result){return result.found;}
|
10 |
|
11 | module.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 |
|
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 |
|