cacheable 0.2.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +136 -141
- package/dist/index.cjs +448 -0
- package/dist/index.d.cts +104 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.js +421 -0
- package/package.json +37 -26
- package/.npmignore +0 -3
- package/.travis.yml +0 -4
- package/Makefile +0 -7
- package/index.js +0 -1
- package/lib/cacheable.js +0 -162
- package/lib/registry.js +0 -170
- package/test/cacheable.test.js +0 -195
- package/test/mocha.opts +0 -2
- package/test/support/user.js +0 -26
package/lib/registry.js
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
// use strict;
|
|
2
|
-
// Global cache for constructor classes
|
|
3
|
-
|
|
4
|
-
var constructors = {}
|
|
5
|
-
var RE_JSON_TIME = /^[0-9\-]+T[0-9\:\.]+Z$/
|
|
6
|
-
|
|
7
|
-
var Cacheable = require('./cacheable')
|
|
8
|
-
|
|
9
|
-
var _REALNAME = Cacheable._REALNAME
|
|
10
|
-
|
|
11
|
-
// default keys for wrapping model methods
|
|
12
|
-
var DEFAULT_KEY = '{_model_}:{_fn_}:%j{0}'
|
|
13
|
-
var DEFAULT_PROTO_KEY = '{_model_}:{id}:{_fn_}'
|
|
14
|
-
var ERROR_DUPLICATE_REGISTRY = 'DUPLICATE_REGISTRY'
|
|
15
|
-
|
|
16
|
-
function enableCache(cached) {
|
|
17
|
-
function enableInstCache(method, key, ttl) {
|
|
18
|
-
var cls = this
|
|
19
|
-
var fn = isValidFunc(cls.prototype[method], method)
|
|
20
|
-
key = key || DEFAULT_PROTO_KEY.replace('{_fn_}', method)
|
|
21
|
-
hiddenProperty(fn, _REALNAME, fn.name || method)
|
|
22
|
-
cls.addCacheKey(key)
|
|
23
|
-
cls.prototype['fresh_' + method] = fn
|
|
24
|
-
cls.prototype[method] = cached.wrap(fn, key, ttl)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return function _enableCache(method, key, ttl) {
|
|
28
|
-
var cls = this, fn
|
|
29
|
-
// can pass ttl as the second argument
|
|
30
|
-
if ('number' === typeof key) {
|
|
31
|
-
ttl = key
|
|
32
|
-
key = null
|
|
33
|
-
}
|
|
34
|
-
if (method[0] === '.') {
|
|
35
|
-
return enableInstCache.call(this, method.slice(1), key, ttl)
|
|
36
|
-
}
|
|
37
|
-
fn = isValidFunc(cls[method], method)
|
|
38
|
-
key = key || DEFAULT_KEY.replace('{_fn_}', method)
|
|
39
|
-
hiddenProperty(fn, _REALNAME, fn.name || method)
|
|
40
|
-
cls['fresh_' + method] = fn
|
|
41
|
-
cls[method] = cached.wrap(fn, key, ttl, cls)
|
|
42
|
-
cls.addCacheKey(key, true)
|
|
43
|
-
return cls[method]
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function clearCache(cached) {
|
|
48
|
-
return function _clearCache(callback) {
|
|
49
|
-
cached.del(this._cacheKeys, callback)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function addCacheKey(key, isClassMethod) {
|
|
54
|
-
if (isClassMethod) {
|
|
55
|
-
this.classCacheKeys.push(key)
|
|
56
|
-
} else {
|
|
57
|
-
this.itemCacheKeys.push(key)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Revive object from a json string
|
|
63
|
-
*/
|
|
64
|
-
function reviver(k, v) {
|
|
65
|
-
if (v && v[_REALNAME]) {
|
|
66
|
-
var cls = v[_REALNAME]
|
|
67
|
-
if (cls) {
|
|
68
|
-
if (!(cls in constructors)) {
|
|
69
|
-
log('Constructor for %s doesn\'t exist anymore.', cls)
|
|
70
|
-
// return a undefined, mean this object is not available anymore
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
cls = constructors[cls]
|
|
74
|
-
// remove `__cachedname` assigned to this object
|
|
75
|
-
delete v[_REALNAME]
|
|
76
|
-
v = new cls(v)
|
|
77
|
-
if (v._unpickle) {
|
|
78
|
-
v._unpickle()
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return v
|
|
82
|
-
}
|
|
83
|
-
if ('string' === typeof v && RE_JSON_TIME.test(v)) {
|
|
84
|
-
// revive a date object
|
|
85
|
-
v = new Date(v)
|
|
86
|
-
}
|
|
87
|
-
return v
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function unpickle(value) {
|
|
91
|
-
return JSON.parse(value, reviver)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Cacheable.prototype._initClassHelper = function() {
|
|
96
|
-
this.helpers.enableCache = enableCache(this)
|
|
97
|
-
this.helpers.clearCache = clearCache(this)
|
|
98
|
-
this.helpers.addCacheKey = addCacheKey
|
|
99
|
-
this._decode = unpickle
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Register constructor class for unpickle
|
|
104
|
-
*/
|
|
105
|
-
Cacheable.prototype.register = function(cls, modelName) {
|
|
106
|
-
modelName = modelName || cls.modelName || cls.name
|
|
107
|
-
hiddenProperty(cls, _REALNAME, modelName)
|
|
108
|
-
hiddenProperty(cls.prototype, _REALNAME, modelName)
|
|
109
|
-
if (cls[_REALNAME] in constructors) {
|
|
110
|
-
var err = new Error('Class "' + cls[_REALNAME] + '" already defined')
|
|
111
|
-
err.code = ERROR_DUPLICATE_REGISTRY
|
|
112
|
-
throw err
|
|
113
|
-
}
|
|
114
|
-
if (!this.helpers.enableCache) {
|
|
115
|
-
this._initClassHelper()
|
|
116
|
-
}
|
|
117
|
-
this._extend(cls)
|
|
118
|
-
constructors[cls[_REALNAME]] = cls
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Extend Model with methods to enable and clear cache
|
|
124
|
-
*/
|
|
125
|
-
Cacheable.prototype._extend = function extendClass(cls) {
|
|
126
|
-
var cached = this, proto = cls.prototype
|
|
127
|
-
cls.classCacheKeys = []
|
|
128
|
-
// default item related cache
|
|
129
|
-
cls.itemCacheKeys = ['{_model_}:{id}']
|
|
130
|
-
// instance cache keys
|
|
131
|
-
Object.defineProperty(proto, '_cacheKeys', {
|
|
132
|
-
get: function() {
|
|
133
|
-
var self = this
|
|
134
|
-
return cls.itemCacheKeys.map(function(item) {
|
|
135
|
-
return cached._applykey(self, item)
|
|
136
|
-
})
|
|
137
|
-
}
|
|
138
|
-
})
|
|
139
|
-
cls.enableCache = cached.helpers.enableCache
|
|
140
|
-
cls.addCacheKey = cached.helpers.addCacheKey
|
|
141
|
-
proto._clearCache = cached.helpers.clearCache
|
|
142
|
-
|
|
143
|
-
if ('function' != typeof proto.toJSON) {
|
|
144
|
-
throw new Error('Cache-able class must have instance method .toJSON')
|
|
145
|
-
}
|
|
146
|
-
proto._toJSON = proto.toJSON
|
|
147
|
-
proto.toJSON = function toJSON() {
|
|
148
|
-
var obj = this._toJSON()
|
|
149
|
-
obj[_REALNAME] = cls[_REALNAME]
|
|
150
|
-
return obj
|
|
151
|
-
}
|
|
152
|
-
return cls
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
function hiddenProperty(where, property, value) {
|
|
157
|
-
Object.defineProperty(where, property, { value: value });
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function isValidFunc(fn, method) {
|
|
161
|
-
if (!fn) {
|
|
162
|
-
throw new Error('method "' + method + '" not defined')
|
|
163
|
-
}
|
|
164
|
-
if ('function' !== typeof fn) {
|
|
165
|
-
throw new Error('method "' + method + '" is not a function')
|
|
166
|
-
}
|
|
167
|
-
return fn
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
package/test/cacheable.test.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
var should = require('should')
|
|
2
|
-
var LRU = require('lru-cache')
|
|
3
|
-
var User = require('./support/user')
|
|
4
|
-
|
|
5
|
-
var Cacheable = require('../')
|
|
6
|
-
|
|
7
|
-
describe('Public API', function() {
|
|
8
|
-
|
|
9
|
-
var client, cache
|
|
10
|
-
|
|
11
|
-
describe('initialize', function() {
|
|
12
|
-
before(function() {
|
|
13
|
-
client = LRU()
|
|
14
|
-
cache = new Cacheable({ client: client })
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('new and no new', function() {
|
|
18
|
-
var cache2 = Cacheable({ client: client })
|
|
19
|
-
cache.should.be.instanceOf(Cacheable)
|
|
20
|
-
cache2.should.be.instanceOf(Cacheable)
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('default options', function() {
|
|
24
|
-
cache.silent.should.equal(true)
|
|
25
|
-
cache.prefix.should.equal('cached:')
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
describe('wrap', function() {
|
|
30
|
-
var reach = 0
|
|
31
|
-
|
|
32
|
-
function foo(callback) {
|
|
33
|
-
reach += 1
|
|
34
|
-
return callback(null, 1)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
beforeEach(function() {
|
|
38
|
-
reach = 0
|
|
39
|
-
client.reset()
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('fn with only callback', function(done) {
|
|
43
|
-
var fn = cache.wrap(foo, 'foo')
|
|
44
|
-
fn(function(err, result) {
|
|
45
|
-
result.should.equal(1)
|
|
46
|
-
fn(function(err, result) {
|
|
47
|
-
result.should.equal(1)
|
|
48
|
-
// if cache is used, `reach` will not accumulate
|
|
49
|
-
reach.should.equal(1)
|
|
50
|
-
done()
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('should have default key', function(done) {
|
|
56
|
-
var fn = cache.wrap(function foo(arg, callback) {
|
|
57
|
-
reach += arg.a
|
|
58
|
-
callback(null, 1)
|
|
59
|
-
})
|
|
60
|
-
var arg = { a: 1 }
|
|
61
|
-
fn(arg, function(err, result) {
|
|
62
|
-
result.should.equal(1)
|
|
63
|
-
// should've wrapped with default cache key: '{_fn_}:%j{0}'
|
|
64
|
-
should.equal(cache.get('foo:{"a":1}'), result)
|
|
65
|
-
fn(arg, function(err, result) {
|
|
66
|
-
result.should.equal(1)
|
|
67
|
-
reach.should.equal(1)
|
|
68
|
-
done()
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
describe('key replace', function() {
|
|
76
|
-
|
|
77
|
-
it('should handle positional', function(done) {
|
|
78
|
-
var fn = cache.wrap(foo, 'foor-{0}-{1}')
|
|
79
|
-
var reach = 0
|
|
80
|
-
|
|
81
|
-
fn(2, 5, function(err, result) {
|
|
82
|
-
reach.should.equal(7)
|
|
83
|
-
result.should.equal(3)
|
|
84
|
-
should.equal(cache.get('foor-2-5'), result)
|
|
85
|
-
fn(2, 5, function(err, result) {
|
|
86
|
-
reach.should.equal(7)
|
|
87
|
-
result.should.equal(3)
|
|
88
|
-
done()
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
function foo(arg1, arg2, callback) {
|
|
93
|
-
reach += arg1 + arg2
|
|
94
|
-
return callback(null, 3)
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should handle context', function(done) {
|
|
99
|
-
var ctx = { hello: 'abc', again: 'def' }
|
|
100
|
-
var fn = cache.wrap(foo, 'contexted-{hello}-{this.hello}-{this.again}', null, ctx)
|
|
101
|
-
var reach = ''
|
|
102
|
-
|
|
103
|
-
fn(1, 2, function(err, result) {
|
|
104
|
-
reach.should.equal('abc')
|
|
105
|
-
result.should.equal('0')
|
|
106
|
-
should.equal(cache.get('contexted-abc-abc-def'), result)
|
|
107
|
-
fn(1, 2, function(err, result) {
|
|
108
|
-
reach.should.equal('abc')
|
|
109
|
-
result.should.equal('0')
|
|
110
|
-
done()
|
|
111
|
-
})
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
function foo(arg1, arg2, callback) {
|
|
115
|
-
reach += this.hello
|
|
116
|
-
return callback(null, '0')
|
|
117
|
-
}
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('should handle context', function() {
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
describe('register', function() {
|
|
127
|
-
|
|
128
|
-
it('cannot register twice', function() {
|
|
129
|
-
var err
|
|
130
|
-
cache.register(User)
|
|
131
|
-
try {
|
|
132
|
-
cache.register(User)
|
|
133
|
-
} catch (e) {
|
|
134
|
-
err = e
|
|
135
|
-
}
|
|
136
|
-
should.exist(err)
|
|
137
|
-
err.code.should.equal('DUPLICATE_REGISTRY')
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
describe('Registry', function() {
|
|
145
|
-
|
|
146
|
-
describe('class method', function() {
|
|
147
|
-
|
|
148
|
-
it('should cache', function(done) {
|
|
149
|
-
|
|
150
|
-
User.enableCache('get')
|
|
151
|
-
|
|
152
|
-
User.get(1, function(err, result) {
|
|
153
|
-
should.equal(User._called, true)
|
|
154
|
-
User._called = 'haha'
|
|
155
|
-
User.get(1, function(err, result) {
|
|
156
|
-
// will remain haha, if cache is used
|
|
157
|
-
should.equal(User._called, 'haha')
|
|
158
|
-
result.should.be.instanceOf(User)
|
|
159
|
-
should.equal(result.data.id, 1)
|
|
160
|
-
done()
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
describe('instance method', function() {
|
|
168
|
-
var user = new User({ id: 1 })
|
|
169
|
-
|
|
170
|
-
it('should cache', function(done) {
|
|
171
|
-
User.enableCache('.articleIds')
|
|
172
|
-
user.articleIds(function(err, result) {
|
|
173
|
-
User._called = 'instance'
|
|
174
|
-
user.articleIds(function(err, result) {
|
|
175
|
-
result.should.eql([1,2,3,1])
|
|
176
|
-
should.equal(User._called, 'instance')
|
|
177
|
-
done()
|
|
178
|
-
})
|
|
179
|
-
})
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
it('can delete cache', function(done) {
|
|
183
|
-
user.articleIds(function(err, result) {
|
|
184
|
-
should.equal(User._called, 'instance')
|
|
185
|
-
user._clearCache(function() {
|
|
186
|
-
user.articleIds(function(err, result) {
|
|
187
|
-
should.equal(User._called, true)
|
|
188
|
-
done()
|
|
189
|
-
})
|
|
190
|
-
})
|
|
191
|
-
})
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
})
|
|
195
|
-
})
|
package/test/mocha.opts
DELETED
package/test/support/user.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
module.exports = User
|
|
2
|
-
|
|
3
|
-
function User(data) {
|
|
4
|
-
this.data = data
|
|
5
|
-
this.id = data.id
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
User.prototype.toJSON = function() {
|
|
9
|
-
return this.data
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
User.prototype.articleIds = function(callback) {
|
|
13
|
-
User._called = true
|
|
14
|
-
var self = this
|
|
15
|
-
process.nextTick(function() {
|
|
16
|
-
callback(null, [1,2,3, self.id])
|
|
17
|
-
})
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
User.get = function(id, callback) {
|
|
21
|
-
User._called = true
|
|
22
|
-
process.nextTick(function() {
|
|
23
|
-
callback(null, new User({ id: id }))
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
|