Added contributors, MRU cache cleanup, closes #46
This commit is contained in:
parent
e2a50d1a3b
commit
4ec9757503
|
@ -1,6 +1,6 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.4
|
||||
- 0.4.12
|
||||
- 0.6
|
||||
before_install:
|
||||
- git submodule init && git submodule --quiet update
|
||||
|
|
|
@ -5,6 +5,7 @@ var Validatable = require('./validatable').Validatable;
|
|||
var Hookable = require('./hookable').Hookable;
|
||||
var util = require('util');
|
||||
var jutil = require('./jutil');
|
||||
var DEFAULT_CACHE_LIMIT = 1000;
|
||||
|
||||
exports.AbstractClass = AbstractClass;
|
||||
|
||||
|
@ -154,7 +155,7 @@ AbstractClass.create = function (data, callback) {
|
|||
this._adapter().create(modelName, data, function (err, id) {
|
||||
if (id) {
|
||||
defineReadonlyProp(obj, 'id', id);
|
||||
this.constructor.cache[id] = obj;
|
||||
addToCache(this.constructor, obj);
|
||||
}
|
||||
done.call(this, function () {
|
||||
if (callback) {
|
||||
|
@ -178,14 +179,15 @@ AbstractClass.find = function find(id, cb) {
|
|||
this.schema.adapter.find(this.modelName, id, function (err, data) {
|
||||
var obj = null;
|
||||
if (data) {
|
||||
if (this.cache[data.id]) {
|
||||
obj = this.cache[data.id];
|
||||
var cached = getCached(this, data.id);
|
||||
if (cached) {
|
||||
obj = cached;
|
||||
substractDirtyAttributes(obj, data);
|
||||
this.call(obj, data);
|
||||
} else {
|
||||
data.id = id;
|
||||
obj = new this(data);
|
||||
this.cache[data.id] = obj;
|
||||
addToCache(this, id);
|
||||
}
|
||||
}
|
||||
cb(err, obj);
|
||||
|
@ -209,14 +211,15 @@ AbstractClass.all = function all(params, cb) {
|
|||
collection = data.map(function (d) {
|
||||
var obj = null;
|
||||
// do not create different instances for the same object
|
||||
if (d.id && constr.cache[d.id]) {
|
||||
obj = constr.cache[d.id];
|
||||
var cached = getCached(constr, d.id);
|
||||
if (cached) {
|
||||
obj = cached;
|
||||
// keep dirty attributes untouthed (remove from dataset)
|
||||
substractDirtyAttributes(obj, d);
|
||||
constr.call(obj, d);
|
||||
} else {
|
||||
obj = new constr(d);
|
||||
if (d.id) constr.cache[d.id] = obj;
|
||||
if (obj.id) addToCache(constr, obj);
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
@ -248,9 +251,7 @@ function substractDirtyAttributes(object, data) {
|
|||
AbstractClass.destroyAll = function destroyAll(cb) {
|
||||
this.schema.adapter.destroyAll(this.modelName, function (err) {
|
||||
if (!err) {
|
||||
Object.keys(this.cache).forEach(function (id) {
|
||||
delete this.cache[id];
|
||||
}.bind(this));
|
||||
clearCache(this);
|
||||
}
|
||||
cb(err);
|
||||
}.bind(this));
|
||||
|
@ -365,7 +366,7 @@ AbstractClass.prototype.toObject = function (onlySchema) {
|
|||
AbstractClass.prototype.destroy = function (cb) {
|
||||
this.trigger('destroy', function (destroyed) {
|
||||
this._adapter().destroy(this.constructor.modelName, this.id, function (err) {
|
||||
delete this.constructor.cache[this.id];
|
||||
removeFromCache(this.constructor, this.id);
|
||||
destroyed(function () {
|
||||
cb && cb(err);
|
||||
});
|
||||
|
@ -442,7 +443,7 @@ AbstractClass.prototype.propertyChanged = function (attr) {
|
|||
};
|
||||
|
||||
AbstractClass.prototype.reload = function (cb) {
|
||||
var obj = this.constructor.cache[this.id];
|
||||
var obj = getCached(this.constructor, this.id);
|
||||
if (obj) {
|
||||
obj.reset();
|
||||
}
|
||||
|
@ -633,6 +634,7 @@ function defineScope(cls, targetClass, name, params, methods) {
|
|||
|
||||
// helper methods
|
||||
//
|
||||
|
||||
function isdef(s) {
|
||||
var undef;
|
||||
return s !== undef;
|
||||
|
@ -657,3 +659,37 @@ function defineReadonlyProp(obj, key, value) {
|
|||
});
|
||||
}
|
||||
|
||||
function addToCache(constr, obj) {
|
||||
touchCache(constr, obj.id);
|
||||
constr.cache[obj.id] = obj;
|
||||
}
|
||||
|
||||
function touchCache(constr, id) {
|
||||
var cacheLimit = constr.CACHE_LIMIT || DEFAULT_CACHE_LIMIT;
|
||||
|
||||
var ind = constr.mru.indexOf(id);
|
||||
if (~ind) constr.mru.splice(ind, 1);
|
||||
if (constr.mru.length >= cacheLimit * 2) {
|
||||
for (var i = 0; i < cacheLimit;i += 1) {
|
||||
delete constr.cache[constr.mru[i]];
|
||||
}
|
||||
constr.mru.splice(0, cacheLimit);
|
||||
}
|
||||
}
|
||||
|
||||
function getCached(constr, id) {
|
||||
if (id) touchCache(constr, id);
|
||||
return id && constr.cache[id];
|
||||
}
|
||||
|
||||
function clearCache(constr) {
|
||||
constr.cache = {};
|
||||
constr.mru = [];
|
||||
}
|
||||
|
||||
function removeFromCache(constr, id) {
|
||||
var ind = constr.mru.indexOf(id);
|
||||
if (!~ind) constr.mru.splice(ind, 1);
|
||||
delete constr.cache[id];
|
||||
}
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ Schema.prototype.define = function defineClass(className, properties, settings)
|
|||
hiddenProperty(newClass, 'schema', schema);
|
||||
hiddenProperty(newClass, 'modelName', className);
|
||||
hiddenProperty(newClass, 'cache', {});
|
||||
hiddenProperty(newClass, 'mru', []);
|
||||
|
||||
// setup inheritance
|
||||
newClass.__proto__ = AbstractClass;
|
||||
|
|
35
package.json
35
package.json
|
@ -1,9 +1,20 @@
|
|||
{
|
||||
"name": "jugglingdb",
|
||||
"author": "Anatoliy Chakkaev",
|
||||
"description": "ORM for every database: redis, mysql, neo4j, mongodb, postgres, sqlite",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"author": "Anatoliy Chakkaev <rpm1602@gmail.com>",
|
||||
"contributors": [
|
||||
{ "name": "Anatoliy Chakkaev", "email": "rpm1602@gmail.com" },
|
||||
{ "name": "Julien Guimont", "email": "julien.guimont@gmail.com" },
|
||||
{ "name": "Henri Bergius", "email": "henri.bergius@iki.fi" },
|
||||
{ "name": "redvulps", "email": "fabopereira@gmail.com" },
|
||||
{ "name": "Amir M. Mahmoudi", "email": "a@geeknux.com" },
|
||||
{ "name": "Justinas Stankevičius", "email": "justinas@justinas.me" },
|
||||
{ "name": "Felipe Sateler", "email": "fsateler@gmail.com" },
|
||||
{ "name": "Rick O'Toole", "email": "patrick.n.otoole@gmail.com" }
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/1602/jugglingdb"
|
||||
},
|
||||
"main": "index.js",
|
||||
|
@ -11,22 +22,22 @@
|
|||
"test": "nodeunit test/*_test*"
|
||||
},
|
||||
"engines": [
|
||||
"node >= 0.4.0"
|
||||
"node >= 0.4.12"
|
||||
],
|
||||
"dependencies": {
|
||||
"node-uuid": "*"
|
||||
"node-uuid": ">= 1.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coffee-script": ">= 1.2.0",
|
||||
"nodeunit": ">= 0.6.4",
|
||||
"redis": ">= 0.6.7",
|
||||
"mongoose": ">= 2.2.3",
|
||||
"mysql": ">= 0.9.4",
|
||||
"sequelize": "*",
|
||||
"pg": "*",
|
||||
"sqlite3": "*",
|
||||
"nodeunit": ">= 0",
|
||||
"coffee-script": ">= 0",
|
||||
"riak-js": ">= 0",
|
||||
"neo4j": ">= 0",
|
||||
"mongodb": "*"
|
||||
"pg": ">= 0.6.9",
|
||||
"sqlite3": ">= 2.1.1",
|
||||
"riak-js": ">= 0.4.1",
|
||||
"neo4j": ">= 0.2.5",
|
||||
"mongodb": ">= 0.9.9",
|
||||
"felix-couchdb": ">= 1.0.3"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue