-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
136 lines (108 loc) · 3.36 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
const IORedis = require('ioredis')
const debug = require('debug')('co-cache')
/**
* Cache function result
*
* @param {Object} defaultConfig
* @return {Function}
* @api public
*/
module.exports = function (defaultConfig = {}) {
if (typeof defaultConfig !== 'object') {
throw new Error('`defaultConfig` must be object!')
}
return function coCache (fn, options = {}) {
if (typeof options !== 'object') {
options = { expire: options }
}
options = Object.assign({}, defaultConfig, options)
const redis = options.client || new IORedis(options.redisOpt)
const prefix = typeof options.prefix === 'string' ? options.prefix : ''
const expire = options.expire || 10000
const key = options.key || fn.name
const getter = options.get || defaultGet
const setter = options.set || defaultSet
if (!key || !((typeof key === 'string') || (typeof key === 'function'))) {
throw new Error('`key` must be string or function!')
}
async function raw () {
const args = [].slice.call(arguments)
return fn.apply(this, args)
}
async function cache () {
const args = [].slice.call(arguments)
const _key = (typeof key === 'string') ? key : (await key.apply(fn, args))
if (_key === false) {
return fn.apply(this, args)
}
const cacheKey = prefix + _key
let result = await getter(redis, cacheKey)
debug('get %s -> %j', cacheKey, result)
if (result !== undefined) {
return result
}
result = await fn.apply(this, args)
await setter(redis, cacheKey, result, expire)
debug('set %s -> %j', cacheKey, result)
return result
}
async function get () {
const args = [].slice.call(arguments)
const _key = (typeof key === 'string') ? key : (await key.apply(fn, args))
if (_key === false) {
return
}
const cacheKey = prefix + _key
const result = await getter(redis, cacheKey)
debug('get %s -> %j', cacheKey, result)
return result
}
async function set () {
const args = [].slice.call(arguments, 0, -1)
const value = [].slice.call(arguments).pop()
const _key = (typeof key === 'string') ? key : (await key.apply(fn, args))
if ((_key === false) || (value === undefined)) {
return
}
const cacheKey = prefix + _key
const result = await setter(redis, cacheKey, value, expire)
debug('set %s -> %j', cacheKey, result)
return result
}
async function clear () {
const args = [].slice.call(arguments)
const _key = (typeof key === 'string') ? key : (await key.apply(fn, args))
if (_key === false) {
return
}
const cacheKey = prefix + _key
const result = await redis.del(cacheKey)
debug('clear %s -> %j', cacheKey, result)
return result
}
cache.raw = raw
cache.get = get
cache.set = set
cache.clear = clear
return cache
}
}
function defaultGet (redis, cacheKey) {
return redis
.get(cacheKey)
.then((result) => {
if (result != null) {
return JSON.parse(result)
}
})
.catch(() => {})
}
function defaultSet (redis, cacheKey, result, ms) {
// cannot save `undefined`` value, `null` is ok
if (result === undefined) {
return
}
return redis
.set(cacheKey, JSON.stringify(result), 'PX', ms)
.catch(() => {})
}