Skip to content

Commit 0466a70

Browse files
committed
release 0.0.1
1 parent 0fb2eba commit 0466a70

File tree

7 files changed

+529
-87
lines changed

7 files changed

+529
-87
lines changed

History.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
0.0.1 / 01-24-2012
3+
==================
4+
5+
* initial release

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) 2012 [Aaron Heckmann](aaron.heckmann+github@gmail.com)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
'Software'), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
TESTS = test/*.js
12

23
test:
3-
node test/index.js
4+
@./node_modules/.bin/mocha --reporter list --require should $(TESTFLAGS) $(TESTS)
45

56
.PHONY: test

Readme.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
2+
#Mongoose-TTL Plugin
3+
4+
Provides time-to-live support [Mongoose]http://mongoosejs.com).
5+
6+
Options:
7+
8+
- ttl: the time each doc should live in the db (default 60 seconds)
9+
- interval: how often the expired doc reaper runs (default 5 mins)
10+
- reap: enable the expired doc reaper (default true)
11+
- onReap: callback passed to reaper execution
12+
13+
Example:
14+
15+
```js
16+
var schema = new Schema({..});
17+
schema.plugin(ttl, { ttl: 5000 });
18+
```
19+
20+
The ttl option supports the ms module by @guille meaning
21+
we can specify ttls with friendlier syntax. Example:
22+
23+
```
24+
value milliseconds
25+
========================
26+
'2d' 172800000
27+
'1.5h' 5400000
28+
'1h' 3600000
29+
'1m' 60000
30+
'5s' 5000
31+
'500ms' 500
32+
100 100
33+
```
34+
35+
The expired document reaper can be disabled by passing `reap: false`.
36+
Useful when working in multi-core environments when we only want one
37+
process executing it.
38+
39+
```
40+
var schema = new Schema({..});
41+
schema.plugin(ttl, { ttl: 5000, reap: false });
42+
var Cache = db.model('Cache', schema);
43+
if (isMyWorker) Cache.startTTLReaper();
44+
```
45+
46+
The reaper can also be stopped.
47+
48+
```js
49+
Cache.stopTTLReaper();
50+
```
51+
52+
Time-to-live is specified at the collection level, however
53+
it can also be overridden for a given document.
54+
55+
```js
56+
var cache = new Cache;
57+
cache.ttl = '2m' // lives for two minutes
58+
cache.save();
59+
```
60+
61+
We can also reset the ttl for a given document to its
62+
default plugin state.
63+
64+
```js
65+
cache.resetTTL();
66+
```
67+

lib/ttl.js

Lines changed: 166 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,137 @@
11

2-
// todo
3-
// mongoose-ttl
4-
// mongoose-keywords
5-
// mongoose-query-cache
6-
// mongoose-timestamps (use createdAt as default name)
7-
// mongoose-created
8-
// more
2+
/**
3+
* Module dependencies.
4+
*/
95

10-
// + tests <<== START HERE !!!!
6+
var Model = require('mongoose').Model
7+
, ms = require('ms')
118

12-
var Model = require('mongoose').Model;
9+
/**
10+
* Exports.
11+
*/
1312

1413
module.exports = exports = ttl;
1514

