1 | 'use strict';
|
2 |
|
3 | const _ = require('lodash');
|
4 | const deprecate = require('depd')('camo');
|
5 | const DB = require('./clients').getClient;
|
6 | const BaseDocument = require('./base-document');
|
7 | const isSupportedType = require('./validate').isSupportedType;
|
8 | const isArray = require('./validate').isArray;
|
9 | const isReferenceable = require('./validate').isReferenceable;
|
10 | const isEmbeddedDocument = require('./validate').isEmbeddedDocument;
|
11 | const isString = require('./validate').isString;
|
12 |
|
13 | class Document extends BaseDocument {
|
14 | constructor(name) {
|
15 | super();
|
16 |
|
17 | if (name !== undefined && name !== null) {
|
18 | deprecate('Document.constructor(name) - override Document.collectionName() instead');
|
19 | this._meta = {
|
20 | collection: name
|
21 | };
|
22 | }
|
23 | }
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | static documentClass() {
|
29 | return 'document';
|
30 | }
|
31 |
|
32 | documentClass() {
|
33 | return 'document';
|
34 | }
|
35 |
|
36 | get meta() {
|
37 | return this._meta;
|
38 | }
|
39 |
|
40 | set meta(meta) {
|
41 | this._meta = meta;
|
42 | }
|
43 |
|
44 | |
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | save() {
|
51 | const that = this;
|
52 |
|
53 | let preValidatePromises = this._getHookPromises('preValidate');
|
54 |
|
55 | return Promise.all(preValidatePromises).then(function() {
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | _.keys(that._schema).forEach(function(key) {
|
62 | if (!(key in that._schema)) {
|
63 | that[key] = that.getDefault(key);
|
64 | }
|
65 | });
|
66 |
|
67 |
|
68 | that.validate();
|
69 |
|
70 |
|
71 | that.canonicalize();
|
72 |
|
73 | return Promise.all(that._getHookPromises('postValidate'));
|
74 | }).then(function() {
|
75 | return Promise.all(that._getHookPromises('preSave'));
|
76 | }).then(function() {
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | let toUpdate = that._toData({_id: false});
|
84 |
|
85 |
|
86 | _.keys(that._schema).forEach(function(key) {
|
87 |
|
88 | if (key === '_id') return;
|
89 |
|
90 | if (isReferenceable(that[key]) ||
|
91 | (isArray(that[key]) &&
|
92 | that[key].length > 0 &&
|
93 | isReferenceable(that[key][0]))) {
|
94 |
|
95 |
|
96 | if (isArray(that[key])) {
|
97 | toUpdate[key] = [];
|
98 | that[key].forEach(function(v) {
|
99 | if (DB().isNativeId(v)) {
|
100 | toUpdate[key].push(v);
|
101 | } else {
|
102 | toUpdate[key].push(v._id);
|
103 | }
|
104 | });
|
105 | } else {
|
106 | if (DB().isNativeId(that[key])) {
|
107 | toUpdate[key] = that[key];
|
108 | } else {
|
109 | toUpdate[key] = that[key]._id;
|
110 | }
|
111 | }
|
112 |
|
113 | }
|
114 | });
|
115 |
|
116 |
|
117 | _.keys(that._schema).forEach(function(key) {
|
118 | if (isEmbeddedDocument(that[key]) ||
|
119 | (isArray(that[key]) &&
|
120 | that[key].length > 0 &&
|
121 | isEmbeddedDocument(that[key][0]))) {
|
122 |
|
123 |
|
124 | if (isArray(that[key])) {
|
125 | toUpdate[key] = [];
|
126 | that[key].forEach(function(v) {
|
127 | toUpdate[key].push(v._toData());
|
128 | });
|
129 | } else {
|
130 | toUpdate[key] = that[key]._toData();
|
131 | }
|
132 |
|
133 | }
|
134 | });
|
135 |
|
136 | return DB().save(that.collectionName(), that._id, toUpdate);
|
137 | }).then(function(id) {
|
138 | if (that._id === null) {
|
139 | that._id = id;
|
140 | }
|
141 | }).then(function() {
|
142 |
|
143 | let postSavePromises = that._getHookPromises('postSave');
|
144 | return Promise.all(postSavePromises);
|
145 | }).then(function() {
|
146 | return that;
|
147 | }).catch(function(error) {
|
148 | return Promise.reject(error);
|
149 | });
|
150 | }
|
151 |
|
152 | |
153 |
|
154 |
|
155 |
|
156 |
|
157 | delete() {
|
158 | const that = this;
|
159 |
|
160 | let preDeletePromises = that._getHookPromises('preDelete');
|
161 |
|
162 | return Promise.all(preDeletePromises).then(function() {
|
163 | return DB().delete(that.collectionName(), that._id);
|
164 | }).then(function(deleteReturn) {
|
165 |
|
166 | let postDeletePromises = [deleteReturn].concat(that._getHookPromises('postDelete'));
|
167 | return Promise.all(postDeletePromises);
|
168 | }).then(function(prevData) {
|
169 | let deleteReturn = prevData[0];
|
170 | return deleteReturn;
|
171 | });
|
172 | }
|
173 |
|
174 | |
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 | static deleteOne(query) {
|
181 | return DB().deleteOne(this.collectionName(), query);
|
182 | }
|
183 |
|
184 | |
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 | static deleteMany(query) {
|
191 | if (query === undefined || query === null) {
|
192 | query = {};
|
193 | }
|
194 |
|
195 | return DB().deleteMany(this.collectionName(), query);
|
196 | }
|
197 |
|
198 | |
199 |
|
200 |
|
201 | static loadOne(query, options) {
|
202 | deprecate('loadOne - use findOne instead');
|
203 | return this.findOne(query, options);
|
204 | }
|
205 |
|
206 | |
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 | static findOne(query, options) {
|
215 | const that = this;
|
216 |
|
217 | let populate = true;
|
218 | if (options && options.hasOwnProperty('populate')) {
|
219 | populate = options.populate;
|
220 | }
|
221 |
|
222 | return DB().findOne(this.collectionName(), query)
|
223 | .then(function(data) {
|
224 | if (!data) {
|
225 | return null;
|
226 | }
|
227 |
|
228 | let doc = that._fromData(data);
|
229 | if (populate === true || (isArray(populate) && populate.length > 0)) {
|
230 | return that.populate(doc, populate);
|
231 | }
|
232 |
|
233 | return doc;
|
234 | }).then(function(docs) {
|
235 | if (docs) {
|
236 | return docs;
|
237 | }
|
238 | return null;
|
239 | });
|
240 | }
|
241 |
|
242 | |
243 |
|
244 |
|
245 | static loadOneAndUpdate(query, values, options) {
|
246 | deprecate('loadOneAndUpdate - use findOneAndUpdate instead');
|
247 | return this.findOneAndUpdate(query, values, options);
|
248 | }
|
249 |
|
250 | |
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | static findOneAndUpdate(query, values, options) {
|
259 | const that = this;
|
260 |
|
261 | if (arguments.length < 2) {
|
262 | throw new Error('findOneAndUpdate requires at least 2 arguments. Got ' + arguments.length + '.');
|
263 | }
|
264 |
|
265 | if (!options) {
|
266 | options = {};
|
267 | }
|
268 |
|
269 | let populate = true;
|
270 | if (options.hasOwnProperty('populate')) {
|
271 | populate = options.populate;
|
272 | }
|
273 |
|
274 | return DB().findOneAndUpdate(this.collectionName(), query, values, options)
|
275 | .then(function(data) {
|
276 | if (!data) {
|
277 | return null;
|
278 | }
|
279 |
|
280 | let doc = that._fromData(data);
|
281 | if (populate) {
|
282 | return that.populate(doc);
|
283 | }
|
284 |
|
285 | return doc;
|
286 | }).then(function(doc) {
|
287 | if (doc) {
|
288 | return doc;
|
289 | }
|
290 | return null;
|
291 | });
|
292 | }
|
293 |
|
294 | |
295 |
|
296 |
|
297 | static loadOneAndDelete(query, options) {
|
298 | deprecate('loadOneAndDelete - use findOneAndDelete instead');
|
299 | return this.findOneAndDelete(query, options);
|
300 | }
|
301 |
|
302 | |
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 |
|
309 | static findOneAndDelete(query, options) {
|
310 | const that = this;
|
311 |
|
312 | if (arguments.length < 1) {
|
313 | throw new Error('findOneAndDelete requires at least 1 argument. Got ' + arguments.length + '.');
|
314 | }
|
315 |
|
316 | if (!options) {
|
317 | options = {};
|
318 | }
|
319 |
|
320 | return DB().findOneAndDelete(this.collectionName(), query, options);
|
321 | }
|
322 |
|
323 | |
324 |
|
325 |
|
326 | static loadMany(query, options) {
|
327 | deprecate('loadMany - use find instead');
|
328 | return this.find(query, options);
|
329 | }
|
330 |
|
331 | |
332 |
|
333 |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 | static find(query, options) {
|
341 | const that = this;
|
342 |
|
343 | if (query === undefined || query === null) {
|
344 | query = {};
|
345 | }
|
346 |
|
347 | if (options === undefined || options === null) {
|
348 |
|
349 | options = {populate: true};
|
350 | }
|
351 |
|
352 | return DB().find(this.collectionName(), query, options)
|
353 | .then(function(datas) {
|
354 | let docs = that._fromData(datas);
|
355 |
|
356 | if (options.populate === true ||
|
357 | (isArray(options.populate) && options.populate.length > 0)) {
|
358 | return that.populate(docs, options.populate);
|
359 | }
|
360 |
|
361 | return docs;
|
362 | }).then(function(docs) {
|
363 |
|
364 | return [].concat(docs);
|
365 | });
|
366 | }
|
367 |
|
368 | |
369 |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 | static count(query) {
|
375 | const that = this;
|
376 | return DB().count(this.collectionName(), query);
|
377 | }
|
378 |
|
379 | |
380 |
|
381 |
|
382 |
|
383 |
|
384 | static createIndexes() {
|
385 | if (this._indexesCreated) {
|
386 | return;
|
387 | }
|
388 |
|
389 | const that = this;
|
390 | let instance = this._instantiate();
|
391 |
|
392 | _.keys(instance._schema).forEach(function(k) {
|
393 | if (instance._schema[k].unique) {
|
394 | DB().createIndex(that.collectionName(), k, {unique: true});
|
395 | }
|
396 | });
|
397 |
|
398 | this._indexesCreated = true;
|
399 | }
|
400 |
|
401 | static _fromData(datas) {
|
402 | let instances = super._fromData(datas);
|
403 |
|
404 |
|
405 |
|
406 | let datasArray = [].concat(datas);
|
407 | let instancesArray = [].concat(instances);
|
408 |
|
409 | |
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 |
|
416 |
|
417 | return instances;
|
418 | }
|
419 |
|
420 | |
421 |
|
422 |
|
423 |
|
424 |
|
425 | static clearCollection() {
|
426 | return DB().clearCollection(this.collectionName());
|
427 | }
|
428 |
|
429 | }
|
430 |
|
431 | module.exports = Document; |
\ | No newline at end of file |