Skip to content

Commit 0fb2eba

Browse files
committed
initial commit
0 parents  commit 0fb2eba

File tree

6 files changed

+218
-0
lines changed

6 files changed

+218
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.swo
2+
*.swp
3+
*.swn
4+
node_modules/

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
test:
3+
node test/index.js
4+
5+
.PHONY: test

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = exports = require('./lib/ttl');

lib/ttl.js

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
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
9+
10+
// + tests <<== START HERE !!!!
11+
12+
var Model = require('mongoose').Model;
13+
14+
module.exports = exports = ttl;
15+
16+
function ttl (schema, options) {
17+
options || (options = {});
18+
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
23+
24+
var o = {};
25+
o[key] = Date;
26+
27+
schema.add(o);
28+
29+
var index = {};
30+
index[key] = 1;
31+
schema.index(index);
32+
33+
schema.pre('save', function (next) {
34+
this[key] = new Date;
35+
next();
36+
});
37+
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+
}
51+
}
52+
53+
/**
54+
* Override Model.init
55+
*/
56+
57+
schema.statics.init = function () {
58+
init(this);
59+
return Model.init.call(this);
60+
}
61+
62+
/**
63+
* init
64+
*
65+
* Hook into all model queries to include the TTL
66+
* filter and kick off the expired doc reaper.
67+
*/
68+
69+
function init (model) {
70+
if (model.__ttl) return;
71+
72+
var distinct_ = model.distinct;
73+
model.distinct = function (field, cond, cb) {
74+
applyTTL(cond);
75+
return distinct_.call(model, field, cond, cb);
76+
}
77+
78+
'findOne find count'.split(' ').forEach(function (method) {
79+
var fn = model[method];
80+
81+
model[method] = function (cond, fields, opts, cb) {
82+
if (!cond) {
83+
cond = {};
84+
} else if ('function' == typeof cond) {
85+
cb = cond;
86+
cond = {};
87+
}
88+
89+
applyTTL(cond);
90+
return fn.call(model, cond, fields, opts, cb);
91+
}
92+
});
93+
94+
'where $where'.split(' ').forEach(function (method) {
95+
var fn = model[method];
96+
model[method] = function () {
97+
var query = fn.apply(this, arguments)
98+
, cond = {};
99+
applyTTL(cond);
100+
return query.find(cond);
101+
}
102+
});
103+
104+
startTTL(model);
105+
}
106+
107+
/**
108+
* startTTL
109+
*
110+
* Initializes the timer which removes expired docs
111+
* from the DB.
112+
*/
113+
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);
123+
}
124+
125+
/**
126+
* clearTTL
127+
*
128+
* Stops hitting the db to remove expired docs.
129+
*/
130+
131+
schema.statics.clearTTL = function clearTTL () {
132+
clearInterval(this.__ttl);
133+
};
134+
135+
}

package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"author": "Aaron Heckmann <aaron.heckmann+github@gmail.com>",
3+
"name": "mongoose-ttl",
4+
"description": "Mongoose Time-To-Live plugin",
5+
"version": "0.0.0",
6+
"repository": {
7+
"url": ""
8+
},
9+
"scripts": {
10+
"test": "make test"
11+
},
12+
"engines": {
13+
"node": "~0.4.12"
14+
},
15+
"dependencies": {},
16+
"devDependencies": {
17+
"mongoose": "2.4.10"
18+
}
19+
}

test/index.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
2+
var mongoose = require('mongoose')
3+
, Schema = mongoose.Schema
4+
, ttl = require('../')
5+
6+
function log (err) {
7+
console.error('reaper ran');
8+
console.error('error? %s', !!err);
9+
if (err) {console.error(err.stack);}
10+
}
11+
12+
mongoose.set('debug', true);
13+
14+
var ThingSchema = new Schema({ name: String });
15+
ThingSchema.plugin(ttl, { ttl: 10000, interval: 20000, cb: log });
16+
17+
mongoose.connect('localhost', 'mongoose_test_ttl');
18+
19+
var T = mongoose.model('Thing', ThingSchema);
20+
21+
mongoose.connection.on('open', function () {
22+
mongoose.connection.db.dropDatabase(function () {
23+
24+
var t = new T({ name: 'Tha Blob' });
25+
t.save(function (err) {
26+
if (err) console.error(err.stack);
27+
28+
T.find({ name: /Tha Blob/ }).run(function (err, t) {
29+
console.error('find', err, t);
30+
31+
T.where('name').exists().exec(function (err, t) {
32+
console.error('where', err, t);
33+
34+
T.findOne({ name: 'Tha Blob' }, function (err, t) {
35+
console.error('findOne', err, t);
36+
37+
T.count({}, function (err, n) {
38+
console.error('count', err, n);
39+
40+
T.find().where('name', 'Tha Blob').run(function (err, t) {
41+
console.error('find()', err, t);
42+
43+
T.distinct('name', { _id: { $exists: true }}, function (err, t) {
44+
console.error('distinct', err, t);
45+
});
46+
});
47+
});
48+
});
49+
});
50+
});
51+
});
52+
});
53+
});
54+

0 commit comments

Comments
 (0)