15+
/**
16+
* Mongoose-TTL Plugin
17+
*
18+
* Provides timespan support for documents.
19+
*
20+
* Options:
21+
* ttl: the time each doc should live in the db (default 60 seconds)
22+
* interval: how often the expired doc reaper runs (default 5 mins)
23+
* reap: enable the expired doc reaper (default true)
24+
* onReap: callback passed to reaper execution
25+
*
26+
* Example:
27+
*
28+
* var schema = new Schema({..});
29+
* schema.plugin(ttl, { ttl: 5000 });
30+
*
31+
* The ttl option supports the ms module by @guille meaning
32+
* we can specify ttls with friendlier syntax. Example:
33+
*
34+
* value milliseconds
35+
* ========================
36+
* '2d' 172800000
37+
* '1.5h' 5400000
38+
* '1h' 3600000
39+
* '1m' 60000
40+
* '5s' 5000
41+
* '500ms' 500
42+
* 100 100
43+
*
44+
* The expired document reaper can be disabled by passing `reap: false`.
45+
* Useful when working in multi-core environments when we only want one
46+
* process executing it.
47+
*
48+
* var schema = new Schema({..});
49+
* schema.plugin(ttl, { ttl: 5000, reap: false });
50+
* var Cache = db.model('Cache', schema);
51+
* if (isMyWorker) Cache.startTTLReaper();
52+
*
53+
* The reaper can also be stopped.
54+
*
55+
* Cache.stopTTLReaper();
56+
*
57+
* Time-to-live is specified at the collection level, however
58+
* it can also be overridden for a given document.
59+
*
60+
* var cache = new Cache;
61+
* cache.ttl = '2m' // lives for two minutes
62+
* cache.save();
63+
*
64+
* We can also reset the ttl for a given document to its
65+
* default plugin state.
66+
*
67+
* cache.resetTTL();
68+
*
69+
* @param {Schema} schema
70+
* @param {Object} options
71+
*/
72+
1673
function ttl (schema, options) {
1774
options || (options = {});
1875

19-
var key = '__ttl' // non-configurable
20-
, ttl = options.ttl || 60000 // doc age limit
21-
, interval = options.interval || 60000*5 // how often to .remove() expired docs
22-
, cb = 'function' == typeof options.cb ? cb : undefined // reaper callback
76+
var key = '__ttl'
77+
, overridden = '__ttlOverride'
78+
, ttl = options.ttl || 60000
79+
, interval = options.interval || 60000*5
80+
, reap = false !== options.reap
81+
, onReap = 'function' == typeof options.onReap
82+
? options.onReap
83+
: undefined
2384

2485
var o = {};
2586
o[key] = Date;
26-
2787
schema.add(o);
2888

29-
var index = {};
30-
index[key] = 1;
31-
schema.index(index);
89+
schema.index(key, { background: true });
3290

3391
schema.pre('save', function (next) {
34-
this[key] = new Date;
92+
if (overridden in this) {
93+
// nothing to do
94+
} else {
95+
this[key] = fromNow();
96+
}
3597
next();
3698
});
3799

38-
function applyTTL (cond) {
39-
if (cond[key]) {
40-
cond.$and || (cond.$and = []);
41-
var a = {};
42-
a[key] = cond[key];
43-
cond.$and.push(a);
44-
var b = {};
45-
b[key] = { $gte: Date.now() - ttl };
46-
cond.$and.push(b);
47-
delete cond[key];
48-
} else {
49-
cond[key] = { $gte: Date.now() - ttl }
50-
}
100+
/**
101+
* startTTLReaper
102+
*
103+
* Starts reaping expired docs from the db.
104+
*/
105+
106+
schema.statics.startTTLReaper = function startTTLReaper () {
107+
if (key in this) return;
108+
109+
var self = this;
110+
self[key] = setInterval((function remove () {
111+
self
112+
.remove()
113+
.where(key).$lte(new Date)
114+
.exec(onReap);
115+
return remove;
116+
})(), interval);
51117
}
52118

53119
/**
54-
* Override Model.init
120+
* stopTTLReaper
121+
*
122+
* Stops removing expired docs from the db.
55123
*/
56124

57-
schema.statics.init = function () {
125+
schema.statics.stopTTLReaper = function stopTTLReapter () {
126+
clearInterval(this[key]);
127+
delete this[key];
128+
};
129+
130+
/**
131+
* Clobber Model.init.
132+
*/
133+
134+
schema.statics.init = function initTTL () {
58135
init(this);
59136
return Model.init.call(this);
60137
}
@@ -63,14 +140,16 @@ function ttl (schema, options) {
63140
* init
64141
*
65142
* Hook into all model queries to include the TTL
66-
* filter and kick off the expired doc reaper.
143+
* filter and kick off the expired doc reaper if
144+
* enabled.
145+
* @private
67146
*/
68147

69148
function init (model) {
70149
if (model.__ttl) return;
71150

72151
var distinct_ = model.distinct;
73-
model.distinct = function (field, cond, cb) {
152+
model.distinct = function distinct (field, cond, cb) {
74153
applyTTL(cond);
75154
return distinct_.call(model, field, cond, cb);
76155
}
@@ -101,35 +180,68 @@ function ttl (schema, options) {
101180
}
102181
});
103182

104-
startTTL(model);
183+
if (reap) {
184+
model.startTTLReaper();
185+
}
105186
}
106187

107188
/**
108-
* startTTL
189+
* Getters/setters
190+
*/
191+
192+
var virt = schema.virtual('ttl');
193+
194+
virt.get(function () {
195+
if (this[key]) return this[key];
196+
this.ttl = ttl;
197+
return this.ttl;
198+
});
199+
200+
virt.set(function (val) {
201+
if ('reset' == val) return this.resetTTL();
202+
this[overridden] = arguments.length ? val : ttl;
203+
return this[key] = fromNow(this[overridden]);
204+
});
205+
206+
/**
207+
* resetTTL
109208
*
110-
* Initializes the timer which removes expired docs
111-
* from the DB.
209+
* Resets this documents ttl to the default specified
210+
* in the plugin options or plugin default.
112211
*/
113212

114-
function startTTL (model) {
115-
var remove;
116-
model.__ttl = setInterval(remove = function () {
117-
model
118-
.remove()
119-
.where(key).$lt(Date.now() - ttl)
120-
.exec(cb);
121-
}, interval);
122-
setTimeout(remove, 10000);
213+
schema.methods.resetTTL = function resetTTL () {
214+
delete this._doc[key];
215+
delete this[overridden];
123216
}
124217

125218
/**
126-
* clearTTL
127-
*
128-
* Stops hitting the db to remove expired docs.
219+
* fromNow
220+
* @private
129221
*/
130222

131-
schema.statics.clearTTL = function clearTTL () {
132-
clearInterval(this.__ttl);
133-
};
223+
function fromNow (val) {
224+
var v = arguments.length ? val : ttl;
225+
return new Date(Date.now() + ms(v));
226+
}
134227

228+
/**
229+
* Applies ttl to query conditions.
230+
* @private
231+
*/
232+
233+
function applyTTL (cond) {
234+
if (cond[key]) {
235+
cond.$and || (cond.$and = []);
236+
var a = {};
237+
a[key] = cond[key];
238+
cond.$and.push(a);
239+
var b = {};
240+
b[key] = { $gt: new Date };
241+
cond.$and.push(b);
242+
delete cond[key];
243+
} else {
244+
cond[key] = { $gt: new Date };
245+
}
246+
}
135247
}

0 commit comments

Comments
 (0)