-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
109 lines (92 loc) · 3.18 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
var _ = require('lodash');
var Promise = require('bluebird');
var crypto = require('crypto');
RegExp.prototype.toJSON = function() {
var json = {
$regexp: this.source
};
var str = this.toString();
var ind = str.lastIndexOf('/');
var opts = str.slice(ind + 1);
if (opts.length > 0) {
json.$options = opts;
}
return json;
}
var mongooseRedis = function(mongoose, redisClient, options) {
var _defaultOptions = {
cache: true,
expires: 60, // unit: s
prefix: 'RedisCache'
};
var _cacheOptions = _.assign(_.clone(_defaultOptions), options);
var redisClient = mongoose.redisClient = redisClient;
// store original Query.exec
mongoose.Query.prototype._exec = mongoose.Query.prototype.exec;
// custom exec to use cache
mongoose.Query.prototype._exec_callback = function(callback) {
var self = this;
var model = this.model;
var query = this._conditions || {};
var options = this._optionsForExec(model) || {};
var fields = _.clone(this._fields) || {};
// diefferent from mongoose-redis-cache,
// var populate = this.options.populate || {};
var populate = this._mongooseOptions.populate || {};
var collectionName = model.collection.name;
// use cache options set up by query statements first
// also diffrent from mongoose-redis-cache,
// as setOptions() set options in this._optionsForExec(model)
// but not this._mongooseOptions ???
var cacheOptions = _.assign(_.clone(_cacheOptions), options.cacheOptions);
// cache only work in lean query
if (!this._mongooseOptions.lean) cacheOptions.cache = false;
// remove cacheOptions from options, for better redis key
delete options.cacheOptions;
if (!cacheOptions.cache) {
return mongoose.Query.prototype._exec.apply(self, arguments);
}
var hash = crypto.createHash('md5')
.update(JSON.stringify(query))
.update(JSON.stringify(options))
.update(JSON.stringify(fields))
.update(JSON.stringify(populate))
.digest('hex');
var key = [cacheOptions.prefix, collectionName, hash].join(':');
redisClient.get(key, function(err, result) {
var dosc, k, path;
if (err) return callback(err);
if (!result) {
// ???
for (var k in populate) {
path = populate[k];
path.options = path.options || {};
_.defaults(path.options, {
cacheOptions: {cache: false} });
}
return mongoose.Query.prototype._exec.call(self, function(err, docs) {
if (err) return callback(err);
var str = JSON.stringify(docs);
redisClient.setex(key, cacheOptions.expires, str);
return callback(null, docs);
});
}
else {
docs = JSON.parse(result);
return callback(null, docs);
}
});
return this;
};
// support both callback style and promise
mongoose.Query.prototype.exec = function(callback) {
var self = this;
return new Promise(function(resolve, reject) {
mongoose.Query.prototype._exec_callback.call(self, function(err, result) {
if (err) return reject(err);
else resolve(result);
})
}).nodeify(callback);
}
};
module.exports = mongooseRedis;