forked from iolo/mongoose-q
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
113 lines (105 loc) · 3.85 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
'use strict';
var
Q = require('q'),
MONGOOSE_MODEL_STATICS = [
// mongoose.Model static
'remove', 'ensureIndexes', 'find', 'findById', 'findOne', 'count', 'distinct',
'findOneAndUpdate', 'findByIdAndUpdate', 'findOneAndRemove', 'findByIdAndRemove',
'create', 'update', 'mapReduce', 'aggregate', 'populate',
'geoNear', 'geoSearch',
// mongoose.Document static
'update'
],
MONGOOSE_MODEL_METHODS = [
// mongoose.Model instance
'save', 'remove',
// mongoose.Document instance
'populate', 'update', 'validate'
],
MONGOOSE_QUERY_METHODS = [
// mongoose.Query instance
'find', 'exec', 'findOne', 'count', 'distinct', 'update', 'remove',
'findOneAndUpdate', 'findOneAndRemove', 'lean', 'limit', 'skip', 'sort'
],
MONGOOSE_AGGREGATE_METHODS = [
'exec'
],
apslice = Array.prototype.slice,
debug = console.log.bind(console),
DEBUG = !!process.env.MONGOOSEQ_DEBUG;
/**
* @module mongooseq
*/
/**
*
* @param {object} obj
* @param {Array.<string>} funcNames - original function names to apply Q
* @param {function(string):string} funcNameMapper maps a function name into Q-applied one
* @param {*} [spread=false] use spread for multi-results
*/
function qualify(obj, funcNames, funcNameMapper, spread) {
funcNames.forEach(function (funcName) {
if (typeof(obj[funcName]) !== 'function') {
DEBUG && debug('***skip*** function not found:', funcName);
return;
}
var mappedFuncName = funcNameMapper(funcName);
DEBUG && debug('wrap function:', funcName, '-->', mappedFuncName);
obj[mappedFuncName] = function () {
var d = Q.defer();
var args = apslice.call(arguments);
args.push(function (err, result) {
if (err) {
return d.reject(err);
}
// with 'spread' option: returns 'all' result with 'spread' only for multiple result
if (spread && arguments.length > 2) {
return d.resolve(apslice.call(arguments, 1));
}
// without 'spread' option: returns the 'first' result only and ignores following result
return d.resolve(result);
});
// fix https://github.com/iolo/mongoose-q/issues/1
// mongoose patches some instance methods after instantiation. :(
this[funcName].apply(this, args);
return d.promise;
};
});
}
/**
* add Q wrappers for static/instance functions of mongoose model and query.
*
* @param {mongoose.Mongoose} [mongoose]
* @param {object.<string,*>} [options={}] - prefix and/or suffix for wrappers
* @param {string} [options.prefix='']
* @param {string} [options.suffix='Q']
* @param {function(string):string} [options.mapper]
* @param {boolean} [options.spread=false]
* @returns {mongoose.Mongoose} the same mongoose instance, for convenince
*/
function mongooseQ(mongoose, options) {
mongoose = mongoose || require('mongoose');
options = options || {};
var prefix = options.prefix || '';
var suffix = options.suffix || 'Q';
var mapper = options.mapper || function (funcName) {
return prefix + funcName + suffix;
};
var spread = options.spread;
// avoid duplicated application for custom mapper function...
var applied = require('crypto').createHash('md5').update(mapper.toString()).digest('hex');
if (mongoose['__q_applied_' + applied]) {
return mongoose;
}
qualify(mongoose.Model, MONGOOSE_MODEL_STATICS, mapper, spread);
qualify(mongoose.Model.prototype, MONGOOSE_MODEL_METHODS, mapper, spread);
qualify(mongoose.Query.prototype, MONGOOSE_QUERY_METHODS, mapper, spread);
// see https://github.com/iolo/mongoose-q/issues/6 and
// https://github.com/LearnBoost/mongoose/issues/1910
var Aggregate = require('mongoose/lib/aggregate');
qualify(Aggregate.prototype, MONGOOSE_AGGREGATE_METHODS, mapper, spread);
mongoose['__q_applied_' + applied] = true;
return mongoose;
}
module.exports = mongooseQ;
module.exports.qualify = qualify;