├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── api.md ├── dist ├── incache.js └── incache.min.js ├── examples ├── auto-load │ ├── app.js │ └── cache.json ├── auto-save │ ├── app-terminate.js │ └── app-timer.js ├── basic │ └── app.js ├── browser-auto-save │ └── index.html ├── browser-save │ └── index.html ├── load │ ├── app.js │ └── cache.json └── save │ └── app.js ├── extra └── logo.png ├── index.js ├── package.json ├── src ├── defined.js ├── helper.js └── incache.js ├── test ├── .incache-save ├── .incache-save2 ├── .incache-save5 ├── app │ ├── fake-content │ ├── index.js │ ├── middleware.js │ └── routes │ │ ├── hello.js │ │ └── index.js ├── helper.js ├── incache-auto-removed.js ├── incache-auto-save.js ├── incache-bulk.js ├── incache-clone.js ├── incache-delete-on-expires.js ├── incache-events.js ├── incache-exceeded.js ├── incache-hits.js ├── incache-info.js ├── incache-load-param.js ├── incache-manually.js ├── incache-more-instance.js ├── incache-no-share.js ├── incache-preserve.js ├── incache-record.js ├── incache-save-param.js ├── incache-save.js ├── incache-stats.js ├── incache.js ├── index.html ├── issues │ └── 4.js └── performace │ ├── load.js │ └── save.js ├── version-to-tag.sh └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | coverage/ 4 | extra/ 5 | test/ 6 | examples/ 7 | .travis.yml 8 | api.md 9 | version-to-tag.sh 10 | webpack.config.js -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [7.2.1] - 2018-12-19 8 | - **Fixed** process don't exit if SAVE MODE is TIMER 9 | 10 | ## [7.2.0] - 2018-09-21 11 | - **Added** event `get` 12 | - **Added** event `beforeGet` 13 | 14 | ## [7.1.0] - 2018-09-20 15 | - **Added** method `info`, now it's possible retrieve only record info without increase `hits` 16 | 17 | ## [7.0.6] - 2018-09-19 18 | - **Removed** vulnerable library 19 | 20 | ## [7.0.5] - 2018-03-06 21 | - **Improved** `all` method, now can return also a plain object 22 | 23 | ## [7.0.4] - 2018-02-28 24 | - **Improved** `save` method, now create the full path if not exists 25 | 26 | ## [7.0.3] - 2018-02-24 27 | - **Improved** performance for `set` method 28 | 29 | ## [7.0.1] - 2018-02-19 30 | - **Fixed** empty `filePath` issue 31 | 32 | ## [7.0.0] - 2018-01-13 33 | - **Added** `load` support for browser 34 | - **Added** `save` support for browser 35 | - **Added** `autoLoad` support for browser 36 | - **Added** `autoSave` support for browser 37 | 38 | ## [6.6.1] - 2017-12-04 39 | - Fixed main entry point 40 | 41 | ## [6.6.0] - 2017-11-25 42 | - Added 43 | - methods 44 | - `suspendEvent` 45 | - `resumeEvent` 46 | - `suspendEvents` 47 | - `resumeEvents` 48 | 49 | ## [6.5.1] - 2017-11-19 50 | - Added 51 | - static method `isRecord` 52 | - UMD support 53 | - Changed 54 | - `bulkSet` now accepts custom array 55 | 56 | ## [6.4.0] - 2017-10-14 57 | - Improvement for `InCache` instance and `on` method, now are chainable 58 | - Added 59 | - events 60 | - `beforeLoad` 61 | - `beforeSave` 62 | - instance parameter to events 63 | - `load` 64 | - `save` 65 | - Bug fix 66 | 67 | ## [6.3.0] - 2017-09-30 68 | - Added 69 | - record property 70 | - `hits` 71 | - `lastHit` 72 | - `stats` method 73 | 74 | ## [6.2.0] - 2017-09-25 75 | - Added 76 | - path parameter to `load` and `save` methods, now it's possible specify a file path to load or save 77 | 78 | ## [6.1.1] - 2017-09-24 79 | - Typo fixed 80 | 81 | ## [6.1.0] - 2017-09-24 82 | - Added 83 | - events 84 | - `change` 85 | - `exceed` 86 | 87 | ## [6.0.0] - 2017-09-23 88 | - Added 89 | - options 90 | - `autoLoad` 91 | - `autoSave` 92 | - `autoSaveMode` 93 | - `autoSavePeriod` 94 | - `clone` 95 | - `preserve` 96 | - `deleteOnExpires` 97 | - `maxRecordNumber` 98 | - methods 99 | - `load()` 100 | - `save()` 101 | - `count()` 102 | - events 103 | - `load` 104 | - `save` 105 | 106 | ## [5.2.0] - 2017-09-06 107 | - **Important:** 108 | - changed the default value of `save` option, now is set to "false" 109 | - changed the default value of `share` option, now is set to "false" 110 | 111 | ## [5.1.0] - 2017-09-05 112 | - **Important:** changed the default value of `nullIfNotFound` option, now is set to "false" 113 | 114 | ## [5.0.0] - 2017-09-05 115 | - Added 116 | - method`on` 117 | - events: 118 | - `beforeSet` 119 | - `set` 120 | - `create` 121 | - `update` 122 | - `beforeRemove` 123 | - `remove` 124 | - `beforeBulkSet` 125 | - `bulkSet` 126 | - `beforeBulkRemove` 127 | - `bulkRemove` 128 | - `expired` 129 | - options: 130 | - `autoRemovePeriod`, now InCache can remove automatically expired records without calling any methods 131 | - `nullIfNotFound` 132 | - Deprecated methods: 133 | - `onCreated` 134 | - `onUpdated` 135 | - `onRemoved` 136 | 137 | ## [4.2.1] - 2017-09-01 138 | - Fixed wrong warning message 139 | 140 | ## [4.2.0] - 2017-09-01 141 | - Added new property to configuration: `share`, now is possible disable global storage 142 | 143 | ## [4.1.2] - 2017-08-30 144 | - Fixed `record.createdOn` is null, it happened when record was updated 145 | 146 | ## [4.1.1] - 2017-08-30 147 | - Added `destroy`, alias of `remove` 148 | - Removed unused code 149 | 150 | ## [4.1.0] - 2017-08-29 151 | - Added new method: `removeExpired`, now is possible remove all records expired at once 152 | 153 | ## [4.0.2] - 2017-08-22 154 | - Fixed expires: now if set overwrites maxAge 155 | 156 | ## [4.0.1] - 2017-08-22 157 | - Fixed default configuration 158 | 159 | ## [4.0.0] - 2017-08-22 160 | - Changed configuration 161 | - Added new properties 162 | - `maxAge` 163 | - `expires` 164 | - `silent` 165 | - **Deprecated properties** 166 | - `global.life` 167 | - `global.silent` 168 | 169 | ## [3.1.1] - 2017-08-21 170 | - Fixed readme 171 | 172 | ## [3.1.0] - 2017-08-21 173 | - Added `clean` method 174 | 175 | ## [3.0.1] - 2017-08-20 176 | - Removed unnecessary files for deployment on NPM 177 | 178 | ## [3.0.0] - 2017-08-19 179 | - Library loading was changed: 180 | - **Now you need to instantiate the `new InCache` object** 181 | - Added cache writing to disk 182 | - Added `setConfig` method 183 | - Added `addTo` method 184 | - Added `prependTo` method 185 | - Added `updateIn` method 186 | - Added `removeFrom` method 187 | - Added global record configuration 188 | 189 | ## [2.0.0] - 2017-08-13 190 | - Changed `set` method: last argument now is an object, see documentation. 191 | - Added expiry date 192 | 193 | ## [1.0.1] - 2017-08-12 194 | - First release -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 | 4 |

5 |

6 | Powerful key/value in-memory storage or on disk to persist data 7 |

8 | 9 | 10 | 11 | 12 |

13 |
14 | 15 | ## What does? 16 | InCache is a module that store any info in memory, it can be used for example for storing **server sessions**, **caching http response** or **sharing singleton object** in your apps. 17 | It also give you the possibility to save data on disk so you can avoid the data loss when the process exit or restart. In a browser scenario all data is saved on localStorage through a key. 18 | 19 | ## Installation 20 | 21 | ### Node.js 22 | ``` 23 | npm install incache --save 24 | ``` 25 | 26 | ## Examples 27 | 28 | ### Basic 29 | ```javascript 30 | const InCache = require('incache'); 31 | const store = new InCache(); 32 | 33 | // Create a record with key 'my key' 34 | store.set('my key', 'my value'); 35 | 36 | // Update 'my key' 37 | store.set('my key', {a: 1, b: 2}); 38 | 39 | // Get key 40 | store.get('my key'); 41 | 42 | // Remove 'my key' 43 | store.remove('my key'); 44 | 45 | // Clear 46 | store.clear(); 47 | 48 | // Expires after 2 seconds 49 | store.set('my string', 'hello world', {maxAge: 2000}); 50 | // Or expires on... 51 | store.set('my string', 'hello world', {expires: '2028-08-22 12:00:00'}); 52 | ``` 53 | 54 | ### Auto remove expired records 55 | ```javascript 56 | const store = new InCache({ 57 | autoRemovePeriod: 2 //checks every 2 seconds 58 | }); 59 | 60 | store.set('my string', 'hello world', {maxAge: 4000}); 61 | 62 | setTimeout(()=>{ 63 | console.log(store.count()) //=> 0 64 | }, 6000); 65 | ``` 66 | 67 | ### Max cache size 68 | ```javascript 69 | const store = new InCache({ 70 | maxRecordNumber: 5 71 | }); 72 | 73 | store.set('k0', 'v0'); 74 | store.set('k1', 'v1'); 75 | store.set('k2', 'v2'); 76 | store.set('k3', 'v3'); 77 | store.set('k4', 'v4'); 78 | store.set('k5', 'v5'); 79 | 80 | console.log(store.count()); //=> 5 81 | console.log(store.has('k0')); //=> false 82 | ``` 83 | 84 | ### Load manually 85 | ```javascript 86 | const store = new InCache({ 87 | autoLoad: false 88 | }); 89 | 90 | // This method returns a Promise 91 | store.load('my-path/my-store.json').then(() => { 92 | console.log('loaded'); 93 | }).catch(err => { 94 | console.log(err); 95 | }); 96 | ``` 97 | 98 | ### Save on disk 99 | By default this operation is running before the process is terminated 100 | ```javascript 101 | const store = new InCache({ 102 | autoSave: true 103 | }); 104 | ``` 105 | 106 | Save when data is changed 107 | ```javascript 108 | const store = new InCache({ 109 | autoSave: true, 110 | autoSaveMode: 'timer' 111 | }); 112 | ``` 113 | 114 | ### Save manually 115 | ```javascript 116 | const store = new InCache({ 117 | filePath: 'my-path/my-store.json' 118 | }); 119 | 120 | store.set('a key', 'a value'); 121 | 122 | // This method returns a Promise 123 | store.save(); 124 | 125 | // or specify a path 126 | store.save('a-path/a-file.json').then(()=>{ 127 | console.log('saved'); 128 | store.load('a-path/a-file.json'); 129 | }).catch(err => { 130 | console.log(err); 131 | }); 132 | ``` 133 | 134 | ### Browser scenario 135 | In browser environment the file path becomes a string key for localStorage interface: 136 | ```javascript 137 | store.load('myLocalStorageKey'); 138 | store.save('myLocalStorageKey'); 139 | ``` 140 | 141 | ### Events 142 | ```javascript 143 | 144 | // Triggered when a record has been deleted 145 | incache.on('remove', key => { 146 | console.log(key); 147 | }); 148 | 149 | // Triggered before create/update 150 | incache.on('beforeSet', (key, value) => { 151 | console.log(key, value); 152 | if(foo) 153 | return false; 154 | }); 155 | 156 | // Triggered when a record has been created 157 | incache.on('create', (key, record) => { 158 | console.log(key, record); 159 | }); 160 | 161 | //Triggered when a record has been updated 162 | incache.on('update', (key, record) => { 163 | console.log(key, record); 164 | }); 165 | 166 | //Triggered when the cache is saved on disk 167 | incache.on('save', () => { 168 | console.log('saved on disk'); 169 | }); 170 | 171 | //Triggered when the cache exceed max size 172 | incache.on('exceed', (diff) => { 173 | console.log(`exceeded for ${diff}`); 174 | }); 175 | 176 | //... for more events see the documentation 177 | ``` 178 | 179 | ### API 180 | Please see the **full documentation** for more details. 181 | 182 | ### Browser 183 | 184 | #### Local 185 | ```html 186 | 187 | ``` 188 | 189 | #### CDN unpkg 190 | ```html 191 | 192 | ``` 193 | 194 | #### CDN jsDeliver 195 | ```html 196 | 197 | ``` 198 | 199 | ## Changelog 200 | You can view the changelog here 201 | 202 | ## License 203 | InCache is open-sourced software licensed under the MIT license 204 | 205 | ## Author 206 | Fabio Ricali 207 | 208 | ## Contributor 209 | Davide Polano -------------------------------------------------------------------------------- /api.md: -------------------------------------------------------------------------------- 1 | ## Classes 2 | 3 |
4 |
InCache
5 |
6 |
7 | 8 | ## Constants 9 | 10 |
11 |
SAVE_MODE
12 |
13 |
14 | 15 | 16 | 17 | ## InCache 18 | **Kind**: global class 19 | 20 | * [InCache](#InCache) 21 | * [new InCache([opts])](#new_InCache_new) 22 | * _instance_ 23 | * [.load([path])](#InCache+load) ⇒ Promise 24 | * [.save([path])](#InCache+save) ⇒ Promise 25 | * [.setConfig([opts])](#InCache+setConfig) 26 | * [.getConfig()](#InCache+getConfig) ⇒ \* 27 | * [.set(key, value, [opts])](#InCache+set) ⇒ [record](#InCache..record) \| \* 28 | * [.get(key, [onlyValue])](#InCache+get) ⇒ [record](#InCache..record) \| \* \| null \| undefined 29 | * [.info(key)](#InCache+info) ⇒ [recordInfo](#InCache..recordInfo) \| \* \| undefined 30 | * [.remove(key, [silent])](#InCache+remove) 31 | * [.removeFrom(key, where)](#InCache+removeFrom) 32 | * [.removeExpired()](#InCache+removeExpired) ⇒ Array 33 | * [.addTo(key, value)](#InCache+addTo) ⇒ [record](#InCache..record) \| undefined 34 | * [.prependTo(key, value)](#InCache+prependTo) ⇒ [record](#InCache..record) \| undefined 35 | * [.updateIn(key, value, where)](#InCache+updateIn) 36 | * [.bulkSet(records, [silent])](#InCache+bulkSet) ⇒ Object \| undefined 37 | * [.bulkRemove(keys, [silent])](#InCache+bulkRemove) 38 | * [.clean(key)](#InCache+clean) 39 | * [.all(asObject)](#InCache+all) ⇒ \* 40 | * [.count()](#InCache+count) ⇒ Number 41 | * [.expired(key)](#InCache+expired) ⇒ boolean 42 | * [.clear()](#InCache+clear) 43 | * [.has(key)](#InCache+has) ⇒ boolean 44 | * [.destroy(...args)](#InCache+destroy) 45 | * [.stats()](#InCache+stats) ⇒ Object 46 | * [.canBeAutoRemove(key)](#InCache+canBeAutoRemove) ⇒ boolean \| \* 47 | * [.onRemoved(callback)](#InCache+onRemoved) 48 | * [.onCreated(callback)](#InCache+onCreated) 49 | * [.onUpdated(callback)](#InCache+onUpdated) 50 | * ["beforeGet" (key, record)](#InCache+event_beforeGet) 51 | * ["get" (key, record)](#InCache+event_get) 52 | * ["beforeSet" (key, value)](#InCache+event_beforeSet) 53 | * ["set" (key, record)](#InCache+event_set) 54 | * ["create" (key, record)](#InCache+event_create) 55 | * ["update" (key, record)](#InCache+event_update) 56 | * ["beforeRemove" (key)](#InCache+event_beforeRemove) 57 | * ["remove" (key)](#InCache+event_remove) 58 | * ["beforeBulkSet" (records)](#InCache+event_beforeBulkSet) 59 | * ["bulkSet" (records)](#InCache+event_bulkSet) 60 | * ["beforeBulkRemove" (keys)](#InCache+event_beforeBulkRemove) 61 | * ["bulkRemove" (keys)](#InCache+event_bulkRemove) 62 | * ["expired" (keys)](#InCache+event_expired) 63 | * ["beforeLoad" (me)](#InCache+event_beforeLoad) 64 | * ["load" (err, me)](#InCache+event_load) 65 | * ["beforeSave" (me)](#InCache+event_beforeSave) 66 | * ["save" (err, me)](#InCache+event_save) 67 | * ["change" (by)](#InCache+event_change) 68 | * ["exceed" (diff)](#InCache+event_exceed) 69 | * _static_ 70 | * [.isRecord(obj)](#InCache.isRecord) ⇒ boolean 71 | * _inner_ 72 | * [~record](#InCache..record) : Object 73 | * [~recordInfo](#InCache..recordInfo) : Object 74 | * [~removedCallback](#InCache..removedCallback) : function 75 | * [~createdCallback](#InCache..createdCallback) : function 76 | * [~updatedCallback](#InCache..updatedCallback) : function 77 | 78 | 79 | 80 | ### new InCache([opts]) 81 | Create instance 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 93 | 94 | 96 | 97 | 99 | 100 | 102 | 103 | 105 | 106 | 108 | 109 | 111 | 112 | 114 | 115 | 117 | 118 | 120 | 121 | 123 | 124 | 126 | 127 | 129 | 130 | 132 | 133 | 135 | 136 | 138 | 139 | 141 | 142 | 144 | 145 | 147 | 148 | 150 | 151 | 153 | 154 |
ParamTypeDefaultDescription
[opts]Object

configuration object

92 |
[opts.maxAge]number0

max age in milliseconds. If 0 not expire. (overwritable by set)

95 |
[opts.expires]Date | string

a Date for expiration. (overwrites opts.maxAge, overwritable by set)

98 |
[opts.silent]booleanfalse

if true no event will be triggered. (overwritable by set)

101 |
[opts.deleteOnExpires]booleantrue

if false, the record will not be deleted after expiry. (overwritable by set)

104 |
[opts.clone]booleanfalse

if true, the object will be cloned before to put it in storage. (overwritable by set)

107 |
[opts.preserve]booleanfalse

if true, you will no longer be able to update the record once created. (overwritable by set)

110 |
[opts.maxRecordNumber]number0

the maximum of record number of the cache, if exceeded some records will be deleted. If 0 is disabled

113 |
[opts.autoLoad]booleantrue

load cache from disk when instance is created.

116 |
[opts.autoSave]booleanfalse

if true saves cache in disk when the process is terminated.

119 |
[opts.autoSaveMode]string"terminate"

there are 2 modes -> "terminate": saves before the process is terminated (server only). "timer": every n seconds checks for new changes and save on disk.

122 |
[opts.autoSavePeriod]number5

period in seconds to check for new changes to save on disk. Works only if opts.autoSaveMode is set to 'timer' mode.

125 |
[opts.filePath]string | *".incache"

cache file path or key. If is a falsy value, load and save will always be solved

128 |
[opts.storeName]string

store name

131 |
[opts.share]booleanfalse

if true, use global object as storage

134 |
[opts.autoRemovePeriod]number0

period in seconds to remove expired records. When set, the records will be removed only on check, when 0 it won't run

137 |
[opts.nullIfNotFound]booleanfalse

calling get if the key is not found returns null. If false returns undefined

140 |
[opts.save]booleanfalse

deprecated: if true saves cache in disk when the process is terminated. Use autoSave instead.

143 |
[opts.global]Object

deprecated: global record configuration

146 |
[opts.global.silent]booleanfalse

deprecated: if true no event will be triggered, use silent instead

149 |
[opts.global.life]number0

deprecated: max age in seconds. If 0 not expire, use maxAge instead

152 |
155 | 156 | 157 | 158 | ### inCache.load([path]) ⇒ Promise 159 | Load cache from disk 160 | 161 | **Kind**: instance method of [InCache](#InCache) 162 | **Emits**: [beforeLoad](#InCache+event_beforeLoad), [load](#InCache+event_load) 163 | **Since**: 6.0.0 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 174 | 175 |
ParamTypeDefaultDescription
[path]string"opts.filePath"

file path or key (browser scenario)

173 |
176 | 177 | 178 | 179 | ### inCache.save([path]) ⇒ Promise 180 | Save cache into disk 181 | 182 | **Kind**: instance method of [InCache](#InCache) 183 | **Emits**: [beforeSave](#InCache+event_beforeSave), [save](#InCache+event_save) 184 | **Since**: 6.0.0 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 195 | 196 |
ParamTypeDefaultDescription
[path]string"opts.filePath"

file path or key (browser scenario)

194 |
197 | 198 | 199 | 200 | ### inCache.setConfig([opts]) 201 | Set configuration 202 | 203 | **Kind**: instance method of [InCache](#InCache) 204 | **See**: [constructor](constructor) for further information 205 | **Since**: 3.0.0 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 216 | 217 |
ParamTypeDescription
[opts]Object

configuration object

215 |
218 | 219 | 220 | 221 | ### inCache.getConfig() ⇒ \* 222 | Get configuration 223 | 224 | **Kind**: instance method of [InCache](#InCache) 225 | 226 | 227 | ### inCache.set(key, value, [opts]) ⇒ [record](#InCache..record) \| \* 228 | Set/update record 229 | 230 | **Kind**: instance method of [InCache](#InCache) 231 | **Emits**: [beforeSet](#InCache+event_beforeSet), [create](#InCache+event_create), [update](#InCache+event_update), [set](#InCache+event_set) 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 246 | 247 | 249 | 250 | 252 | 253 | 255 | 256 | 258 | 259 | 261 | 262 | 264 | 265 | 267 | 268 |
ParamTypeDefaultDescription
keystring
value*
[opts]Object

options object

245 |
[opts.silent]booleanfalse

if true no event will be triggered. (overwrites global configuration)

248 |
[opts.maxAge]number0

max age in milliseconds. If 0 not expire. (overwrites global configuration)

251 |
[opts.clone]booleanfalse

if true, the object will be cloned before to put it in storage. (overwrites global configuration)

254 |
[opts.preserve]booleanfalse

if true, you will no longer be able to update the record once created. (overwrites global configuration)

257 |
[opts.expires]Date | string

a Date for expiration. (overwrites global configuration and opts.maxAge)

260 |
[opts.deleteOnExpires]booleantrue

if false, the record will not be deleted after expiry. (overwrites global configuration)

263 |
[opts.life]number0

deprecated: max age in seconds. If 0 not expire. (overwrites global configuration)

266 |
269 | 270 | **Example** 271 | ```js 272 | inCache.set('my key', 'my value'); inCache.set('my object', {a: 1, b: 2}); inCache.set('my boolean', true, {maxAge: 2000}); // Expires after 2 seconds 273 | ``` 274 | 275 | 276 | ### inCache.get(key, [onlyValue]) ⇒ [record](#InCache..record) \| \* \| null \| undefined 277 | Get record by key 278 | 279 | **Kind**: instance method of [InCache](#InCache) 280 | **Emits**: [get](#InCache+event_get), [beforeGet](#InCache+event_beforeGet) 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 293 | 294 |
ParamTypeDefaultDescription
keystring
[onlyValue]booleantrue

if false get InCache record

292 |
295 | 296 | **Example** 297 | ```js 298 | inCache.get('my key'); 299 | ``` 300 | 301 | 302 | ### inCache.info(key) ⇒ [recordInfo](#InCache..recordInfo) \| \* \| undefined 303 | Get info record by key 304 | 305 | **Kind**: instance method of [InCache](#InCache) 306 | **Since**: 7.1.0 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 |
ParamType
keystring
318 | 319 | **Example** 320 | ```js 321 | inCache.info('my key'); 322 | ``` 323 | 324 | 325 | ### inCache.remove(key, [silent]) 326 | Delete a record 327 | 328 | **Kind**: instance method of [InCache](#InCache) 329 | **Emits**: [beforeRemove](#InCache+event_beforeRemove), [remove](#InCache+event_remove) 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 342 | 343 |
ParamTypeDefaultDescription
keystring
[silent]booleanfalse

if true no event will be triggered

341 |
344 | 345 | **Example** 346 | ```js 347 | inCache.remove('my key'); 348 | ``` 349 | 350 | 351 | ### inCache.removeFrom(key, where) 352 | Given a key that has value like an array removes key(s) if `where` is satisfied 353 | 354 | **Kind**: instance method of [InCache](#InCache) 355 | **Since**: 3.0.0 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 |
ParamType
keystring
where*
369 | 370 | **Example** 371 | ```js 372 | inCache.set('myArray', ['hello', 'world']); inCache.removeFrom('myArray', 'hello'); //-> ['world']; 373 | ``` 374 | 375 | 376 | ### inCache.removeExpired() ⇒ Array 377 | Remove expired records 378 | 379 | **Kind**: instance method of [InCache](#InCache) 380 | **Returns**: Array - expired keys 381 | **Since**: 4.1.0 382 | **Example** 383 | ```js 384 | inCache.set('my key 1', 'my value'); inCache.set('my key 2', 'my value', {maxAge: 1000}); inCache.set('my key 3', 'my value', {maxAge: 1500}); setTimeout(()=>{ inCache.removeExpired(); inCache.all(); //-> [{key: 'my key 1', value: 'my value'}] }, 2000) 385 | ``` 386 | 387 | 388 | ### inCache.addTo(key, value) ⇒ [record](#InCache..record) \| undefined 389 | Given a key that has value like an array adds value to end of array 390 | 391 | **Kind**: instance method of [InCache](#InCache) 392 | **Since**: 3.0.0 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 |
ParamType
keystring
value*
406 | 407 | **Example** 408 | ```js 409 | inCache.set('myArray', ['hello', 'world']); inCache.addTo('myArray', 'ciao'); //-> ['hello', 'world', 'ciao']; 410 | ``` 411 | 412 | 413 | ### inCache.prependTo(key, value) ⇒ [record](#InCache..record) \| undefined 414 | Given a key that has value like an array adds value to beginning of array 415 | 416 | **Kind**: instance method of [InCache](#InCache) 417 | **Since**: 3.0.0 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 |
ParamType
keystring
value*
431 | 432 | **Example** 433 | ```js 434 | inCache.set('myArray', ['hello', 'world']); inCache.prependTo('myArray', 'ciao'); //-> ['ciao', 'hello', 'world']; 435 | ``` 436 | 437 | 438 | ### inCache.updateIn(key, value, where) 439 | Given a key that has value like an array updates key(s) if `where` is satisfied 440 | 441 | **Kind**: instance method of [InCache](#InCache) 442 | **Since**: 3.0.0 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 |
ParamType
keystring
value*
where*
458 | 459 | **Example** 460 | ```js 461 | inCache.set('myArray', ['hello', 'world']); inCache.updateIn('myArray', 'ciao', 'hello'); //-> ['ciao', 'world']; inCache.set('myArray', [{a: 1, b: 2, c: 3], {b: 2, c: 3}, {b: 4, e: 5}); inCache.updateIn('myArray', {z: 0, x: 0}, {b: 2, c: 3}); //-> [{z: 0, x: 0}, {z: 0, x: 0}, {b: 4, e: 5}]; 462 | ``` 463 | 464 | 465 | ### inCache.bulkSet(records, [silent]) ⇒ Object \| undefined 466 | Set/update multiple records. This method not trigger any event. 467 | 468 | **Kind**: instance method of [InCache](#InCache) 469 | **Emits**: [beforeBulkSet](#InCache+event_beforeBulkSet), [bulkSet](#InCache+event_bulkSet) 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 480 | 481 | 483 | 484 |
ParamTypeDefaultDescription
recordsArray

e.g. [{key: foo1, value: bar1},{key: foo2, value: bar2}]

479 |
[silent]booleanfalse

if true no event will be triggered

482 |
485 | 486 | **Example** 487 | ```js 488 | inCache.bulkSet([ {key: 'my key 1', value: 'my value 1'}, {key: 'my key 2', value: 'my value 2'}, {key: 'my key 3', value: 'my value 3'}, {key: 'my key 4', value: 'my value 4'} ]); // or inCache.bulkSet(['hello','world']); 489 | ``` 490 | 491 | 492 | ### inCache.bulkRemove(keys, [silent]) 493 | Delete multiple records 494 | 495 | **Kind**: instance method of [InCache](#InCache) 496 | **Emits**: [beforeBulkRemove](#InCache+event_beforeBulkRemove), [bulkRemove](#InCache+event_bulkRemove) 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 507 | 508 | 510 | 511 |
ParamTypeDefaultDescription
keysArray

an array of keys

506 |
[silent]booleanfalse

if true no event will be triggered

509 |
512 | 513 | **Example** 514 | ```js 515 | inCache.bulkRemove(['key1', 'key2', 'key3']); 516 | ``` 517 | 518 | 519 | ### inCache.clean(key) 520 | Delete multiple records that contain the passed keyword 521 | 522 | **Kind**: instance method of [InCache](#InCache) 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 533 | 534 |
ParamTypeDescription
keystring

a string that is relative to a group of keys

532 |
535 | 536 | **Example** 537 | ```js 538 | inCache.set('/api/users/foo', 'Mario Rossi'); inCache.set('/api/users/bar', 'Antonio Bianchi'); inCache.clean('/api/users'); 539 | ``` 540 | 541 | 542 | ### inCache.all(asObject) ⇒ \* 543 | Fetch all records 544 | 545 | **Kind**: instance method of [InCache](#InCache) 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 |
ParamDefault
asObjectfalse
557 | 558 | 559 | 560 | ### inCache.count() ⇒ Number 561 | Returns total of records in storage 562 | 563 | **Kind**: instance method of [InCache](#InCache) 564 | **Since**: 6.0.0 565 | 566 | 567 | ### inCache.expired(key) ⇒ boolean 568 | Check if record is expired 569 | 570 | **Kind**: instance method of [InCache](#InCache) 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 |
ParamType
keystring
582 | 583 | 584 | 585 | ### inCache.clear() 586 | Remove all records 587 | 588 | **Kind**: instance method of [InCache](#InCache) 589 | 590 | 591 | ### inCache.has(key) ⇒ boolean 592 | Check if key exists 593 | 594 | **Kind**: instance method of [InCache](#InCache) 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 |
ParamType
keystring
606 | 607 | **Example** 608 | ```js 609 | inCache.has('my key'); 610 | ``` 611 | 612 | 613 | ### inCache.destroy(...args) 614 | Alias of `remove` 615 | 616 | **Kind**: instance method of [InCache](#InCache) 617 | **Since**: 4.1.1 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 |
Param
...args
629 | 630 | 631 | 632 | ### inCache.stats() ⇒ Object 633 | Returns stats of storage 634 | 635 | **Kind**: instance method of [InCache](#InCache) 636 | **Since**: 6.3.0 637 | 638 | 639 | ### inCache.canBeAutoRemove(key) ⇒ boolean \| \* 640 | Check if key can be auto removed 641 | 642 | **Kind**: instance method of [InCache](#InCache) 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 |
Param
key
654 | 655 | 656 | 657 | ### inCache.onRemoved(callback) 658 | ***Deprecated*** 659 | 660 | Triggered when a record has been deleted. **Deprecated since 5.0.0:** use `on('remove', callback)` instead. 661 | 662 | **Kind**: instance method of [InCache](#InCache) 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 673 | 674 |
ParamTypeDescription
callbackremovedCallback

callback function

672 |
675 | 676 | **Example** 677 | ```js 678 | inCache.onRemoved((key)=>{ console.log('removed', key); }); 679 | ``` 680 | 681 | 682 | ### inCache.onCreated(callback) 683 | ***Deprecated*** 684 | 685 | Triggered when a record has been created. **Deprecated since 5.0.0:** use `on('create', callback)` instead 686 | 687 | **Kind**: instance method of [InCache](#InCache) 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 698 | 699 |
ParamTypeDescription
callbackcreatedCallback

callback function

697 |
700 | 701 | **Example** 702 | ```js 703 | inCache.onCreated((key, record)=>{ console.log('created', key, record); }); 704 | ``` 705 | 706 | 707 | ### inCache.onUpdated(callback) 708 | ***Deprecated*** 709 | 710 | Triggered when a record has been updated. **Deprecated since 5.0.0:** use `on('update', callback)` instead 711 | 712 | **Kind**: instance method of [InCache](#InCache) 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 723 | 724 |
ParamTypeDescription
callbackupdatedCallback

callback function

722 |
725 | 726 | **Example** 727 | ```js 728 | inCache.onUpdated((key, record)=>{ console.log('updated', key, record); }); 729 | ``` 730 | 731 | 732 | ### "beforeGet" (key, record) 733 | Triggered before get 734 | 735 | **Kind**: event emitted by [InCache](#InCache) 736 | **Since**: 7.2.0 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 747 | 748 | 750 | 751 |
ParamTypeDescription
keystring

key

746 |
recordrecord

record object

749 |
752 | 753 | 754 | 755 | ### "get" (key, record) 756 | Triggered after get 757 | 758 | **Kind**: event emitted by [InCache](#InCache) 759 | **Since**: 7.2.0 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 770 | 771 | 773 | 774 |
ParamTypeDescription
keystring

key

769 |
recordrecord

record object

772 |
775 | 776 | 777 | 778 | ### "beforeSet" (key, value) 779 | Triggered before set 780 | 781 | **Kind**: event emitted by [InCache](#InCache) 782 | **Since**: 5.0.0 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 793 | 794 | 796 | 797 |
ParamTypeDescription
keystring

key

792 |
valuestring

value

795 |
798 | 799 | 800 | 801 | ### "set" (key, record) 802 | Triggered after set 803 | 804 | **Kind**: event emitted by [InCache](#InCache) 805 | **Since**: 5.0.0 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 816 | 817 | 819 | 820 |
ParamTypeDescription
keystring

key

815 |
recordrecord

record object

818 |
821 | 822 | 823 | 824 | ### "create" (key, record) 825 | Triggered after create the record 826 | 827 | **Kind**: event emitted by [InCache](#InCache) 828 | **Since**: 5.0.0 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 839 | 840 | 842 | 843 |
ParamTypeDescription
keystring

key of record

838 |
recordrecord

record object

841 |
844 | 845 | 846 | 847 | ### "update" (key, record) 848 | Triggered after update the record 849 | 850 | **Kind**: event emitted by [InCache](#InCache) 851 | **Since**: 5.0.0 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 862 | 863 | 865 | 866 |
ParamTypeDescription
keystring

key of record

861 |
recordrecord

record object

864 |
867 | 868 | 869 | 870 | ### "beforeRemove" (key) 871 | Triggered before remove the record 872 | 873 | **Kind**: event emitted by [InCache](#InCache) 874 | **Since**: 5.0.0 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 885 | 886 |
ParamTypeDescription
keystring

key of record to be removed

884 |
887 | 888 | 889 | 890 | ### "remove" (key) 891 | Triggered after record has been removed 892 | 893 | **Kind**: event emitted by [InCache](#InCache) 894 | **Since**: 5.0.0 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 905 | 906 |
ParamTypeDescription
keystring

key of record

904 |
907 | 908 | 909 | 910 | ### "beforeBulkSet" (records) 911 | Triggered before bulk set 912 | 913 | **Kind**: event emitted by [InCache](#InCache) 914 | **Since**: 5.0.0 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 925 | 926 |
ParamTypeDescription
recordsArray

array of objects

924 |
927 | 928 | 929 | 930 | ### "bulkSet" (records) 931 | Triggered after bulk set 932 | 933 | **Kind**: event emitted by [InCache](#InCache) 934 | **Since**: 5.0.0 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 945 | 946 |
ParamTypeDescription
recordsArray

array of objects

944 |
947 | 948 | 949 | 950 | ### "beforeBulkRemove" (keys) 951 | Triggered before remove the records 952 | 953 | **Kind**: event emitted by [InCache](#InCache) 954 | **Since**: 5.0.0 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 965 | 966 |
ParamTypeDescription
keysArray

array of keys to be removed

964 |
967 | 968 | 969 | 970 | ### "bulkRemove" (keys) 971 | Triggered after records have been removed 972 | 973 | **Kind**: event emitted by [InCache](#InCache) 974 | **Since**: 5.0.0 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 985 | 986 |
ParamTypeDescription
keysArray

array of keys removed

984 |
987 | 988 | 989 | 990 | ### "expired" (keys) 991 | Triggered when records are expired and `opts.autoRemovePeriod` is set 992 | 993 | **Kind**: event emitted by [InCache](#InCache) 994 | **Since**: 5.0.0 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1005 | 1006 |
ParamTypeDescription
keysArray

array of keys expired

1004 |
1007 | 1008 | 1009 | 1010 | ### "beforeLoad" (me) 1011 | Triggered before load (only if `autoLoad` is false) 1012 | 1013 | **Kind**: event emitted by [InCache](#InCache) 1014 | **Since**: 6.4.0 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 |
ParamType
meInCache
1026 | 1027 | 1028 | 1029 | ### "load" (err, me) 1030 | Triggered after load invocation 1031 | 1032 | **Kind**: event emitted by [InCache](#InCache) 1033 | **Since**: 6.0.0 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1044 | 1045 | 1046 | 1047 |
ParamTypeDescription
errnull | string

error message, if no errors occurred is null

1043 |
meInCache
1048 | 1049 | 1050 | 1051 | ### "beforeSave" (me) 1052 | Triggered before save 1053 | 1054 | **Kind**: event emitted by [InCache](#InCache) 1055 | **Since**: 6.4.0 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 |
ParamType
meInCache
1067 | 1068 | 1069 | 1070 | ### "save" (err, me) 1071 | Triggered after save invocation 1072 | 1073 | **Kind**: event emitted by [InCache](#InCache) 1074 | **Since**: 6.0.0 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1085 | 1086 | 1087 | 1088 |
ParamTypeDescription
errnull | string

error message, if no errors occurred is null

1084 |
meInCache
1089 | 1090 | 1091 | 1092 | ### "change" (by) 1093 | Triggered when data is changed 1094 | 1095 | **Kind**: event emitted by [InCache](#InCache) 1096 | **Since**: 6.1.0 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1107 | 1108 |
ParamTypeDescription
bystring

event called by set,remove,clear or clean

1106 |
1109 | 1110 | 1111 | 1112 | ### "exceed" (diff) 1113 | Triggered when data exceed max size 1114 | 1115 | **Kind**: event emitted by [InCache](#InCache) 1116 | **Since**: 6.1.0 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1127 | 1128 |
ParamTypeDescription
diffnumber

exceeded by record number

1126 |
1129 | 1130 | 1131 | 1132 | ### InCache.isRecord(obj) ⇒ boolean 1133 | Check if object is a InCache~record 1134 | 1135 | **Kind**: static method of [InCache](#InCache) 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1146 | 1147 |
ParamTypeDescription
objrecord

InCache record

1145 |
1148 | 1149 | 1150 | 1151 | ### InCache~record : Object 1152 | InCache record 1153 | 1154 | **Kind**: inner typedef of [InCache](#InCache) 1155 | **Properties** 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1167 | 1168 | 1170 | 1171 | 1173 | 1174 | 1176 | 1177 | 1179 | 1180 | 1182 | 1183 | 1185 | 1186 | 1188 | 1189 | 1191 | 1192 | 1194 | 1195 |
NameTypeDescription
idstring

uuid

1166 |
isNewboolean

indicates if is a new record

1169 |
isPreservedboolean

indicates if record will no longer be editable once created

1172 |
toDeleteboolean

indicates if record will be deleted after expiry

1175 |
hitsnumber

how many times it has been used

1178 |
lastHitDate | null

last usage

1181 |
createdOnDate | null

creation date

1184 |
updatedOnDate | null

update date

1187 |
expiresOnDate | null

expiry date

1190 |
value*

record value

1193 |
1196 | 1197 | 1198 | 1199 | ### InCache~recordInfo : Object 1200 | InCache recordInfo 1201 | 1202 | **Kind**: inner typedef of [InCache](#InCache) 1203 | **Properties** 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1215 | 1216 | 1218 | 1219 | 1221 | 1222 | 1224 | 1225 | 1227 | 1228 | 1230 | 1231 | 1233 | 1234 | 1236 | 1237 | 1239 | 1240 |
NameTypeDescription
idstring

uuid

1214 |
isNewboolean

indicates if is a new record

1217 |
isPreservedboolean

indicates if record will no longer be editable once created

1220 |
toDeleteboolean

indicates if record will be deleted after expiry

1223 |
hitsnumber

how many times it has been used

1226 |
lastHitDate | null

last usage

1229 |
createdOnDate | null

creation date

1232 |
updatedOnDate | null

update date

1235 |
expiresOnDate | null

expiry date

1238 |
1241 | 1242 | 1243 | 1244 | ### InCache~removedCallback : function 1245 | ***Deprecated*** 1246 | 1247 | onRemoved callback 1248 | 1249 | **Kind**: inner typedef of [InCache](#InCache) 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1260 | 1261 |
ParamTypeDescription
keystring

key of record removed

1259 |
1262 | 1263 | 1264 | 1265 | ### InCache~createdCallback : function 1266 | ***Deprecated*** 1267 | 1268 | onCreated callback 1269 | 1270 | **Kind**: inner typedef of [InCache](#InCache) 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1281 | 1282 | 1284 | 1285 |
ParamTypeDescription
keystring

key of record created

1280 |
recordrecord

record object

1283 |
1286 | 1287 | 1288 | 1289 | ### InCache~updatedCallback : function 1290 | ***Deprecated*** 1291 | 1292 | onUpdated callback 1293 | 1294 | **Kind**: inner typedef of [InCache](#InCache) 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1305 | 1306 | 1308 | 1309 |
ParamTypeDescription
keystring

key of record updated

1304 |
recordrecord

record object

1307 |
1310 | 1311 | 1312 | 1313 | ## SAVE_MODE 1314 | **Kind**: global constant 1315 | 1316 | * [SAVE_MODE](#SAVE_MODE) 1317 | * [.TERMINATE](#SAVE_MODE.TERMINATE) 1318 | * [.TIMER](#SAVE_MODE.TIMER) 1319 | 1320 | 1321 | 1322 | ### SAVE_MODE.TERMINATE 1323 | **Kind**: static property of [SAVE_MODE](#SAVE_MODE) 1324 | 1325 | 1326 | ### SAVE_MODE.TIMER 1327 | **Kind**: static property of [SAVE_MODE](#SAVE_MODE) 1328 | -------------------------------------------------------------------------------- /examples/auto-load/app.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../../src/incache'); 2 | 3 | new InCache({ 4 | autoLoad: true, 5 | filePath: 'cache.json' 6 | }).on('load', (err, me) => { 7 | if(!err) 8 | console.log('load', me.get('a key')); 9 | }); -------------------------------------------------------------------------------- /examples/auto-load/cache.json: -------------------------------------------------------------------------------- 1 | {"a key":{"id":"034953b0-b057-11e7-818a-5798d0166a8f","isNew":false,"isPreserved":false,"toDelete":true,"hits":2,"lastHit":"2017-10-13T20:54:51.060Z","createdOn":"2017-10-13T20:42:22.187Z","updatedOn":"2017-10-13T20:54:51.045Z","expiresOn":null,"value":"a value"}} -------------------------------------------------------------------------------- /examples/auto-save/app-terminate.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../../src/incache'); 2 | 3 | const store = new InCache({ 4 | autoSave: true, 5 | autoSaveMode: InCache.SAVE_MODE.TERMINATE, 6 | filePath: 'cache-terminate.json' 7 | }); 8 | 9 | store.set('a key', 'a value'); 10 | 11 | console.log(store.get('a key')); -------------------------------------------------------------------------------- /examples/auto-save/app-timer.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../../src/incache'); 2 | 3 | const store = new InCache({ 4 | autoSave: true, 5 | autoSaveMode: InCache.SAVE_MODE.TIMER, 6 | filePath: 'cache-timer.json' 7 | }).on('beforeSave', () => { 8 | console.log('before save'); 9 | }).on('save', () => { 10 | console.log('save'); 11 | }); 12 | 13 | store.set('a key', 'a value'); 14 | 15 | console.log(store.get('a key')); -------------------------------------------------------------------------------- /examples/basic/app.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../../src/incache'); 2 | 3 | const store = new InCache(); 4 | 5 | store.set('a key', 'a value'); 6 | 7 | console.log(store.get('a key')); -------------------------------------------------------------------------------- /examples/browser-auto-save/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | browser-save 6 | 7 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /examples/browser-save/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | browser-save 6 | 7 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/load/app.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../../src/incache'); 2 | 3 | const store = new InCache({ 4 | autoLoad: false, 5 | filePath: 'cache.json' 6 | }).on('beforeLoad', () => { 7 | console.log('beforeLoad'); 8 | }).on('load', (err, me) => { 9 | if(!err) 10 | console.log('load', me.get('a key')); 11 | }); 12 | 13 | store.load().then(me => { 14 | console.log(me); 15 | }).catch(e => { 16 | console.log(e); 17 | }); -------------------------------------------------------------------------------- /examples/load/cache.json: -------------------------------------------------------------------------------- 1 | {"a key":{"id":"034953b0-b057-11e7-818a-5798d0166a8f","isNew":false,"isPreserved":false,"toDelete":true,"hits":2,"lastHit":"2017-10-13T20:54:51.060Z","createdOn":"2017-10-13T20:42:22.187Z","updatedOn":"2017-10-13T20:54:51.045Z","expiresOn":null,"value":"a value"}} -------------------------------------------------------------------------------- /examples/save/app.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../../src/incache'); 2 | 3 | const store = new InCache() 4 | .on('save', () => { 5 | console.log('save'); 6 | }); 7 | 8 | store.set('a key', 'a value'); 9 | 10 | store.save('cache.json').then(me => { 11 | console.log('save, promise response'); 12 | }).catch(e => { 13 | console.log(e); 14 | }); -------------------------------------------------------------------------------- /extra/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fabioricali/incache/9fca2549277591c8b8a5a33e09ae58c7eac1b4f1/extra/logo.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/incache'); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "incache", 3 | "version": "7.2.1", 4 | "description": "Powerful key/value in-memory storage or on disk to persist some data", 5 | "main": "index.js", 6 | "browser": "dist/incache.js", 7 | "scripts": { 8 | "version:major": "webpack --env.major && npm run-script doc && version-to-tag.sh && npm publish", 9 | "version:minor": "webpack --env.minor && npm run-script doc && version-to-tag.sh && npm publish", 10 | "version:patch": "webpack --env.patch && npm run-script doc && version-to-tag.sh && npm publish", 11 | "build": "webpack --progress", 12 | "mocha.test": "mocha test", 13 | "test": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", 14 | "doc": "jsdoc2md --no-gfm src/incache.js > api.md", 15 | "benchmark:app": "node ./test/app/index.js", 16 | "benchmark:koa": "node ./node_modules/autocannon/autocannon -c 100 -d 1 -p 10 127.0.0.1:3188/benchmark/notCached", 17 | "benchmark:cache": "node ./node_modules/autocannon/autocannon -c 100 -d 1 -p 10 127.0.0.1:3188/benchmark/cached" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/fabioricali/incache.git" 22 | }, 23 | "keywords": [ 24 | "cache", 25 | "object", 26 | "global", 27 | "storage", 28 | "share", 29 | "node-cache", 30 | "localstorage", 31 | "session", 32 | "database", 33 | "db" 34 | ], 35 | "author": "Fabio Ricali", 36 | "license": "MIT", 37 | "bugs": { 38 | "url": "https://github.com/fabioricali/incache/issues" 39 | }, 40 | "homepage": "https://github.com/fabioricali/incache#readme", 41 | "devDependencies": { 42 | "autocannon": "^0.16.5", 43 | "babel-core": "^6.26.0", 44 | "babel-loader": "^7.1.2", 45 | "babel-preset-es2015": "^6.24.1", 46 | "bejs": "^1.12.2", 47 | "browser-env": "^3.2.0", 48 | "coveralls": "^2.13.1", 49 | "execution-time": "^1.2.0", 50 | "istanbul": "^0.4.5", 51 | "jsdoc-to-markdown": "^3.0.0", 52 | "koa": "^2.3.0", 53 | "koa-router": "^7.2.1", 54 | "mocha": "^3.5.0", 55 | "mocha-lcov-reporter": "^1.3.0", 56 | "mock-local-storage": "^1.0.5", 57 | "typis": "^1.0.2", 58 | "unminified-webpack-plugin": "^1.2.0", 59 | "webpack": "^3.5.5", 60 | "webpack-auto-inject-version": "^0.5.14" 61 | }, 62 | "dependencies": { 63 | "clone": "^2.1.1", 64 | "flak": "^1.0.0", 65 | "object-sizeof": "^1.2.0", 66 | "uuid": "^3.1.0", 67 | "write": "^1.0.3" 68 | } 69 | } -------------------------------------------------------------------------------- /src/defined.js: -------------------------------------------------------------------------------- 1 | /* istanbul ignore */ 2 | 3 | exports.SAVE_MODE = Object.defineProperties({}, { 4 | TERMINATE: { 5 | value: 'terminate', 6 | enumerable: true 7 | }, 8 | TIMER: { 9 | value: 'timer', 10 | enumerable: true 11 | } 12 | }); 13 | 14 | exports.REMOVE_EXCEED = Object.defineProperties({}, { 15 | OLDER: { 16 | value: 'older', 17 | enumerable: true 18 | }, 19 | USAGE: { 20 | value: 'usage', 21 | enumerable: true 22 | }, 23 | NONE: { 24 | value: 'none', 25 | enumerable: true 26 | } 27 | }); 28 | 29 | exports.RECORD = { 30 | id: null, 31 | isNew: true, 32 | isPreserved: null, 33 | toDelete: null, 34 | hits: null, 35 | lastHit: null, 36 | createdOn: null, 37 | updatedOn: null, 38 | expiresOn: null, 39 | value: null 40 | }; -------------------------------------------------------------------------------- /src/helper.js: -------------------------------------------------------------------------------- 1 | const helper = {}; 2 | 3 | /** 4 | * Get object type 5 | * @param object {*} 6 | * @param type {string} 7 | * @returns {boolean} 8 | */ 9 | helper.is = (object, type) => { 10 | let objectToString = Object.prototype.toString.call(object); 11 | return objectToString.toLowerCase() === '[object ' + type + ']'.toLowerCase(); 12 | }; 13 | 14 | /** 15 | * Set default value 16 | * @param opts {Object} options 17 | * @param defaultOpts {Object} default options 18 | * @returns {*} 19 | */ 20 | helper.defaults = (opts, defaultOpts) => { 21 | for (let i in defaultOpts) { 22 | if(defaultOpts.hasOwnProperty(i)) 23 | if (!opts.hasOwnProperty(i)) { 24 | opts[i] = defaultOpts[i]; 25 | } else { 26 | if (typeof opts[i] === 'object' && opts[i] !== null) { 27 | helper.defaults(opts[i], defaultOpts[i]); 28 | } 29 | } 30 | } 31 | return opts; 32 | }; 33 | 34 | /** 35 | * Adds seconds to current date 36 | * @param seconds {number} number of seconds to add 37 | * @returns {Date} 38 | * @deprecated 39 | */ 40 | helper.addSecondsToNow = (seconds) => { 41 | let now = new Date(); 42 | return new Date(now.setSeconds(now.getSeconds() + seconds)); 43 | }; 44 | 45 | /** 46 | * Adds milliseconds to current date 47 | * @param ms {number} number of milliseconds to add 48 | * @returns {Date} 49 | */ 50 | helper.addMSToNow = (ms) => { 51 | let now = new Date(); 52 | return new Date(now.setMilliseconds(now.getMilliseconds() + ms)); 53 | }; 54 | 55 | /** 56 | * Check if is Node environment 57 | * @returns {boolean} 58 | */ 59 | helper.isServer = () => { 60 | //return typeof process === 'object' && typeof process.pid !== 'undefined'; 61 | return typeof window === 'undefined'; 62 | }; 63 | 64 | /** 65 | * Throw deprecated 66 | * @param prop 67 | * @param msg 68 | * @param [type=warn] 69 | */ 70 | helper.deprecated = (prop, msg, type='warn') => { 71 | if(typeof prop !== 'undefined') { 72 | console[type](msg || prop); 73 | return true; 74 | } 75 | return false; 76 | }; 77 | 78 | /** 79 | * Throw error 80 | * @param msg 81 | */ 82 | helper.throwError = (msg) => { 83 | throw new Error(msg); 84 | }; 85 | 86 | module.exports = helper; -------------------------------------------------------------------------------- /src/incache.js: -------------------------------------------------------------------------------- 1 | const helper = require('./helper'); 2 | const Flak = require('flak'); 3 | const fs = require('fs'); 4 | const write = require('write'); 5 | const uuid = require('uuid/v1'); 6 | const clone = require('clone'); 7 | const sizeOf = require('object-sizeof'); 8 | const {SAVE_MODE, RECORD} = require('./defined'); 9 | 10 | /** 11 | * @constant SAVE_MODE 12 | */ 13 | 14 | /** 15 | * @memberOf SAVE_MODE 16 | * @name TERMINATE 17 | */ 18 | 19 | /** 20 | * @memberOf SAVE_MODE 21 | * @name TIMER 22 | */ 23 | 24 | /** 25 | * InCache record 26 | * @typedef {Object} InCache~record 27 | * @property {string} id - uuid 28 | * @property {boolean} isNew - indicates if is a new record 29 | * @property {boolean} isPreserved - indicates if record will no longer be editable once created 30 | * @property {boolean} toDelete - indicates if record will be deleted after expiry 31 | * @property {number} hits - how many times it has been used 32 | * @property {Date|null} lastHit - last usage 33 | * @property {Date|null} createdOn - creation date 34 | * @property {Date|null} updatedOn - update date 35 | * @property {Date|null} expiresOn - expiry date 36 | * @property {*} value - record value 37 | */ 38 | 39 | 40 | /** 41 | * InCache recordInfo 42 | * @typedef {Object} InCache~recordInfo 43 | * @property {string} id - uuid 44 | * @property {boolean} isNew - indicates if is a new record 45 | * @property {boolean} isPreserved - indicates if record will no longer be editable once created 46 | * @property {boolean} toDelete - indicates if record will be deleted after expiry 47 | * @property {number} hits - how many times it has been used 48 | * @property {Date|null} lastHit - last usage 49 | * @property {Date|null} createdOn - creation date 50 | * @property {Date|null} updatedOn - update date 51 | * @property {Date|null} expiresOn - expiry date 52 | */ 53 | 54 | /** 55 | * @class 56 | */ 57 | class InCache extends Flak { 58 | 59 | /** 60 | * Create instance 61 | * @param [opts] {Object} configuration object 62 | * @param [opts.maxAge=0] {number} max age in milliseconds. If 0 not expire. (overwritable by `set`) 63 | * @param [opts.expires] {Date|string} a Date for expiration. (overwrites `opts.maxAge`, overwritable by `set`) 64 | * @param [opts.silent=false] {boolean} if true no event will be triggered. (overwritable by `set`) 65 | * @param [opts.deleteOnExpires=true] {boolean} if false, the record will not be deleted after expiry. (overwritable by `set`) 66 | * @param [opts.clone=false] {boolean} if true, the object will be cloned before to put it in storage. (overwritable by `set`) 67 | * @param [opts.preserve=false] {boolean} if true, you will no longer be able to update the record once created. (overwritable by `set`) 68 | * @param [opts.maxRecordNumber=0] {number} the maximum of record number of the cache, if exceeded some records will be deleted. If 0 is disabled 69 | * @param [opts.autoLoad=true] {boolean} load cache from disk when instance is created. 70 | * @param [opts.autoSave=false] {boolean} if true saves cache in disk when the process is terminated. 71 | * @param [opts.autoSaveMode=terminate] {string} there are 2 modes -> "terminate": saves before the process is terminated (server only). "timer": every n seconds checks for new changes and save on disk. 72 | * @param [opts.autoSavePeriod=5] {number} period in seconds to check for new changes to save on disk. Works only if `opts.autoSaveMode` is set to 'timer' mode. 73 | * @param [opts.filePath=.incache] {string|*} cache file path or key. If is a falsy value, `load` and `save` will always be solved 74 | * @param [opts.storeName] {string} store name 75 | * @param [opts.share=false] {boolean} if true, use global object as storage 76 | * @param [opts.autoRemovePeriod=0] {number} period in seconds to remove expired records. When set, the records will be removed only on check, when 0 it won't run 77 | * @param [opts.nullIfNotFound=false] {boolean} calling `get` if the key is not found returns `null`. If false returns `undefined` 78 | * @param [opts.save=false] {boolean} **deprecated:** if true saves cache in disk when the process is terminated. Use `autoSave` instead. 79 | * @param [opts.global] {Object} **deprecated:** global record configuration 80 | * @param [opts.global.silent=false] {boolean} **deprecated:** if true no event will be triggered, use `silent` instead 81 | * @param [opts.global.life=0] {number} **deprecated:** max age in seconds. If 0 not expire, use `maxAge` instead 82 | * @fires InCache#expired 83 | * @fires InCache#change 84 | * @fires InCache#exceed 85 | * @constructor 86 | * @returns {InCache} 87 | */ 88 | constructor(opts = {}) { 89 | 90 | super(); 91 | 92 | Object.defineProperties(this, { 93 | _root: { 94 | writable: true, 95 | enumerable: false 96 | }, 97 | _storage: { 98 | writable: true, 99 | enumerable: false 100 | }, 101 | _memory: { 102 | writable: true, 103 | enumerable: false 104 | }, 105 | _opts: { 106 | writable: true, 107 | enumerable: false 108 | }, 109 | _timerExpiryCheck: { 110 | value: null, 111 | writable: true, 112 | enumerable: false 113 | }, 114 | _timerSaveCheck: { 115 | value: null, 116 | writable: true, 117 | enumerable: false 118 | }, 119 | GLOBAL_KEY: { 120 | writable: true, 121 | enumerable: false 122 | }, 123 | _lastChange: { 124 | value: null, 125 | writable: true, 126 | enumerable: false 127 | }, 128 | _lastChangeDetected: { 129 | value: null, 130 | writable: true, 131 | enumerable: false 132 | }, 133 | _lastSave: { 134 | value: null, 135 | writable: true, 136 | enumerable: false 137 | }, 138 | _saving: { 139 | value: false, 140 | writable: true, 141 | enumerable: false 142 | }, 143 | _loading: { 144 | value: false, 145 | writable: true, 146 | enumerable: false 147 | } 148 | }); 149 | 150 | /** 151 | * Global key 152 | * @type {string} 153 | * @ignore 154 | */ 155 | this.GLOBAL_KEY = '___InCache___storage___global___key___'; 156 | 157 | /** 158 | * InCache default configuration 159 | * @ignore 160 | */ 161 | this.DEFAULT_CONFIG = { 162 | storeName: '', 163 | autoLoad: true, 164 | autoSave: false, 165 | autoSaveMode: SAVE_MODE.TERMINATE, 166 | autoSavePeriod: 5, 167 | save: false, 168 | clone: false, 169 | preserve: false, 170 | deleteOnExpires: true, 171 | filePath: '.incache', 172 | maxAge: 0, 173 | maxRecordNumber: 0, 174 | expires: null, 175 | silent: false, 176 | share: false, 177 | autoRemovePeriod: 0, 178 | nullIfNotFound: false, 179 | global: { 180 | silent: false, 181 | life: 0 182 | } 183 | }; 184 | 185 | // Defines callback private 186 | this._onRemoved = () => { 187 | }; 188 | this._onCreated = () => { 189 | }; 190 | this._onUpdated = () => { 191 | }; 192 | 193 | this.on('_change', (by) => { 194 | this._lastChange = (new Date()).getTime(); 195 | if (!this._opts.silent) 196 | this.fire('change', by); 197 | }); 198 | 199 | this.setConfig(opts); 200 | 201 | //return this; 202 | } 203 | 204 | _checkExceeded() { 205 | if (!this._opts.maxRecordNumber) return; 206 | let keys = Object.keys(this._memory.data); 207 | /* istanbul ignore else */ 208 | if (keys.length > this._opts.maxRecordNumber) { 209 | let diff = keys.length - this._opts.maxRecordNumber; 210 | this.fire('exceed', diff); 211 | this.bulkRemove(keys.slice(0, diff), true); 212 | } 213 | } 214 | 215 | _importData(data) { 216 | /* istanbul ignore else */ 217 | if (helper.is(data, 'object')) { 218 | let keys = Object.keys(data); 219 | 220 | if (keys.length) { 221 | if (InCache.isRecord(data[keys[0]])) 222 | this._memory.data = data; 223 | else 224 | this.bulkSet(data, true); 225 | } 226 | 227 | } else if (helper.is(data, 'array')) { 228 | if (data.length) 229 | this.bulkSet(data, true); 230 | } else { 231 | throw new Error('bad data'); 232 | } 233 | 234 | } 235 | 236 | /** 237 | * Load cache from disk 238 | * @param [path=opts.filePath] {string} file path or key (browser scenario) 239 | * @fires InCache#beforeLoad 240 | * @fires InCache#load 241 | * @returns {Promise} 242 | * @since 6.0.0 243 | */ 244 | load(path = this._opts.filePath) { 245 | return new Promise( 246 | (resolve, reject) => { 247 | if (!path) return resolve(this); 248 | 249 | if (this._loading) return reject('loading locked'); 250 | 251 | /* istanbul ignore else */ 252 | if (this.fireTheFirst('beforeLoad', this) === false) { 253 | return reject(); 254 | } 255 | 256 | this._loading = true; 257 | 258 | try { 259 | let content = helper.isServer() ? fs.readFileSync(path) : window.localStorage.getItem(path); 260 | 261 | if (content === null) 262 | helper.throwError('content cannot is null'); 263 | 264 | this._importData(JSON.parse(content.toString())); 265 | this._loading = false; 266 | resolve(this); 267 | this.fireAsync('load', null, this); 268 | } catch (err) { 269 | err = err.message; 270 | this._loading = false; 271 | reject(err); 272 | this.fireAsync('load', err, this); 273 | } 274 | } 275 | ) 276 | } 277 | 278 | /** 279 | * Save cache into disk 280 | * @param [path=opts.filePath] {string} file path or key (browser scenario) 281 | * @fires InCache#beforeSave 282 | * @fires InCache#save 283 | * @returns {Promise} 284 | * @since 6.0.0 285 | */ 286 | save(path = this._opts.filePath) { 287 | return new Promise( 288 | (resolve, reject) => { 289 | if (!path) return resolve(this); 290 | 291 | if (this._saving) return reject('saving locked'); 292 | 293 | /* istanbul ignore else */ 294 | if (this.fireTheFirst('beforeSave', this) === false) { 295 | return reject(); 296 | } 297 | 298 | this._saving = true; 299 | 300 | let dataString = JSON.stringify(this._memory.data); 301 | 302 | try { 303 | if (helper.isServer()) 304 | write.sync(path, dataString, {}); 305 | else 306 | window.localStorage.setItem(path, dataString); 307 | 308 | this._lastSave = (new Date()).getTime(); 309 | this._saving = false; 310 | resolve(this); 311 | this.fireAsync('save', null, this); 312 | } catch (err) { 313 | err = err.message; 314 | this._saving = false; 315 | reject(err); 316 | this.fireAsync('save', err, this); 317 | } 318 | } 319 | ) 320 | } 321 | 322 | /** 323 | * Set configuration 324 | * @param [opts] {Object} configuration object 325 | * @see {@link constructor} for further information 326 | * @since 3.0.0 327 | */ 328 | setConfig(opts = {}) { 329 | 330 | /* istanbul ignore if */ 331 | if (opts.global) { 332 | helper.deprecated(opts.global.life, 'global.life is deprecated use maxAge instead'); 333 | helper.deprecated(opts.global.silent, 'global.silent is deprecated use silent instead'); 334 | } 335 | 336 | helper.defaults(opts, this.DEFAULT_CONFIG); 337 | 338 | this._opts = opts; 339 | 340 | /** 341 | * Root object 342 | * @ignore 343 | */ 344 | this._root = opts.share 345 | ? helper.isServer() 346 | ? global 347 | : window 348 | : {}; 349 | 350 | /* istanbul ignore else */ 351 | if (opts.storeName) 352 | this.GLOBAL_KEY += opts.storeName; 353 | 354 | /* istanbul ignore else */ 355 | if (!this._root[this.GLOBAL_KEY]) { 356 | this._root[this.GLOBAL_KEY] = { 357 | data: {} 358 | }; 359 | } 360 | 361 | this._memory = this._root[this.GLOBAL_KEY]; 362 | 363 | /* istanbul ignore else */ 364 | //if (helper.isServer()) { 365 | if (opts.autoLoad) 366 | this.load().then().catch((e) => { 367 | }); 368 | 369 | /* istanbul ignore else */ 370 | if (opts.autoSave || opts.save) { 371 | 372 | /* istanbul ignore else */ 373 | if (opts.autoSaveMode === SAVE_MODE.TERMINATE && helper.isServer()) { 374 | let self = this; 375 | 376 | // Wrap function 377 | function pWrite() { 378 | self.save().then().catch((e) => { 379 | }); 380 | } 381 | 382 | // Remove if event already exists 383 | process.removeListener('exit', pWrite); 384 | process.removeListener('SIGINT', pWrite); 385 | 386 | //process.stdin.resume(); 387 | process.on('exit', pWrite); 388 | process.on('SIGINT', pWrite); 389 | 390 | } else if (opts.autoSaveMode === SAVE_MODE.TIMER) { 391 | /* istanbul ignore else */ 392 | if (this._timerSaveCheck) { 393 | clearInterval(this._timerSaveCheck); 394 | this._timerSaveCheck = null; 395 | } 396 | 397 | process.on('SIGINT', ()=>{ 398 | process.exit(); 399 | }); 400 | 401 | /* istanbul ignore else */ 402 | if (opts.autoSavePeriod) { 403 | this._timerSaveCheck = setInterval(() => { 404 | if (this._lastChange !== this._lastChangeDetected) { 405 | this._lastChangeDetected = this._lastChange; 406 | this.save().then().catch(e => { 407 | }); 408 | } 409 | }, opts.autoSavePeriod * 1000); 410 | } 411 | } 412 | 413 | } 414 | //} 415 | 416 | /* istanbul ignore else */ 417 | if (this._timerExpiryCheck) { 418 | clearInterval(this._timerExpiryCheck); 419 | this._timerExpiryCheck = null; 420 | } 421 | 422 | /* istanbul ignore else */ 423 | if (opts.autoRemovePeriod) { 424 | this._timerExpiryCheck = setInterval(() => { 425 | let expired = this.removeExpired(); 426 | if (expired.length) { 427 | this.fire('expired', expired); 428 | } 429 | }, opts.autoRemovePeriod * 1000); 430 | } 431 | } 432 | 433 | /** 434 | * Get configuration 435 | * @returns {*} 436 | */ 437 | getConfig() { 438 | return this._opts; 439 | } 440 | 441 | /** 442 | * Set/update record 443 | * @param key {string} 444 | * @param value {*} 445 | * @param [opts] {Object} options object 446 | * @param [opts.silent=false] {boolean} if true no event will be triggered. (overwrites global configuration) 447 | * @param [opts.maxAge=0] {number} max age in milliseconds. If 0 not expire. (overwrites global configuration) 448 | * @param [opts.clone=false] {boolean} if true, the object will be cloned before to put it in storage. (overwrites global configuration) 449 | * @param [opts.preserve=false] {boolean} if true, you will no longer be able to update the record once created. (overwrites global configuration) 450 | * @param [opts.expires] {Date|string} a Date for expiration. (overwrites global configuration and `opts.maxAge`) 451 | * @param [opts.deleteOnExpires=true] {boolean} if false, the record will not be deleted after expiry. (overwrites global configuration) 452 | * @param [opts.life=0] {number} **deprecated:** max age in seconds. If 0 not expire. (overwrites global configuration) 453 | * @returns {InCache~record|*} 454 | * @fires InCache#beforeSet 455 | * @fires InCache#create 456 | * @fires InCache#update 457 | * @fires InCache#set 458 | * @example 459 | * inCache.set('my key', 'my value'); 460 | * inCache.set('my object', {a: 1, b: 2}); 461 | * inCache.set('my boolean', true, {maxAge: 2000}); // Expires after 2 seconds 462 | */ 463 | set(key, value, opts = {}) { 464 | 465 | /* istanbul ignore else */ 466 | if (!opts.silent && this.fireTheFirst('beforeSet', key, value) === false) { 467 | return; 468 | } 469 | 470 | opts = helper.defaults(opts, this._opts); 471 | 472 | /* istanbul ignore else */ 473 | if (this.has(key) && this._memory.data[key].isPreserved) { 474 | return; 475 | } 476 | 477 | /* istanbul ignore else */ 478 | if (opts.clone) { 479 | value = clone(value); 480 | } 481 | 482 | let record = Object.assign({}, RECORD); 483 | 484 | record.isNew = true; 485 | record.isPreserved = opts.preserve; 486 | record.toDelete = opts.deleteOnExpires; 487 | record.hits = 0; 488 | record.value = value; 489 | 490 | if (opts.expires && (helper.is(opts.expires, 'date') || helper.is(opts.expires, 'string'))) { 491 | record.expiresOn = new Date(opts.expires); 492 | } else if (opts.maxAge && helper.is(opts.maxAge, 'number')) { 493 | record.expiresOn = helper.addMSToNow(opts.maxAge); 494 | } else if (opts.life && helper.is(opts.life, 'number')) { 495 | helper.deprecated(opts.life, 'life is deprecated use maxAge instead'); 496 | record.expiresOn = helper.addSecondsToNow(opts.life); 497 | } 498 | 499 | if (this.has(key)) { 500 | record.isNew = false; 501 | record.hits = this._memory.data[key].hits; 502 | record.id = this._memory.data[key].id; 503 | record.createdOn = this._memory.data[key].createdOn; 504 | record.updatedOn = new Date(); 505 | if (!opts.silent) { 506 | this._onUpdated.call(this, key, record); 507 | this.fire('update', key, record); 508 | } 509 | } else { 510 | record.id = uuid(); 511 | record.createdOn = new Date(); 512 | if (!opts.silent) { 513 | this._onCreated.call(this, key, record); 514 | this.fire('create', key, record); 515 | } 516 | } 517 | 518 | this._memory.data[key] = record; 519 | 520 | if (!opts.silent) { 521 | this.fire('set', key, record); 522 | } 523 | 524 | this._checkExceeded(); 525 | 526 | this.fire('_change', 'set'); 527 | 528 | return record; 529 | } 530 | 531 | /** 532 | * Get record by key 533 | * @param key {string} 534 | * @param [onlyValue=true] {boolean} if false get InCache record 535 | * @returns {InCache~record|*|null|undefined} 536 | * @fires InCache#get 537 | * @fires InCache#beforeGet 538 | * @example 539 | * inCache.get('my key'); 540 | */ 541 | get(key, onlyValue = true) { 542 | if (this.has(key)) { 543 | if (this.canBeAutoRemove(key)) { 544 | this.remove(key, true); 545 | return (this._opts.nullIfNotFound ? null : undefined); 546 | } 547 | 548 | /* istanbul ignore else */ 549 | if (this.fireTheFirst('beforeGet', key, this._memory.data[key]) === false) { 550 | return; 551 | } 552 | 553 | this._memory.data[key].hits += 1; 554 | this._memory.data[key].lastHit = new Date(); 555 | 556 | this.fire('get', key, this._memory.data[key]); 557 | 558 | return onlyValue ? this._memory.data[key].value : this._memory.data[key]; 559 | } else { 560 | return (this._opts.nullIfNotFound ? null : undefined); 561 | } 562 | } 563 | 564 | /** 565 | * Get info record by key 566 | * @param key {string} 567 | * @returns {InCache~recordInfo|*|undefined} 568 | * @example 569 | * inCache.info('my key'); 570 | * @since 7.1.0 571 | */ 572 | info(key) { 573 | if (this.has(key)) { 574 | if (this.canBeAutoRemove(key)) { 575 | this.remove(key, true); 576 | return undefined; 577 | } 578 | 579 | const record = Object.assign({}, this._memory.data[key]); 580 | delete record.value; 581 | 582 | return record; 583 | } else { 584 | return undefined; 585 | } 586 | } 587 | 588 | /** 589 | * Delete a record 590 | * @param key {string} 591 | * @param [silent=false] {boolean} if true no event will be triggered 592 | * @fires InCache#beforeRemove 593 | * @fires InCache#remove 594 | * @example 595 | * inCache.remove('my key'); 596 | */ 597 | remove(key, silent = false) { 598 | if (!silent && this.fireTheFirst('beforeRemove', key) === false) { 599 | return; 600 | } 601 | delete this._memory.data[key]; 602 | if (!silent) { 603 | this._onRemoved.call(this, key); 604 | this.fire('remove', key); 605 | } 606 | this.fire('_change', 'remove'); 607 | } 608 | 609 | /** 610 | * Given a key that has value like an array removes key(s) if `where` is satisfied 611 | * @param key {string} 612 | * @param where {*} 613 | * @example 614 | * inCache.set('myArray', ['hello', 'world']); 615 | * inCache.removeFrom('myArray', 'hello'); //-> ['world']; 616 | * @since 3.0.0 617 | */ 618 | removeFrom(key, where) { 619 | if (!this.has(key)) return null; 620 | 621 | if (helper.is(where, 'undefined')) 622 | throw new Error('where cannot be undefined'); 623 | 624 | if (this._memory.data[key].isPreserved) { 625 | return; 626 | } 627 | 628 | let recordValue = this.get(key); 629 | 630 | if (!helper.is(recordValue, 'array')) 631 | throw new Error('value must be an array'); 632 | 633 | let recordLengthBefore = recordValue.length; 634 | for (let i in recordValue) { 635 | if (recordValue.hasOwnProperty(i)) { 636 | let result = []; 637 | for (let prop in where) { 638 | if (where.hasOwnProperty(prop)) 639 | if (helper.is(where, 'object')) 640 | result.push(typeof recordValue[i][prop] !== 'undefined' && recordValue[i][prop] === where[prop]); 641 | else 642 | result.push(recordValue[i] === where); 643 | } 644 | 645 | if (result.length && result.indexOf(false) === -1) 646 | recordValue.splice(i, 1); 647 | } 648 | } 649 | 650 | if (recordLengthBefore !== recordValue.length) { 651 | this.set(key, recordValue); 652 | } 653 | } 654 | 655 | /** 656 | * Remove expired records 657 | * @returns {Array} expired keys 658 | * @since 4.1.0 659 | * @example 660 | * inCache.set('my key 1', 'my value'); 661 | * inCache.set('my key 2', 'my value', {maxAge: 1000}); 662 | * inCache.set('my key 3', 'my value', {maxAge: 1500}); 663 | * setTimeout(()=>{ 664 | * inCache.removeExpired(); 665 | * inCache.all(); //-> [{key: 'my key 1', value: 'my value'}] 666 | * }, 2000) 667 | */ 668 | removeExpired() { 669 | const expired = []; 670 | for (let key in this._memory.data) { 671 | if (this._memory.data.hasOwnProperty(key) && this.expired(key) && this._memory.data[key].toDelete) { 672 | this.remove(key, true); 673 | expired.push(key); 674 | } 675 | } 676 | return expired; 677 | } 678 | 679 | /** 680 | * Given a key that has value like an array adds value to end of array 681 | * @param key {string} 682 | * @param value {*} 683 | * @returns {InCache~record|undefined} 684 | * @example 685 | * inCache.set('myArray', ['hello', 'world']); 686 | * inCache.addTo('myArray', 'ciao'); //-> ['hello', 'world', 'ciao']; 687 | * @since 3.0.0 688 | */ 689 | addTo(key, value) { 690 | if (!this.has(key)) return; 691 | let record = this.get(key); 692 | 693 | if (this._memory.data[key].isPreserved) { 694 | return; 695 | } 696 | 697 | if (!helper.is(record, 'array')) 698 | throw new Error('object must be an array'); 699 | 700 | record.push(value); 701 | 702 | return this.set(key, record); 703 | } 704 | 705 | /** 706 | * Given a key that has value like an array adds value to beginning of array 707 | * @param key {string} 708 | * @param value {*} 709 | * @returns {InCache~record|undefined} 710 | * @example 711 | * inCache.set('myArray', ['hello', 'world']); 712 | * inCache.prependTo('myArray', 'ciao'); //-> ['ciao', 'hello', 'world']; 713 | * @since 3.0.0 714 | */ 715 | prependTo(key, value) { 716 | if (!this.has(key)) return; 717 | 718 | if (this._memory.data[key].isPreserved) { 719 | return; 720 | } 721 | 722 | let record = this.get(key); 723 | 724 | if (!helper.is(record, 'array')) 725 | throw new Error('object must be an array'); 726 | 727 | record.unshift(value); 728 | 729 | return this.set(key, record); 730 | } 731 | 732 | 733 | /** 734 | * Given a key that has value like an array updates key(s) if `where` is satisfied 735 | * @param key {string} 736 | * @param value {*} 737 | * @param where {*} 738 | * @example 739 | * inCache.set('myArray', ['hello', 'world']); 740 | * inCache.updateIn('myArray', 'ciao', 'hello'); //-> ['ciao', 'world']; 741 | * 742 | * inCache.set('myArray', [{a: 1, b: 2, c: 3], {b: 2, c: 3}, {b: 4, e: 5}); 743 | * inCache.updateIn('myArray', {z: 0, x: 0}, {b: 2, c: 3}); //-> [{z: 0, x: 0}, {z: 0, x: 0}, {b: 4, e: 5}]; 744 | * @since 3.0.0 745 | */ 746 | updateIn(key, value, where) { 747 | if (!this.has(key)) return; 748 | 749 | if (helper.is(value, 'undefined')) 750 | throw new Error('value cannot be undefined'); 751 | 752 | if (helper.is(where, 'undefined')) 753 | throw new Error('where cannot be undefined'); 754 | 755 | if (this._memory.data[key].isPreserved) { 756 | return; 757 | } 758 | 759 | let recordValue = this.get(key); 760 | 761 | if (!helper.is(recordValue, 'array')) 762 | throw new Error('value must be an array'); 763 | 764 | let updated = false; 765 | for (let i in recordValue) { 766 | if (recordValue.hasOwnProperty(i)) { 767 | let result = []; 768 | for (let prop in where) { 769 | if (where.hasOwnProperty(prop)) 770 | if (helper.is(where, 'object')) 771 | result.push(typeof recordValue[i][prop] !== 'undefined' && recordValue[i][prop] === where[prop]); 772 | else 773 | result.push(recordValue[i] === where); 774 | } 775 | 776 | if (result.length && result.indexOf(false) === -1) { 777 | updated = true; 778 | recordValue[i] = value; 779 | } 780 | } 781 | } 782 | 783 | if (updated) { 784 | this.set(key, recordValue); 785 | } 786 | } 787 | 788 | /** 789 | * Set/update multiple records. This method not trigger any event. 790 | * @param records {Array} e.g. [{key: foo1, value: bar1},{key: foo2, value: bar2}] 791 | * @param [silent=false] {boolean} if true no event will be triggered 792 | * @fires InCache#beforeBulkSet 793 | * @fires InCache#bulkSet 794 | * @example 795 | * inCache.bulkSet([ 796 | * {key: 'my key 1', value: 'my value 1'}, 797 | * {key: 'my key 2', value: 'my value 2'}, 798 | * {key: 'my key 3', value: 'my value 3'}, 799 | * {key: 'my key 4', value: 'my value 4'} 800 | * ]); 801 | * // or 802 | * inCache.bulkSet(['hello','world']); 803 | * 804 | * @returns {{}|undefined} 805 | */ 806 | bulkSet(records, silent = false) { 807 | if (!helper.is(records, 'array') && !helper.is(records, 'object')) 808 | throw new Error('records must be an array, e.g. {key: foo, value: bar}'); 809 | 810 | if (!silent && this.fireTheFirst('beforeBulkSet', records) === false) { 811 | return; 812 | } 813 | 814 | const result = {}; 815 | let record; 816 | 817 | for (let i = 0; i < records.length; i++) { 818 | 819 | if (!helper.is(records[i].key, 'undefined') && !helper.is(records[i].value, 'undefined')) { 820 | record = this.set(records[i].key, records[i].value, {silent: true, fromBulk: true}); 821 | if (record) 822 | result[records[i].key] = record; 823 | } else { 824 | record = this.set(i, records[i], {silent: true, fromBulk: true}); 825 | if (record) 826 | result[i] = record; 827 | } 828 | 829 | } 830 | 831 | if (!silent) { 832 | this.fire('bulkSet', records); 833 | } 834 | 835 | return result; 836 | } 837 | 838 | /** 839 | * Delete multiple records 840 | * @param keys {Array} an array of keys 841 | * @param [silent=false] {boolean} if true no event will be triggered 842 | * @fires InCache#beforeBulkRemove 843 | * @fires InCache#bulkRemove 844 | * @example 845 | * inCache.bulkRemove(['key1', 'key2', 'key3']); 846 | */ 847 | bulkRemove(keys, silent) { 848 | if (!helper.is(keys, 'array')) 849 | throw new Error('keys must be an array of keys'); 850 | 851 | if (!silent && this.fireTheFirst('beforeBulkRemove', keys) === false) { 852 | return; 853 | } 854 | 855 | for (let i = 0; i < keys.length; i++) { 856 | this.remove(keys[i], true); 857 | } 858 | 859 | if (!silent) { 860 | this.fire('bulkRemove', keys); 861 | } 862 | } 863 | 864 | /** 865 | * Delete multiple records that contain the passed keyword 866 | * @param key {string} a string that is relative to a group of keys 867 | * @example 868 | * inCache.set('/api/users/foo', 'Mario Rossi'); 869 | * inCache.set('/api/users/bar', 'Antonio Bianchi'); 870 | * inCache.clean('/api/users'); 871 | */ 872 | clean(key) { 873 | if (!helper.is(key, 'string')) 874 | throw new Error('key must be a string'); 875 | 876 | for (let k in this._memory.data) { 877 | if (this._memory.data.hasOwnProperty(k) && k.indexOf(key) !== -1) { 878 | delete this._memory.data[k]; 879 | this.fire('_change', 'clean'); 880 | } 881 | } 882 | } 883 | 884 | /** 885 | * Fetch all records 886 | * @param asObject 887 | * @returns {*} 888 | */ 889 | all(asObject = false) { 890 | let records = asObject ? {} : []; 891 | 892 | for (let key in this._memory.data) { 893 | if (this._memory.data.hasOwnProperty(key)) { 894 | if (this.canBeAutoRemove(key)) { 895 | this.remove(key, true); 896 | } else { 897 | if (Array.isArray(records)) { 898 | records.push({ 899 | key: key, 900 | value: this._memory.data[key].value 901 | }); 902 | } else { 903 | records[key] = this._memory.data[key].value; 904 | } 905 | } 906 | } 907 | } 908 | 909 | return records; 910 | } 911 | 912 | /** 913 | * Returns total of records in storage 914 | * @returns {Number} 915 | * @since 6.0.0 916 | */ 917 | count() { 918 | this.removeExpired(); 919 | return Object.keys(this._memory.data).length; 920 | } 921 | 922 | /** 923 | * Check if record is expired 924 | * @param key {string} 925 | * @returns {boolean} 926 | */ 927 | expired(key) { 928 | if (this._memory.data[key] && this._memory.data[key].expiresOn) { 929 | let now = new Date(); 930 | let expiry = new Date(this._memory.data[key].expiresOn); 931 | return now > expiry; 932 | } else { 933 | return false; 934 | } 935 | } 936 | 937 | /** 938 | * Remove all records 939 | */ 940 | clear() { 941 | /** 942 | * Reset object 943 | * @ignore 944 | */ 945 | this._memory.data = {}; 946 | this.fire('_change', 'clear'); 947 | } 948 | 949 | /** 950 | * Check if key exists 951 | * @param key {string} 952 | * @returns {boolean} 953 | * @example 954 | * inCache.has('my key'); 955 | */ 956 | has(key) { 957 | return this._memory.data.hasOwnProperty(key); 958 | } 959 | 960 | /** 961 | * Alias of `remove` 962 | * @borrows remove as destroy 963 | * @param args 964 | * @since 4.1.1 965 | */ 966 | destroy(...args) { 967 | this.remove.apply(this, args); 968 | } 969 | 970 | /** 971 | * Returns stats of storage 972 | * @returns {{count: Number, size: Number}} 973 | * @since 6.3.0 974 | */ 975 | stats() { 976 | return { 977 | count: this.count(), 978 | size: sizeOf(this._memory.data) 979 | } 980 | } 981 | 982 | /** 983 | * Check if key can be auto removed 984 | * @param key 985 | * @returns {boolean|*} 986 | */ 987 | canBeAutoRemove(key) { 988 | return !this._opts.autoRemovePeriod && this.expired(key) && this._memory.data[key].toDelete 989 | } 990 | 991 | /** 992 | * Adds listener to instance 993 | * @param eventName {string} event name 994 | * @param callback {Function} callback 995 | * @returns {InCache} 996 | */ 997 | 998 | /** 999 | * Suspends firing of the named event(s). 1000 | * @param eventName {...string} multiple event names to suspend 1001 | * @returns {InCache} 1002 | * @since 6.6.0 1003 | */ 1004 | 1005 | /** 1006 | * Resumes firing of the named event(s). 1007 | * @param eventName {...string} multiple event names to resume. 1008 | * @returns {InCache} 1009 | * @since 6.6.0 1010 | */ 1011 | 1012 | /** 1013 | * Suspends all events. 1014 | * @returns {InCache} 1015 | * @since 6.6.0 1016 | */ 1017 | 1018 | /** 1019 | * Resume all events. 1020 | * @returns {InCache} 1021 | * @since 6.6.0 1022 | */ 1023 | 1024 | /** 1025 | * Triggered before get 1026 | * @event InCache#beforeGet 1027 | * @param key {string} key 1028 | * @param record {InCache~record} record object 1029 | * @since 7.2.0 1030 | */ 1031 | 1032 | /** 1033 | * Triggered after get 1034 | * @event InCache#get 1035 | * @param key {string} key 1036 | * @param record {InCache~record} record object 1037 | * @since 7.2.0 1038 | */ 1039 | 1040 | /** 1041 | * Triggered before set 1042 | * @event InCache#beforeSet 1043 | * @param key {string} key 1044 | * @param value {string} value 1045 | * @since 5.0.0 1046 | */ 1047 | 1048 | /** 1049 | * Triggered after set 1050 | * @event InCache#set 1051 | * @param key {string} key 1052 | * @param record {InCache~record} record object 1053 | * @since 5.0.0 1054 | */ 1055 | 1056 | /** 1057 | * Triggered after create the record 1058 | * @event InCache#create 1059 | * @param key {string} key of record 1060 | * @param record {InCache~record} record object 1061 | * @since 5.0.0 1062 | */ 1063 | 1064 | /** 1065 | * Triggered after update the record 1066 | * @event InCache#update 1067 | * @param key {string} key of record 1068 | * @param record {InCache~record} record object 1069 | * @since 5.0.0 1070 | */ 1071 | 1072 | /** 1073 | * Triggered before remove the record 1074 | * @event InCache#beforeRemove 1075 | * @param key {string} key of record to be removed 1076 | * @since 5.0.0 1077 | */ 1078 | 1079 | /** 1080 | * Triggered after record has been removed 1081 | * @event InCache#remove 1082 | * @param key {string} key of record 1083 | * @since 5.0.0 1084 | */ 1085 | 1086 | /** 1087 | * Triggered before bulk set 1088 | * @event InCache#beforeBulkSet 1089 | * @param records {Array} array of objects 1090 | * @since 5.0.0 1091 | */ 1092 | 1093 | /** 1094 | * Triggered after bulk set 1095 | * @event InCache#bulkSet 1096 | * @param records {Array} array of objects 1097 | * @since 5.0.0 1098 | */ 1099 | 1100 | /** 1101 | * Triggered before remove the records 1102 | * @event InCache#beforeBulkRemove 1103 | * @param keys {Array} array of keys to be removed 1104 | * @since 5.0.0 1105 | */ 1106 | 1107 | /** 1108 | * Triggered after records have been removed 1109 | * @event InCache#bulkRemove 1110 | * @param keys {Array} array of keys removed 1111 | * @since 5.0.0 1112 | */ 1113 | 1114 | /** 1115 | * Triggered when records are expired and `opts.autoRemovePeriod` is set 1116 | * @event InCache#expired 1117 | * @param keys {Array} array of keys expired 1118 | * @since 5.0.0 1119 | */ 1120 | 1121 | /** 1122 | * Triggered before load (only if `autoLoad` is false) 1123 | * @event InCache#beforeLoad 1124 | * @param me {InCache} 1125 | * @since 6.4.0 1126 | */ 1127 | 1128 | /** 1129 | * Triggered after load invocation 1130 | * @event InCache#load 1131 | * @param err {null|string} error message, if no errors occurred is null 1132 | * @param me {InCache} 1133 | * @since 6.0.0 1134 | */ 1135 | 1136 | /** 1137 | * Triggered before save 1138 | * @event InCache#beforeSave 1139 | * @param me {InCache} 1140 | * @since 6.4.0 1141 | */ 1142 | 1143 | /** 1144 | * Triggered after save invocation 1145 | * @event InCache#save 1146 | * @param err {null|string} error message, if no errors occurred is null 1147 | * @param me {InCache} 1148 | * @since 6.0.0 1149 | */ 1150 | 1151 | /** 1152 | * Triggered when data is changed 1153 | * @event InCache#change 1154 | * @param by {string} event called by `set`,`remove`,`clear` or `clean` 1155 | * @since 6.1.0 1156 | */ 1157 | 1158 | /** 1159 | * Triggered when data exceed max size 1160 | * @event InCache#exceed 1161 | * @param diff {number} exceeded by record number 1162 | * @since 6.1.0 1163 | */ 1164 | 1165 | /** 1166 | * Check if object is a InCache~record 1167 | * @param obj {InCache~record} InCache record 1168 | * @returns {boolean} 1169 | */ 1170 | static isRecord(obj) { 1171 | return Object.keys(RECORD).every(el => { 1172 | return typeof obj === 'object' && obj.hasOwnProperty(el); 1173 | }); 1174 | } 1175 | 1176 | /***************************** DEPRECATED ********************************/ 1177 | 1178 | /** 1179 | * Triggered when a record has been deleted. **Deprecated since 5.0.0:** use `on('remove', callback)` instead. 1180 | * @param callback {InCache~removedCallback} callback function 1181 | * @deprecated 1182 | * @example 1183 | * inCache.onRemoved((key)=>{ 1184 | * console.log('removed', key); 1185 | * }); 1186 | */ 1187 | onRemoved(callback) { 1188 | this._onRemoved = callback; 1189 | } 1190 | 1191 | /** 1192 | * onRemoved callback 1193 | * @callback InCache~removedCallback 1194 | * @param key {string} key of record removed 1195 | * @deprecated 1196 | */ 1197 | 1198 | /** 1199 | * Triggered when a record has been created. **Deprecated since 5.0.0:** use `on('create', callback)` instead 1200 | * @param callback {InCache~createdCallback} callback function 1201 | * @deprecated 1202 | * @example 1203 | * inCache.onCreated((key, record)=>{ 1204 | * console.log('created', key, record); 1205 | * }); 1206 | */ 1207 | onCreated(callback) { 1208 | this._onCreated = callback; 1209 | } 1210 | 1211 | /** 1212 | * onCreated callback 1213 | * @callback InCache~createdCallback 1214 | * @param key {string} key of record created 1215 | * @param record {InCache~record} record object 1216 | * @deprecated 1217 | */ 1218 | 1219 | /** 1220 | * Triggered when a record has been updated. **Deprecated since 5.0.0:** use `on('update', callback)` instead 1221 | * @param callback {InCache~updatedCallback} callback function 1222 | * @deprecated 1223 | * @example 1224 | * inCache.onUpdated((key, record)=>{ 1225 | * console.log('updated', key, record); 1226 | * }); 1227 | */ 1228 | onUpdated(callback) { 1229 | this._onUpdated = callback; 1230 | } 1231 | 1232 | /** 1233 | * onUpdated callback 1234 | * @callback InCache~updatedCallback 1235 | * @param key {string} key of record updated 1236 | * @param record {InCache~record} record object 1237 | * @deprecated 1238 | */ 1239 | } 1240 | 1241 | /** 1242 | * Expose module 1243 | */ 1244 | module.exports = InCache; 1245 | module.exports.SAVE_MODE = SAVE_MODE; -------------------------------------------------------------------------------- /test/.incache-save: -------------------------------------------------------------------------------- 1 | {"myKey":{"id":"dd85be50-a478-11e7-b194-e52a3ed7ecbb","isNew":false,"isPreserved":false,"toDelete":true,"hits":101,"lastHit":"2018-12-19T15:43:05.561Z","createdOn":"2017-09-28T18:14:27.765Z","updatedOn":"2018-12-19T15:43:05.561Z","expiresOn":null,"value":"myValue"},"myKeyAB":{"id":"c7790db0-03a4-11e9-a290-9f789c110d2e","isNew":false,"isPreserved":false,"toDelete":true,"hits":1,"lastHit":"2018-12-19T15:43:06.763Z","createdOn":"2018-12-19T15:43:06.763Z","updatedOn":"2018-12-19T15:43:06.763Z","expiresOn":null,"value":"myValueUpdate"}} -------------------------------------------------------------------------------- /test/.incache-save2: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /test/.incache-save5: -------------------------------------------------------------------------------- 1 | {"myKey":{"id":"82c34b20-a236-11e7-8a3b-73666a4a72b6","isNew":true,"isPreserved":false,"hits":0,"lastHit":null,"toDelete":true,"createdOn":"2017-09-25T21:14:26.386Z","updatedOn":null,"expiresOn":null,"value":"hello"}} -------------------------------------------------------------------------------- /test/app/fake-content: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce pharetra facilisis massa eget auctor. Suspendisse potenti. Donec non odio massa. In tincidunt dapibus est sed consectetur. Donec a diam id libero maximus facilisis vitae vitae eros. Quisque velit lorem, placerat eu nunc eget, ornare condimentum ipsum. Morbi semper iaculis tincidunt. Curabitur ut metus sit amet justo dapibus vehicula. 2 | 3 | Maecenas sollicitudin vitae ipsum id pellentesque. Vivamus aliquet tellus arcu, nec convallis lacus ultrices suscipit. Donec ultrices gravida dignissim. Nulla facilisi. Aenean sit amet finibus tellus. Vivamus iaculis massa justo, eget dignissim massa ultricies quis. Vivamus eget dui a nunc accumsan dictum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc nec fringilla nisl, quis condimentum enim. Nullam porta erat at libero aliquet lacinia. Quisque posuere leo purus, non hendrerit sem semper non. Donec molestie consequat orci, ut congue turpis rhoncus sed. In eu sapien justo. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras eleifend est sed est sollicitudin feugiat. Aenean non arcu mauris. 4 | 5 | Donec ultrices placerat cursus. Integer et neque tempus, lacinia mauris sit amet, elementum ex. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vestibulum, purus eget posuere tempus, risus ex molestie felis, sit amet venenatis ipsum neque ac neque. Praesent ut nisi eu mi aliquam fringilla. Integer a iaculis eros, eget efficitur lorem. Sed bibendum placerat ex, vel laoreet diam posuere non. 6 | 7 | Fusce semper ex ultrices turpis convallis, sed posuere urna varius. Mauris consequat nulla ante, eu fermentum urna facilisis eu. Duis enim mauris, viverra ut posuere eu, accumsan eget ligula. Vivamus blandit, felis id varius hendrerit, dui enim hendrerit ligula, et luctus ante neque eget odio. Suspendisse porttitor vulputate ex, at condimentum lectus cursus et. Proin sit amet bibendum elit. Aenean luctus ultrices elit. Donec ac interdum eros, eget suscipit lectus. Curabitur interdum facilisis ex in cursus. Sed pretium fringilla erat laoreet laoreet. 8 | 9 | Pellentesque neque orci, consectetur at placerat id, euismod sed velit. Donec venenatis tortor eu turpis consectetur sagittis. Mauris et dapibus felis. Etiam dignissim ultricies sapien sed faucibus. Nullam odio leo, imperdiet sit amet convallis vitae, volutpat a arcu. Curabitur ultrices lectus odio, sed rhoncus lacus vestibulum sit amet. Cras faucibus gravida mollis. 10 | 11 | Vivamus bibendum, turpis id feugiat placerat, sem neque pharetra nibh, efficitur egestas risus lacus sit amet nulla. Duis eget elementum libero. Fusce elit mauris, dapibus nec pharetra ac, porta sit amet augue. Morbi ac felis at nisi eleifend gravida. Praesent non lobortis arcu. Cras iaculis, tellus non sollicitudin mattis, sapien ante pretium mi, lobortis imperdiet lorem ligula vel nibh. Vivamus elit elit, lobortis eu diam eu, posuere elementum magna. Donec quis diam fringilla, venenatis eros quis, iaculis nunc. Phasellus quis ipsum eleifend, lobortis lectus at, faucibus tellus. Aliquam laoreet arcu vel nunc tristique sodales eleifend nec tortor. Quisque maximus iaculis ante, sit amet laoreet erat maximus eget. Nam in dolor lacus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce aliquet tellus vel porta aliquam. Vestibulum pellentesque convallis tincidunt. Maecenas fringilla quis arcu a sodales. 12 | 13 | Duis pulvinar erat eleifend leo maximus, et pretium eros dapibus. Pellentesque tincidunt dui nec turpis commodo, ultricies auctor orci ultricies. Duis in odio ac diam sodales tincidunt sit amet vel dolor. Duis faucibus nibh pharetra nunc finibus venenatis. Mauris convallis, purus vel tincidunt facilisis, lacus eros dictum felis, ac tristique sapien enim at tellus. Aliquam semper elementum augue ut ultrices. Mauris porta eros nec ultricies sollicitudin. Donec faucibus eu justo et tincidunt. Maecenas dui turpis, faucibus vitae mattis tristique, gravida eget augue. Morbi ligula neque, luctus in mollis ut, consequat nec libero. Nulla in est gravida, congue nisi id, feugiat metus. 14 | 15 | Mauris quis vulputate est. Sed fermentum scelerisque quam, vitae eleifend neque. Etiam non vulputate ligula, eget maximus est. Donec condimentum quis nunc id gravida. Fusce ac nibh non leo condimentum auctor a porta nibh. Vivamus commodo, libero sit amet mollis porta, orci ligula feugiat magna, id rutrum massa leo luctus odio. Quisque ac risus a purus tempor scelerisque quis vitae eros. 16 | 17 | Mauris imperdiet, risus in fermentum lacinia, ipsum elit rhoncus orci, nec sollicitudin risus erat eu erat. Fusce ut turpis ligula. Nullam pellentesque fermentum quam vitae suscipit. Cras pretium est non massa rutrum rhoncus. Donec sit amet eros faucibus, tempor sapien et, vehicula dolor. Donec posuere nibh vitae tempus tempus. Curabitur vitae leo vel augue finibus finibus sed at dui. Sed nec eleifend tellus. Proin cursus ipsum at aliquet maximus. Phasellus sed orci venenatis, imperdiet elit tincidunt, ultricies libero. 18 | 19 | Nunc auctor convallis consectetur. Nam mi leo, finibus ut erat vitae, dictum vulputate diam. Duis scelerisque sapien ac hendrerit tempor. Maecenas interdum arcu sit amet magna elementum, sit amet cursus velit efficitur. Suspendisse non magna id nunc malesuada eleifend at eu ligula. Aliquam erat volutpat. Aliquam gravida leo lectus, vel condimentum magna congue eu. Sed vestibulum metus tellus, a feugiat nisi luctus id. Donec blandit posuere viverra. Pellentesque aliquet arcu metus, ac malesuada metus consectetur a. Aliquam erat volutpat. Praesent justo urna, semper et risus eu, laoreet porttitor felis. Aenean volutpat erat sit amet tortor accumsan eleifend. Nam eget molestie magna, ut pellentesque purus. Duis non leo enim. 20 | 21 | -------------------------------------------------------------------------------- /test/app/index.js: -------------------------------------------------------------------------------- 1 | const koa = require('koa'); 2 | const apiRoutes = require('./routes/index'); 3 | const InCache = require('../../src/incache'); 4 | const cache = new InCache({ 5 | filePath: __dirname +'/.incache-koa' 6 | }); 7 | const app = new koa(); 8 | 9 | app.context.cache = cache; 10 | 11 | app.use(apiRoutes.routes()); 12 | 13 | app.listen(3188, '127.0.0.1'); 14 | 15 | function randomData(keyNumber, dataAmount) { 16 | const testArray = []; 17 | 18 | for(let k=0; k { 5 | const result = fs.readFileSync(filePath).toString(); 6 | ctx.cache.set(ctx.path, result); 7 | ctx.body = result; 8 | }; 9 | 10 | exports.world = async (ctx) => { 11 | ctx.body = fs.readFileSync(filePath).toString(); 12 | }; 13 | -------------------------------------------------------------------------------- /test/app/routes/index.js: -------------------------------------------------------------------------------- 1 | const router = require('koa-router')(); 2 | const { hello, world } = require('./hello'); 3 | const cacheMiddleware = require('../middleware'); 4 | 5 | router 6 | .get('/benchmark/cached', cacheMiddleware(), hello) 7 | .get('/benchmark/notCached', world); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /test/helper.js: -------------------------------------------------------------------------------- 1 | const helper = require('../src/helper'); 2 | const be = require('bejs'); 3 | 4 | describe('helper', function () { 5 | 6 | describe('is', function () { 7 | it('should be return true', () => { 8 | let result = helper.is('hello', 'string'); 9 | console.log(result); 10 | be.err.true(result); 11 | }); 12 | it('should be return false', () => { 13 | let result = helper.is([], 'string'); 14 | console.log(result); 15 | be.err.false(result); 16 | }); 17 | }); 18 | 19 | describe('defaults', function () { 20 | it('should be return true', () => { 21 | let result = helper.defaults({a: 4, b: 5}, {a: 1, b: 2, c: 3}); 22 | console.log(result); 23 | be.err.equal(result, {a: 4, b: 5, c: 3}); 24 | }); 25 | it('should be return false', () => { 26 | let result = helper.defaults({a: 4, b: 5}, {a: 1, b: 2, c: 3}); 27 | console.log(result); 28 | be.err.not.equal(result, {a: 4, b: 5}); 29 | }); 30 | }); 31 | 32 | describe('defaults, deep', function () { 33 | it('should be return true', () => { 34 | let result = helper.defaults({a: 4, b: 5, d: {a: 1}}, {a: 1, b: 2, c: 3, d: {a: 5, b: 2}}); 35 | console.log(result); 36 | be.err.equal(result, {a: 4, b: 5, c: 3, d: {a: 1, b: 2}}); 37 | }); 38 | }); 39 | 40 | describe('addSecondsToNow', function () { 41 | it('should be return true', () => { 42 | let result = helper.addSecondsToNow(2); 43 | be.err.true(result > new Date()); 44 | }); 45 | }); 46 | 47 | describe('isServer', function () { 48 | it('should be return true', () => { 49 | be.err.true(helper.isServer()); 50 | }); 51 | }); 52 | 53 | describe('deprecated', function () { 54 | it('should be return true', () => { 55 | const result = helper.deprecated('foo()', 'foo() is deprecated'); 56 | be.err.true(result); 57 | }); 58 | it('only one argument, should be return true', () => { 59 | const result = helper.deprecated('bar() is deprecated'); 60 | be.err.true(result); 61 | }); 62 | it('log type, should be return true', () => { 63 | const result = helper.deprecated(123, 'bar() is deprecated', 'log'); 64 | be.err.true(result); 65 | }); 66 | it('undefined, should be return false', () => { 67 | const result = helper.deprecated(undefined, 'bar() is deprecated'); 68 | be.err.false(result); 69 | }); 70 | }); 71 | }); -------------------------------------------------------------------------------- /test/incache-auto-removed.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const cache = new InCache(); 3 | const be = require('bejs'); 4 | 5 | cache.setConfig({ 6 | storeName: 'auto-remove', 7 | save: false, 8 | share: false, 9 | autoRemovePeriod: 2 10 | }); 11 | 12 | describe('cache-auto-remove', function () { 13 | this.timeout(5000); 14 | 15 | describe('on expired event', function () { 16 | it('with expiry, should be return true', (done)=>{ 17 | cache.on('expired', keys => { 18 | console.log(keys); 19 | be.err.array(keys); 20 | be.err.equal(keys[0], 'myKeyExpiry'); 21 | done(); 22 | }); 23 | 24 | cache.set('myKeyExpiry', 'myValue', { 25 | maxAge: 1000 26 | }); 27 | 28 | cache.set('myKey', 'myValue'); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/incache-auto-save.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const fs = require('fs'); 3 | 4 | const FILE_PATH = './test/.incache-save3'; 5 | 6 | describe('cache-auto-save', function () { 7 | this.timeout(10000); 8 | 9 | before(function () { 10 | if(fs.existsSync(FILE_PATH)) { 11 | fs.unlinkSync(FILE_PATH); 12 | } 13 | }); 14 | 15 | it('should create cache file', (done) => { 16 | 17 | const cache = new InCache({ 18 | autoSave: true, 19 | filePath: FILE_PATH, 20 | autoSaveMode: InCache.SAVE_MODE.TIMER, 21 | autoSavePeriod: 1 22 | }); 23 | 24 | cache.set('myKey', 'hello'); 25 | 26 | setTimeout(function () { 27 | if(fs.existsSync(FILE_PATH)) { 28 | console.log('exists'); 29 | // Add new key 30 | cache.set('myKey2', 'hello2'); 31 | } else 32 | done('file cache not exists'); 33 | }, 1500); 34 | 35 | setTimeout(function () { 36 | const data = JSON.parse(fs.readFileSync(FILE_PATH)); 37 | console.log(data); 38 | if(data.hasOwnProperty('myKey2')) 39 | done(); 40 | else 41 | done('key not exists'); 42 | }, 3000); 43 | 44 | //be.err.object(result); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/incache-bulk.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('cache-bulk', function () { 5 | this.timeout(5000); 6 | 7 | describe('cancel bulkSet by events', function () { 8 | it('should be return true', (done)=>{ 9 | const cache = new InCache(); 10 | cache.on('beforeBulkSet', function () { 11 | return false; 12 | }); 13 | cache.bulkSet([{key: 'hello', value: 'world'}]); 14 | setTimeout(function () { 15 | be.err(done).empty(cache.all()); 16 | }, 200); 17 | }); 18 | }); 19 | 20 | describe('bulkSet', function () { 21 | it('object with key and value should be ok', ()=>{ 22 | const cache = new InCache(); 23 | let result = cache.bulkSet([{key: 'hello', value: 'world'}]); 24 | 25 | console.log(result); 26 | 27 | }); 28 | it('object should be ok', ()=>{ 29 | const cache = new InCache(); 30 | let result = cache.bulkSet([{value: 'world'}]); 31 | 32 | console.log(result); 33 | 34 | }); 35 | it('array should be ok', ()=>{ 36 | const cache = new InCache(); 37 | let result = cache.bulkSet(['world']); 38 | 39 | console.log(result); 40 | 41 | }); 42 | }); 43 | 44 | describe('bulkSet silent true', function () { 45 | it('should be return true', (done)=>{ 46 | const cache = new InCache(); 47 | cache.on('beforeBulkSet', function () { 48 | return false; 49 | }); 50 | cache.bulkSet([{key: 'hello', value: 'world'}], true); 51 | setTimeout(function () { 52 | be.err(done).not.empty(cache.all()); 53 | }, 200); 54 | }); 55 | }); 56 | 57 | describe('cancel bulkRemove by events', function () { 58 | it('should be return true', (done)=>{ 59 | const cache = new InCache(); 60 | cache.on('beforeBulkRemove', function () { 61 | return false; 62 | }); 63 | cache.set('hello', 'world'); 64 | cache.bulkRemove(['hello']); 65 | setTimeout(function () { 66 | be.err(done).not.empty(cache.all()); 67 | }, 200); 68 | }); 69 | }); 70 | 71 | describe('bulkRemove silent true', function () { 72 | it('should be return true', (done)=>{ 73 | const cache = new InCache(); 74 | cache.on('beforeBulkRemove', function () { 75 | return false; 76 | }); 77 | cache.set('hello', 'world'); 78 | cache.bulkRemove(['hello'], true); 79 | setTimeout(function () { 80 | be.err(done).empty(cache.all()); 81 | }, 200); 82 | }); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /test/incache-clone.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('clone', function () { 5 | 6 | this.timeout(5000); 7 | 8 | it('should be return false', () => { 9 | const cache = new InCache({ 10 | autoLoad: false, 11 | clone: true 12 | }); 13 | 14 | const o = {a: 1, b: 2}; 15 | 16 | cache.set('k', o); 17 | 18 | let result = cache.get('k'); 19 | 20 | be.err.false(result === o); 21 | }); 22 | 23 | it('should be return true', () => { 24 | const cache = new InCache({ 25 | autoLoad: false, 26 | clone: false 27 | }); 28 | 29 | const o = {a: 1, b: 2}; 30 | 31 | cache.set('k', o); 32 | 33 | let result = cache.get('k'); 34 | 35 | be.err.true(result === o); 36 | }); 37 | 38 | }); -------------------------------------------------------------------------------- /test/incache-delete-on-expires.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('delete on expires', function () { 5 | 6 | this.timeout(5000); 7 | 8 | it('deleteOnExpires false', (done) => { 9 | const cache = new InCache({ 10 | deleteOnExpires: false, 11 | maxAge: 1000 12 | }); 13 | 14 | cache.set('k0', 'v0'); 15 | 16 | setTimeout(function () { 17 | be.err(done).equal(cache.count(), 1); 18 | }, 1500); 19 | }); 20 | 21 | it('deleteOnExpires true, autoRemove', (done) => { 22 | const cache = new InCache({ 23 | deleteOnExpires: true, 24 | maxAge: 500, 25 | autoRemovePeriod: 1 26 | }); 27 | 28 | cache.set('k0', 'v0'); 29 | 30 | setTimeout(function () { 31 | be.err(done).equal(cache.count(), 0); 32 | }, 1500); 33 | }); 34 | 35 | it('deleteOnExpires true, on get', (done) => { 36 | const cache = new InCache({ 37 | deleteOnExpires: true, 38 | maxAge: 1000 39 | }); 40 | 41 | cache.set('k0', 'v0'); 42 | 43 | console.log(cache); 44 | 45 | setTimeout(function () { 46 | cache.get('k0'); 47 | be.err(done).equal(cache.count(), 0); 48 | }, 1500); 49 | }); 50 | 51 | }); -------------------------------------------------------------------------------- /test/incache-events.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const InCache = require('../src/incache'); 3 | const be = require('bejs'); 4 | const typis = require('typis'); 5 | 6 | describe('cache-events', function () { 7 | 8 | this.timeout(5000); 9 | 10 | describe('onRemoved', function () { 11 | it('should be return done', (done)=>{ 12 | const cache = new InCache({ 13 | save: false, 14 | share: false 15 | }); 16 | 17 | cache.onRemoved((key)=>{ 18 | console.log('deleted', key); 19 | if(key === 'myKeyBI') 20 | done(); 21 | }); 22 | cache.set('myKeyBI', 'myValue'); 23 | cache.remove('myKeyBI'); 24 | }); 25 | }); 26 | 27 | describe('onCreated', function () { 28 | it('should be return done', (done)=>{ 29 | const cache = new InCache({ 30 | save: false, 31 | share: false 32 | }); 33 | 34 | cache.onCreated((key, record)=>{ 35 | console.log('created', key, record); 36 | if(key === 'myKeyBB') 37 | done(); 38 | }); 39 | cache.set('myKeyBB', 'myValue'); 40 | }); 41 | }); 42 | 43 | describe('onUpdated', function () { 44 | it('should be return done', (done)=>{ 45 | const cache = new InCache({ 46 | save: false, 47 | share: false 48 | }); 49 | 50 | cache.onUpdated((key, record)=>{ 51 | console.log('updated', record); 52 | if(record.createdOn && key === 'myKeyBBB') done(); 53 | }); 54 | cache.destroy('myKeyBBB'); 55 | cache.set('myKeyBBB', 'myValue'); 56 | cache.set('myKeyBBB', 'myValue 2'); 57 | }); 58 | }); 59 | 60 | describe('on', function () { 61 | describe('create', function () { 62 | it('should be return done', (done)=>{ 63 | const cache = new InCache({ 64 | save: false, 65 | share: false 66 | }); 67 | 68 | cache.on('create', (key, record)=>{ 69 | console.log('create', key, record); 70 | done(); 71 | }); 72 | 73 | cache.set('myKeyBBB', 'myValue'); 74 | }); 75 | }); 76 | describe('load', function () { 77 | it('should be return done, file not found', (done)=>{ 78 | const cache = new InCache({ 79 | filePath: 'no-found' 80 | }); 81 | 82 | cache.on('load', (err)=>{ 83 | console.log('load with', 'error', err); 84 | if(err) 85 | done(); 86 | }); 87 | }); 88 | it('should be return done', (done)=>{ 89 | const cache = new InCache({ 90 | filePath: './test/.incache-save2' 91 | }); 92 | 93 | cache.on('load', (err)=>{ 94 | console.log('load with', 'error', err); 95 | if(err === null) 96 | done(); 97 | }); 98 | }); 99 | it('should be return done, autoLoad false', (done)=>{ 100 | const cache = new InCache({ 101 | autoLoad: false, 102 | filePath: './test/.incache-save2' 103 | }); 104 | 105 | cache.load().then(()=>{ 106 | console.log('loaded'); 107 | }).catch(e => { 108 | console.log(e); 109 | }); 110 | 111 | cache.on('load', (err)=>{ 112 | console.log('load with', 'error', err); 113 | if(err === null) 114 | done(); 115 | }); 116 | }); 117 | }); 118 | describe('beforeLoad', function () { 119 | it('should be reject', (done)=>{ 120 | const cache = new InCache({ 121 | autoLoad: false, 122 | filePath: './test/.incache-save2' 123 | }); 124 | 125 | cache.on('beforeLoad', ()=>{ 126 | console.log('beforeLoad'); 127 | return false; 128 | }); 129 | 130 | cache.load().then(()=>{ 131 | done('loaded'); 132 | }).catch(e => { 133 | done(); 134 | }); 135 | 136 | }); 137 | it('should be not reject, autoLoad true', (done)=>{ 138 | new InCache({ 139 | autoLoad: true, 140 | filePath: './test/.incache-save2' 141 | }).on('beforeLoad', ()=>{ 142 | console.log('beforeLoad'); 143 | return false; 144 | }).on('load', (err)=>{ 145 | console.log(err, 'load'); 146 | done(); 147 | }); 148 | 149 | }); 150 | }); 151 | describe('beforeSave', function () { 152 | it('should be reject', (done)=>{ 153 | const cache = new InCache({ 154 | autoSave: false, 155 | filePath: './test/.incache-save6' 156 | }); 157 | 158 | cache.on('beforeSave', ()=>{ 159 | return false; 160 | }); 161 | 162 | cache.save().then(()=>{ 163 | done('saved'); 164 | }).catch(e => { 165 | done(); 166 | }); 167 | 168 | }); 169 | }); 170 | describe('save', function () { 171 | it('should be return done', (done)=>{ 172 | const cache = new InCache({ 173 | autoSave: false, 174 | filePath: './test/.incache-save2' 175 | }); 176 | 177 | cache.save().then(()=>{ 178 | console.log('saved'); 179 | }).catch(e => { 180 | console.log(e); 181 | }); 182 | 183 | cache.on('save', (err)=>{ 184 | console.log('save with', 'error', err); 185 | if(err === null) 186 | done(); 187 | }); 188 | }); 189 | }); 190 | describe('remove', function () { 191 | it('should be return done', (done)=>{ 192 | const cache = new InCache({ 193 | save: false, 194 | share: false 195 | }); 196 | 197 | cache.on('remove', (key)=>{ 198 | console.log('remove', key); 199 | done(); 200 | }); 201 | 202 | cache.set('myKeyBBB', 'myValue'); 203 | cache.remove('myKeyBBB'); 204 | }); 205 | }); 206 | describe('beforeGet', function () { 207 | it('should be return done', (done)=>{ 208 | const cache = new InCache({ 209 | save: false, 210 | share: false 211 | }); 212 | 213 | cache.on('beforeGet', (key, record)=>{ 214 | console.log('beforeGet', key, record); 215 | return false; 216 | }); 217 | 218 | cache.set('myKeyBBB', 'myValue'); 219 | if (cache.get('myKeyBBB') === undefined) 220 | done(); 221 | ì }); 222 | }); 223 | describe('get', function () { 224 | it('should be return done', (done)=>{ 225 | const cache = new InCache({ 226 | save: false, 227 | share: false 228 | }); 229 | 230 | cache.on('get', (key, record)=>{ 231 | console.log('get', key, record); 232 | done(); 233 | }); 234 | 235 | cache.set('myKeyBBB', 'myValue'); 236 | cache.get('myKeyBBB'); 237 | ì }); 238 | }); 239 | describe('set', function () { 240 | it('should be return done', (done)=>{ 241 | const cache = new InCache({ 242 | save: false, 243 | share: false 244 | }); 245 | 246 | cache.on('set', (key, record)=>{ 247 | console.log('set', key, record); 248 | done(); 249 | }); 250 | 251 | cache.set('myKeyBBB', 'myValue'); 252 | ì }); 253 | }); 254 | describe('beforeSet', function () { 255 | it('should be return done', (done)=>{ 256 | const cache = new InCache({ 257 | save: false, 258 | share: false 259 | }); 260 | 261 | cache.on('beforeSet', (key, value)=>{ 262 | console.log('beforeSet', key, value); 263 | done(); 264 | }); 265 | 266 | cache.set('myKeyBBB', 'myValue'); 267 | }); 268 | it('returning false, should be return done', (done)=>{ 269 | const cache = new InCache({ 270 | save: false, 271 | share: false 272 | }); 273 | 274 | cache.on('beforeSet', (key, value)=>{ 275 | console.log('beforeSet', key, value); 276 | return false; 277 | }); 278 | 279 | cache.set('myKeyBBB', 'myValue'); 280 | setTimeout(function () { 281 | be.err(done).undefined(cache.get('myKeyBBB')); 282 | },100); 283 | }); 284 | }); 285 | describe('update', function () { 286 | it('should be return done', (done)=>{ 287 | const cache = new InCache({ 288 | save: false, 289 | share: false 290 | }); 291 | 292 | cache.on('update', (key, record)=>{ 293 | console.log('update', record); 294 | if(record.createdOn && key === 'myKeyBBB') done(); 295 | }); 296 | 297 | cache.destroy('myKeyBBB'); 298 | cache.set('myKeyBBB', 'myValue'); 299 | cache.set('myKeyBBB', 'myValue 2'); 300 | }); 301 | }); 302 | describe('change', function () { 303 | it('should be return done', (done)=>{ 304 | const cache = new InCache({ 305 | save: false 306 | }); 307 | 308 | cache.on('change', by => { 309 | console.log('change', by); 310 | done(); 311 | }); 312 | 313 | cache.set('myKeyBBB', 'myValue'); 314 | }); 315 | }); 316 | describe('exceed', function () { 317 | it('should be return done', (done)=>{ 318 | const cache = new InCache({ 319 | save: false, 320 | maxRecordNumber: 2 321 | }); 322 | 323 | cache.on('exceed', diff => { 324 | console.log('exceed', diff); 325 | if(diff === 1) 326 | done(); 327 | }); 328 | 329 | cache.set('myKeyBBB1', 'myValue'); 330 | cache.set('myKeyBBB2', 'myValue'); 331 | cache.set('myKeyBBB3', 'myValue'); 332 | }); 333 | }); 334 | 335 | describe('suspendEvent change', function () { 336 | it('should be return done', (done)=>{ 337 | const cache = new InCache({ 338 | save: false 339 | }); 340 | 341 | cache.on('change', by => { 342 | throw new Error('suspendEvent error'); 343 | }); 344 | 345 | cache.suspendEvent('change'); 346 | 347 | cache.set('myKeyBBB', 'myValue'); 348 | done(); 349 | }); 350 | }); 351 | 352 | describe('resumeEvent change', function () { 353 | it('should be return done', (done)=>{ 354 | const cache = new InCache({ 355 | save: false 356 | }); 357 | 358 | cache.on('change', by => { 359 | done(); 360 | }); 361 | 362 | cache.suspendEvent('change'); 363 | 364 | cache.set('myKeyBBB', 'myValue'); 365 | 366 | cache.resumeEvent('change'); 367 | 368 | cache.set('myKeyBBB', 'myValue2'); 369 | 370 | }); 371 | }); 372 | 373 | describe('suspendEvents', function () { 374 | it('should be return done', (done)=>{ 375 | const cache = new InCache({ 376 | save: false 377 | }); 378 | 379 | cache.on('change', by => { 380 | throw new Error('suspendEvent error'); 381 | }); 382 | 383 | cache.suspendEvents(); 384 | 385 | cache.set('myKeyBBB', 'myValue'); 386 | done(); 387 | }); 388 | }); 389 | 390 | describe('resumeEvents', function () { 391 | it('should be return done', (done)=>{ 392 | const cache = new InCache({ 393 | save: false 394 | }); 395 | 396 | cache.on('change', by => { 397 | done(); 398 | }); 399 | 400 | cache.suspendEvents(); 401 | 402 | cache.set('myKeyBBB', 'myValue'); 403 | 404 | cache.resumeEvents(); 405 | 406 | cache.set('myKeyBBB', 'myValue2'); 407 | 408 | }); 409 | }); 410 | }); 411 | }); 412 | -------------------------------------------------------------------------------- /test/incache-exceeded.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('exceeded', function () { 5 | 6 | it('enable maxRecordNumber', () => { 7 | const cache = new InCache({ 8 | maxRecordNumber: 2 9 | }); 10 | 11 | cache.set('k0', 'v0'); 12 | cache.set('k1', 'v1'); 13 | cache.set('k2', 'v2'); 14 | cache.set('k3', 'v3'); 15 | cache.set('k4', 'v4'); 16 | cache.set('k5', 'v5'); 17 | cache.set('k6', 'v6'); 18 | cache.set('k7', 'v7'); 19 | 20 | console.log(cache.all()); 21 | 22 | be.err.equal(cache.count(), 2); 23 | be.err.true(cache.has('k6')); 24 | be.err.true(cache.has('k7')); 25 | }); 26 | 27 | it('disable maxRecordNumber', () => { 28 | const cache = new InCache({ 29 | maxRecordNumber: 0 30 | }); 31 | 32 | cache.set('k0', 'v0'); 33 | cache.set('k1', 'v1'); 34 | cache.set('k2', 'v2'); 35 | cache.set('k3', 'v3'); 36 | cache.set('k4', 'v4'); 37 | cache.set('k5', 'v5'); 38 | cache.set('k6', 'v6'); 39 | cache.set('k7', 'v7'); 40 | 41 | console.log(cache.all()); 42 | 43 | be.err.equal(cache.count(), 8); 44 | }); 45 | 46 | it('_checkExceeded', () => { 47 | const cache = new InCache({ 48 | maxRecordNumber: 0 49 | }); 50 | 51 | cache.set('k0', 'v0'); 52 | cache.set('k1', 'v1'); 53 | cache.set('k2', 'v2'); 54 | cache.set('k3', 'v3'); 55 | cache.set('k4', 'v4'); 56 | cache.set('k5', 'v5'); 57 | cache.set('k6', 'v6'); 58 | cache.set('k7', 'v7'); 59 | cache._opts.maxRecordNumber = 2; 60 | cache._checkExceeded(); 61 | 62 | console.log(cache.all()); 63 | 64 | be.err.equal(cache.count(), 2); 65 | }); 66 | }); -------------------------------------------------------------------------------- /test/incache-hits.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('cache-hits', function () { 5 | this.timeout(10000); 6 | 7 | it('should be return true', () => { 8 | 9 | const cache = new InCache({ 10 | autoSave: false 11 | }); 12 | 13 | 14 | let record = cache.set(`myKey`, `hello`); 15 | 16 | console.log(record); 17 | be.err.equal(record.hits, 0); 18 | be.err.null(record.lastHit); 19 | 20 | 21 | record = cache.get(`myKey`, false); 22 | 23 | console.log(record); 24 | be.err.equal(record.hits, 1); 25 | be.err.date(record.lastHit); 26 | 27 | 28 | record = cache.get(`myKey`, false); 29 | 30 | console.log(record); 31 | be.err.equal(record.hits, 2); 32 | }); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /test/incache-info.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('cache-info', function () { 5 | this.timeout(10000); 6 | 7 | it('should be return true', () => { 8 | 9 | const cache = new InCache({ 10 | autoSave: false 11 | }); 12 | 13 | 14 | let record = cache.set(`myKey`, `hello`); 15 | 16 | console.log(record); 17 | be.err.equal(record.hits, 0); 18 | be.err.null(record.lastHit); 19 | 20 | 21 | record = cache.get(`myKey`, false); 22 | 23 | console.log(record); 24 | be.err.equal(record.hits, 1); 25 | be.err.date(record.lastHit); 26 | 27 | 28 | record = cache.info(`myKey`); 29 | 30 | console.log(record); 31 | be.err.equal(record.hits, 1); 32 | be.err.undefined(record.value); 33 | }); 34 | 35 | }); 36 | -------------------------------------------------------------------------------- /test/incache-load-param.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const fs = require('fs'); 3 | 4 | const FILE_PATH = './test/.incache-save5'; 5 | 6 | describe('cache-load-param', function () { 7 | this.timeout(10000); 8 | 9 | it('should read cache file', (done) => { 10 | 11 | const cache = new InCache({ 12 | autoLoad: false 13 | }); 14 | 15 | cache.load(FILE_PATH).then(()=>{ 16 | const data = JSON.parse(fs.readFileSync(FILE_PATH)); 17 | console.log(data); 18 | if(data.hasOwnProperty('myKey')) 19 | done(); 20 | else 21 | done('key not exists'); 22 | }).catch(e=>{ 23 | done(e); 24 | }); 25 | 26 | }); 27 | 28 | it('should return error', (done) => { 29 | 30 | const cache = new InCache({ 31 | autoLoad: false 32 | }); 33 | 34 | cache.load('-wrong-path').then(()=>{ 35 | done('error'); 36 | }).catch(e=>{ 37 | done(); 38 | }); 39 | 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/incache-manually.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | require('mock-local-storage'); 3 | 4 | describe('manually', function () { 5 | 6 | this.timeout(5000); 7 | 8 | describe('load', function () { 9 | it('should be return done, autoLoad false', (done)=>{ 10 | const cache = new InCache({ 11 | autoLoad: false, 12 | filePath: './test/.incache-save2' 13 | }); 14 | 15 | cache.load().then(()=>{ 16 | console.log('loaded'); 17 | done(); 18 | }).catch(e => { 19 | console.log(e); 20 | }); 21 | 22 | }); 23 | it('more call to load, fails', (done)=>{ 24 | const cache = new InCache({ 25 | autoLoad: false, 26 | filePath: './test/.incache-save2' 27 | }); 28 | 29 | cache._loading = true; 30 | 31 | cache.load().then(()=>{ 32 | done('fail'); 33 | }).catch(e => { 34 | done(); 35 | }); 36 | 37 | }); 38 | it('in browser returns empty object if key not found', (done)=>{ 39 | //require('browser-env')(); 40 | //require('mock-local-storage'); 41 | //delete process.pid; 42 | global.window = {localStorage}; 43 | 44 | const cache = new InCache({ 45 | autoLoad: false, 46 | filePath: 'mKey' 47 | }); 48 | 49 | cache.load().then((data)=>{ 50 | //if(data.count() === 0) 51 | done('fail'); 52 | }).catch(e => { 53 | console.log(e); 54 | if(e === 'content cannot is null') 55 | done(); 56 | }); 57 | 58 | }); 59 | }); 60 | 61 | describe('save', function () { 62 | it('should be return done', (done)=>{ 63 | const cache = new InCache({ 64 | autoSave: false, 65 | filePath: './test/.incache-save2' 66 | }); 67 | 68 | if(typeof window !== 'undefined') 69 | delete window; 70 | 71 | cache.save().then(()=>{ 72 | console.log('saved'); 73 | done(); 74 | }).catch(e => { 75 | console.log(e); 76 | }); 77 | 78 | }); 79 | it('more call to save, fails', (done)=>{ 80 | const cache = new InCache({ 81 | autoSave: false, 82 | filePath: './test/.incache-save2' 83 | }); 84 | 85 | cache._saving = true; 86 | 87 | cache.save().then(()=>{ 88 | done('fail'); 89 | }).catch(e => { 90 | done(); 91 | }); 92 | 93 | }); 94 | 95 | it('in browser it\'s ok', (done)=>{ 96 | global.window = {localStorage}; 97 | 98 | const cache = new InCache({ 99 | autoSave: false, 100 | filePath: './test/.incache-save2' 101 | }); 102 | 103 | cache.save().then(()=>{ 104 | done(); 105 | }).catch(e => { 106 | done(e); 107 | }); 108 | 109 | }); 110 | }); 111 | }); -------------------------------------------------------------------------------- /test/incache-more-instance.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | const fs = require('fs'); 4 | 5 | describe('cache-save-more-instance', function () { 6 | this.timeout(5000); 7 | 8 | before(function () { 9 | if(fs.existsSync('./test/.incache-save-more-instance')) 10 | fs.unlinkSync('./test/.incache-save-more-instance'); 11 | if(fs.existsSync('./test/.incache-save-more-instance-1')) 12 | fs.unlinkSync('./test/.incache-save-more-instance-1'); 13 | }); 14 | 15 | describe('set', function () { 16 | it('should be return true', ()=>{ 17 | 18 | const cache = new InCache({ 19 | filePath: './test/.incache-save-more-instance', 20 | save: true 21 | }); 22 | 23 | cache.set('myKeyXCV', 'myValue'); 24 | let result = cache.get('myKeyXCV'); 25 | console.log(result); 26 | be.err.equal(result, 'myValue'); 27 | }); 28 | it('with expiry, should be return true', (done)=>{ 29 | 30 | const cache = new InCache({ 31 | filePath: './test/.incache-save-more-instance', 32 | save: true 33 | }); 34 | 35 | cache.set('myKeyXCVExpiry', 'myValue', { 36 | maxAge: 1000 37 | }); 38 | setTimeout(()=>{ 39 | let result = cache.get('myKeyXCVExpiry', false); 40 | console.log(result); 41 | be.err(done).undefined(result); 42 | }, 1200); 43 | }); 44 | it('should be equal', ()=>{ 45 | 46 | if(typeof window !== 'undefined') 47 | delete window; 48 | 49 | const cache = new InCache({ 50 | storeName: 'new', 51 | filePath: './test/.incache-save-more-instance-1', 52 | save: true, 53 | share: true 54 | }); 55 | 56 | let result; 57 | cache.remove('myKeyABVB'); 58 | result = cache.set('myKeyABVB', 'myValue'); 59 | be.err.true(result.isNew); 60 | result = cache.set('myKeyABVB', 'myValueUpdate'); 61 | be.err.false(result.isNew); 62 | result = cache.get('myKeyABVB'); 63 | console.log(result); 64 | be.err.equal(global[cache.GLOBAL_KEY].data['myKeyABVB'].value, result); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /test/incache-no-share.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const cache = new InCache(); 3 | const be = require('bejs'); 4 | 5 | cache.setConfig({ 6 | storeName: 'no-share', 7 | save: false, 8 | share: false 9 | }); 10 | 11 | describe('cache-no-share', function () { 12 | this.timeout(5000); 13 | 14 | describe('set', function () { 15 | it('should be return true', ()=>{ 16 | cache.set('myKey', 'myValue'); 17 | let result = cache.get('myKey'); 18 | console.log(result); 19 | be.err.equal(result, 'myValue'); 20 | }); 21 | it('with expiry, should be return true', (done)=>{ 22 | cache.set('myKeyExpiry', 'myValue', { 23 | maxAge: 1000 24 | }); 25 | setTimeout(()=>{ 26 | let result = cache.get('myKeyExpiry', false); 27 | console.log(result); 28 | be.err(done).undefined(result); 29 | }, 1200); 30 | }); 31 | it('should be equal', ()=>{ 32 | let result; 33 | cache.remove('myKeyAB--noshare'); 34 | result = cache.set('myKeyAB--noshare', 'myValue'); 35 | be.err.true(result.isNew); 36 | result = cache.set('myKeyAB--noshare', 'myValueUpdate'); 37 | be.err.false(result.isNew); 38 | result = cache.get('myKeyAB--noshare'); 39 | console.log(result); 40 | be.err.undefined(global[cache.GLOBAL_KEY]); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/incache-preserve.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('preserve', function () { 5 | 6 | this.timeout(5000); 7 | 8 | it('should be return true', () => { 9 | const cache = new InCache({ 10 | autoLoad: false, 11 | preserve: true 12 | }); 13 | 14 | cache.set('k', 'v'); 15 | cache.set('k', 'v2'); 16 | let result = cache.get('k'); 17 | 18 | be.err.equal(result, 'v'); 19 | }); 20 | 21 | it('should be return true, overwrite option', () => { 22 | const cache = new InCache({ 23 | autoLoad: false, 24 | preserve: true 25 | }); 26 | 27 | cache.set('k', 'v', {preserve: false}); 28 | cache.set('k', 'v2'); 29 | let result = cache.get('k'); 30 | 31 | be.err.equal(result, 'v2'); 32 | }); 33 | 34 | it('should be return true, isPreserved', () => { 35 | const cache = new InCache({ 36 | autoLoad: false, 37 | preserve: true 38 | }); 39 | 40 | cache.set('k', 'v'); 41 | 42 | let result = cache.get('k', false).isPreserved; 43 | 44 | be.err.true(result); 45 | }); 46 | 47 | it('should be return true, isPreserved false', () => { 48 | const cache = new InCache({ 49 | autoLoad: false 50 | }); 51 | 52 | cache.set('k', 'v'); 53 | 54 | let result = cache.get('k', false).isPreserved; 55 | 56 | be.err.false(result); 57 | }); 58 | }); -------------------------------------------------------------------------------- /test/incache-record.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | const RECORD = {"id":"7ccb17d0-b35b-11e7-82fa-519b6a24f113","isNew":true,"isPreserved":false,"toDelete":true,"hits":0,"lastHit":null,"createdOn":"2017-10-17T16:51:57.517Z","updatedOn":null,"expiresOn":null,"value":"hello"}; 4 | const NO_RECORD = {"id":"82c34b20-a236-11e7-8a3b-73666a4a72b6","isNew":true,"isPreserved":false,"toDelete":true,"createdOn":"2017-09-25T21:14:26.386Z","updatedOn":null,"expiresOn":null}; 5 | 6 | describe('cache-record', function () { 7 | it('should be return true', () => { 8 | be.err.true(InCache.isRecord(RECORD)); 9 | }); 10 | 11 | it('should be return false', () => { 12 | be.err.false(InCache.isRecord(NO_RECORD)); 13 | }); 14 | 15 | it('should be return false if passing a no object', () => { 16 | be.err.false(InCache.isRecord(1)); 17 | }); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /test/incache-save-param.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const fs = require('fs'); 3 | 4 | const FILE_PATH = './test/.incache-save4'; 5 | 6 | describe('cache-save-param', function () { 7 | this.timeout(10000); 8 | 9 | before(function () { 10 | if(fs.existsSync(FILE_PATH)) { 11 | fs.unlinkSync(FILE_PATH); 12 | } 13 | }); 14 | 15 | it('should create cache file', (done) => { 16 | 17 | const cache = new InCache({ 18 | autoSave: false 19 | }); 20 | 21 | cache.set('myKey', 'hello'); 22 | 23 | cache.save(FILE_PATH).then(()=>{ 24 | const data = JSON.parse(fs.readFileSync(FILE_PATH)); 25 | console.log(data); 26 | if(data.hasOwnProperty('myKey')) 27 | done(); 28 | else 29 | done('key not exists'); 30 | }).catch(e=>{ 31 | done(e); 32 | }); 33 | 34 | }); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/incache-save.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const cache = new InCache(); 3 | const be = require('bejs'); 4 | 5 | cache.setConfig({ 6 | storeName: 'incache-save', 7 | save: true, 8 | filePath: './test/.incache-save', 9 | share: true 10 | }); 11 | 12 | describe('cache-save', function () { 13 | this.timeout(5000); 14 | 15 | describe('get, onlyValue false', function () { 16 | it('should be return object', () => { 17 | console.log(cache.all()); 18 | let result = cache.get('myKey', false); 19 | console.log(result); 20 | be.err.object(result); 21 | }); 22 | }); 23 | 24 | describe('set', function () { 25 | it('should be return true', () => { 26 | cache.set('myKey', 'myValue'); 27 | let result = cache.get('myKey'); 28 | console.log(result); 29 | be.err.equal(result, 'myValue'); 30 | }); 31 | it('with expiry, should be return true', (done) => { 32 | cache.set('myKeyExpiry', 'myValue', { 33 | maxAge: 1000 34 | }); 35 | setTimeout(() => { 36 | let result = cache.get('myKeyExpiry', false); 37 | console.log(result); 38 | be.err(done).undefined(result); 39 | }, 1200); 40 | }); 41 | it('should be equal', () => { 42 | let result; 43 | cache.remove('myKeyAB'); 44 | result = cache.set('myKeyAB', 'myValue'); 45 | be.err.true(result.isNew); 46 | result = cache.set('myKeyAB', 'myValueUpdate'); 47 | be.err.false(result.isNew); 48 | result = cache.get('myKeyAB'); 49 | console.log(result); 50 | be.err.equal(global[cache.GLOBAL_KEY].data['myKeyAB'].value, result); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /test/incache-stats.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../src/incache'); 2 | const be = require('bejs'); 3 | 4 | describe('cache-stats', function () { 5 | this.timeout(10000); 6 | 7 | it('should be return an object', () => { 8 | 9 | const cache = new InCache({ 10 | autoSave: false 11 | }); 12 | 13 | for(let i = 0; i < 2000; i++) 14 | cache.set(`myKey${i}`, `hello${i}`); 15 | 16 | let result = cache.stats(); 17 | console.log(result); 18 | be.err.equal(result.count, 2000); 19 | be.err.equal(result.size, 527560); 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /test/incache.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const InCache = require('../src/incache'); 3 | const cache = new InCache({ 4 | save: true, 5 | filePath: './test/.incache', 6 | share: true 7 | }); 8 | const be = require('bejs'); 9 | const typis = require('typis'); 10 | 11 | describe('cache', function () { 12 | 13 | this.timeout(5000); 14 | 15 | before(function () { 16 | if(fs.existsSync('./test/.incache')) 17 | fs.unlinkSync('./test/.incache'); 18 | }); 19 | 20 | describe('set', function () { 21 | it('should be return true', ()=>{ 22 | let record = cache.set('myKey', 'myValue'); 23 | console.log(record); 24 | let result = cache.get('myKey'); 25 | console.log(result); 26 | be.err.equal(result, 'myValue'); 27 | }); 28 | it('with expiry, should be return true', (done)=>{ 29 | cache.set('myKeyExpiry', 'myValue', { 30 | maxAge: 1000 31 | }); 32 | setTimeout(()=>{ 33 | let result = cache.get('myKeyExpiry', false); 34 | console.log(result); 35 | be.err(done).undefined(result); 36 | }, 1200); 37 | }); 38 | it('should be equal', ()=>{ 39 | let result; 40 | result = cache.set('myKeyAX', 'myValue'); 41 | console.log('=================================>',cache.getConfig()); 42 | console.log('=================================>',result); 43 | be.err.true(result.isNew); 44 | result = cache.set('myKeyAX', 'myValueUpdate'); 45 | be.err.false(result.isNew); 46 | result = cache.get('myKeyAX'); 47 | //console.log(result); 48 | be.err.equal(global[cache.GLOBAL_KEY].data['myKeyAX'].value, result); 49 | }); 50 | it('with slash, should be equal', ()=>{ 51 | let result; 52 | let route = '/benchmark/cached'; 53 | cache.set(route, 'myValue'); 54 | result = cache.get(route); 55 | //console.log(result); 56 | be.err.equal(global[cache.GLOBAL_KEY].data[route].value, result); 57 | }); 58 | }); 59 | 60 | describe('get, not found', function () { 61 | it('should be return undefined', ()=>{ 62 | let result = cache.get('myKey_not_found'); 63 | console.log(result); 64 | be.err.undefined(result); 65 | }); 66 | }); 67 | 68 | describe('get, onlyValue false', function () { 69 | it('should be return null', ()=>{ 70 | cache.set('myKeyWow', 'myValue'); 71 | let result = cache.get('myKeyWow', false); 72 | console.log(result); 73 | be.err.object(result); 74 | }); 75 | }); 76 | 77 | describe('has', function () { 78 | it('should be return true', ()=>{ 79 | cache.set('myKey', 'myValue'); 80 | let result = cache.has('myKey'); 81 | console.log(result); 82 | be.err.true(result); 83 | }); 84 | it('should be return false', ()=>{ 85 | let result = cache.has('myKey2'); 86 | console.log(result); 87 | be.err.false(result); 88 | }); 89 | }); 90 | 91 | describe('remove', function () { 92 | it('should be return false', ()=>{ 93 | cache.set('myKeyB', 'myValue'); 94 | let result = cache.has('myKeyB'); 95 | be.err.true(result); 96 | console.log(result); 97 | cache.remove('myKeyB'); 98 | result = cache.has('myKeyB'); 99 | console.log(result); 100 | be.err.falsy(global[cache.GLOBAL_KEY]['myKeyB']); 101 | be.err.false(result); 102 | }); 103 | it('using alias destroy, should be return false', ()=>{ 104 | cache.set('myKeyBD', 'myValue'); 105 | let result = cache.has('myKeyBD'); 106 | be.err.true(result); 107 | console.log(result); 108 | cache.destroy('myKeyBD'); 109 | result = cache.has('myKeyBD'); 110 | console.log(result); 111 | be.err.falsy(global[cache.GLOBAL_KEY]['myKeyBD']); 112 | be.err.false(result); 113 | }); 114 | }); 115 | 116 | describe('removeExpired', function () { 117 | it('should be return false', (done)=>{ 118 | cache.set('_myKeyBExp', 'myValue', {maxAge: 500}); 119 | cache.set('_myKeyBExp2', 'myValue'); 120 | cache.set('_myKeyBExp3', 'myValue', {maxAge: 500}); 121 | setTimeout(function () { 122 | cache.removeExpired(); 123 | console.log(cache.has('_myKeyBExp2')); 124 | be.err.false(cache.has('_myKeyBExp')); 125 | be.err.true(cache.has('_myKeyBExp2')); 126 | be.err.false(cache.has('_myKeyBExp3')); 127 | done(); 128 | }, 1000); 129 | }); 130 | }); 131 | 132 | describe('all', function () { 133 | it('should be return an array of 5 items', ()=>{ 134 | cache.clear(); 135 | cache.set('myKey1', 'myValue1'); 136 | cache.set('myKey2', 'myValue2'); 137 | cache.set('myKey3', 'myValue3'); 138 | cache.set('myKey4', 'myValue4'); 139 | cache.set('myKey5', 'myValue5'); 140 | let result = cache.all(); 141 | console.log(result); 142 | be.err.array(result); 143 | be.err.equal(result.length, 5); 144 | }); 145 | it('should be return an object of 5 items', ()=>{ 146 | cache.clear(); 147 | cache.set('myKey1', 'myValue1'); 148 | cache.set('myKey2', 'myValue2'); 149 | cache.set('myKey3', 'myValue3'); 150 | cache.set('myKey4', 'myValue4'); 151 | cache.set('myKey5', 'myValue5'); 152 | let result = cache.all(true); 153 | console.log(result); 154 | be.err.object(result); 155 | be.err.equal(Object.keys(result).length, 5); 156 | }); 157 | it('with expired, should be return an array of 4 items', (done)=>{ 158 | cache.clear(); 159 | cache.set('myKey1', 'myValue1'); 160 | cache.set('myKey2', 'myValue2'); 161 | cache.set('myKey3', 'myValue3'); 162 | cache.set('myKey4', 'myValue4', {maxAge: 1000}); 163 | cache.set('myKey5', 'myValue5'); 164 | setTimeout(()=>{ 165 | result = cache.all(); 166 | console.log(result); 167 | be.err.array(result); 168 | be.err.equal(result.length, 4); 169 | done(); 170 | }, 1500); 171 | 172 | }); 173 | }); 174 | 175 | describe('clear', function () { 176 | it('should be return an array', ()=>{ 177 | cache.clear(); 178 | cache.set('myKey1', 'myValue1'); 179 | cache.set('myKey2', 'myValue2'); 180 | cache.set('myKey3', 'myValue3'); 181 | cache.set('myKey4', 'myValue4'); 182 | cache.set('myKey5', 'myValue5'); 183 | result = cache.all(); 184 | be.err.array(result); 185 | be.err.equal(result.length, 5); 186 | cache.clear(); 187 | result = cache.all(); 188 | console.log(result); 189 | be.err.empty(global[cache.GLOBAL_KEY].data); 190 | be.err.array(result); 191 | be.err.equal(result.length, 0); 192 | }); 193 | }); 194 | 195 | describe('bulkSet', function () { 196 | it('should be return 5 records', ()=>{ 197 | cache.clear(); 198 | 199 | cache.bulkSet([ 200 | {key: 'key1', value: 'value1'}, 201 | {key: 'key2', value: 'value2'}, 202 | {key: 'key3', value: 'value3'}, 203 | {key: 'key4', value: 'value4'}, 204 | {key: 'key5', value: 'value5'}, 205 | ]); 206 | let result = cache.all(); 207 | console.log(result); 208 | be.err.equal(result.length, 5); 209 | }); 210 | 211 | it('wrong params type, should be return error', (done)=>{ 212 | cache.clear(); 213 | 214 | try { 215 | cache.bulkSet('hello'); 216 | } catch (e) { 217 | console.log(e.message); 218 | done(); 219 | } 220 | }); 221 | 222 | /* 223 | it('key param missing, should be return error', (done)=>{ 224 | cache.clear(); 225 | 226 | try { 227 | cache.bulkSet([{value: 'foo'}]); 228 | } catch (e) { 229 | console.log(e.message); 230 | done(); 231 | } 232 | }); 233 | 234 | it('value param missing, should be return error', (done)=>{ 235 | cache.clear(); 236 | 237 | try { 238 | cache.bulkSet([{key: 'foo'}]); 239 | } catch (e) { 240 | console.log(e.message); 241 | done(); 242 | } 243 | });*/ 244 | }); 245 | 246 | describe('bulkRemove', function () { 247 | it('should be return 2 records', ()=> { 248 | cache.clear(); 249 | cache.bulkSet([ 250 | {key: 'key1', value: 'value1'}, 251 | {key: 'key2', value: 'value2'}, 252 | {key: 'key3', value: 'value3'}, 253 | {key: 'key4', value: 'value4'}, 254 | {key: 'key5', value: 'value5'}, 255 | ]); 256 | 257 | cache.bulkRemove(['key1', 'key2', 'key5']); 258 | 259 | let result = cache.all(); 260 | console.log(result); 261 | be.err.equal(result.length, 2); 262 | be.err.equal(result[0].key, 'key3'); 263 | }); 264 | 265 | it('wrong params type, should be return error', (done)=>{ 266 | 267 | try { 268 | cache.bulkRemove('hello'); 269 | } catch (e) { 270 | console.log(e.message); 271 | done(); 272 | } 273 | }); 274 | }); 275 | 276 | describe('expired', function () { 277 | it('with param life, should be return true', (done)=>{ 278 | cache.set('myKeyExpiry1-life', 'myValue', { 279 | life: 1 280 | }); 281 | setTimeout(()=>{ 282 | be.err.true(cache.expired('myKeyExpiry1-life')); 283 | done(); 284 | }, 2000); 285 | }); 286 | it('with param maxAge, should be return true', (done)=>{ 287 | cache.set('myKeyExpiry1-maxAge', 'myValue', { 288 | maxAge: 1000 289 | }); 290 | setTimeout(()=>{ 291 | be.err.true(cache.expired('myKeyExpiry1-maxAge')); 292 | done(); 293 | }, 2000); 294 | }); 295 | it('with param expires, should be return true', (done)=>{ 296 | let now = new Date(); 297 | now = new Date(now.setSeconds(now.getSeconds() + 1)); 298 | cache.set('myKeyExpiry1-expires', 'myValue', { 299 | expires: now 300 | }); 301 | setTimeout(()=>{ 302 | be.err.true(cache.expired('myKeyExpiry1-expires')); 303 | done(); 304 | }, 2000); 305 | }); 306 | it('with param expires and string date, should be return true', (done)=>{ 307 | let now = new Date(); 308 | now = new Date(now.setSeconds(now.getSeconds() + 1)).toLocaleString(); 309 | let result = cache.set('myKeyExpiry1-expires2', 'myValue', { 310 | expires: now 311 | }); 312 | console.log(result); 313 | setTimeout(()=>{ 314 | be.err.true(cache.expired('myKeyExpiry1-expires2')); 315 | done(); 316 | }, 2000); 317 | }); 318 | 319 | it('key not found, should be return false', ()=>{ 320 | be.err.false(cache.expired('myKeyExpiry10')); 321 | }); 322 | }); 323 | 324 | describe('addTo', function () { 325 | it('should be return a record', (done)=>{ 326 | cache.set('myAddTo', ['hello', 'world']); 327 | let result = cache.addTo('myAddTo', 'ciao'); 328 | console.log(result); 329 | be.err(done).inArray('ciao', result.value); 330 | }); 331 | it('should be return error', (done)=>{ 332 | try { 333 | cache.set('myAddTo', 'hello'); 334 | cache.addTo('myAddTo', 'world'); 335 | } catch (e) { 336 | console.log(e.message); 337 | done(); 338 | } 339 | 340 | }); 341 | }); 342 | 343 | describe('prependTo', function () { 344 | it('should be return a record', ()=>{ 345 | cache.set('myPrependTo', ['hello', 'world']); 346 | let result = cache.prependTo('myPrependTo', 'ciao'); 347 | console.log(result); 348 | be.err.equal(result.value.indexOf('ciao'), 0); 349 | }); 350 | it('should be return error', (done)=>{ 351 | try { 352 | cache.set('myPrependTo', 'hello'); 353 | cache.prependTo('myPrependTo', 'world'); 354 | } catch (e) { 355 | console.log(e.message); 356 | done(); 357 | } 358 | 359 | }); 360 | }); 361 | 362 | describe('removeFrom', function () { 363 | it('should be remove array of object', ()=>{ 364 | cache.set('myRemoveFrom', [{a: 1, b: 2, c: 3}, {a: 1, d: 4}, {b: 2}]); 365 | cache.removeFrom('myRemoveFrom', {b: 2}); 366 | let result = cache.get('myRemoveFrom'); 367 | console.log(result); 368 | be.err.equal(result.length, 1); 369 | be.err.equal(result[0], {a: 1, d: 4}); 370 | }); 371 | it('should be remove array of string', ()=>{ 372 | cache.set('myRemoveFrom', ['hello', 'world', 'hello']); 373 | cache.removeFrom('myRemoveFrom', 'hello'); 374 | let result = cache.get('myRemoveFrom'); 375 | console.log(result); 376 | be.err.equal(result.length, 1); 377 | be.err.equal(result[0], 'world'); 378 | }); 379 | it('undefined where, should be return error', (done)=>{ 380 | try { 381 | cache.set('myRemoveFrom', 'hello world'); 382 | cache.removeFrom('myRemoveFrom'); 383 | } catch (e) { 384 | console.log(e.message); 385 | done(); 386 | } 387 | }); 388 | it('should be return error', (done)=>{ 389 | try { 390 | cache.set('myRemoveFrom', 'hello world'); 391 | cache.removeFrom('myRemoveFrom', 'world'); 392 | } catch (e) { 393 | console.log(e.message); 394 | done(); 395 | } 396 | }); 397 | }); 398 | 399 | describe('updateIn', function () { 400 | it('should be update', ()=>{ 401 | cache.set('myUpdateIn', [{a: 1, b: 2, c: 3}, {a: 1, d: 4}, {b: 2}]); 402 | cache.updateIn('myUpdateIn', {test: 1}, {b: 2}); 403 | let result = cache.get('myUpdateIn'); 404 | console.log(result); 405 | be.err.equal(result[0], {test: 1}); 406 | be.err.equal(result[2], {test: 1}); 407 | }); 408 | it('should be remove array of string', ()=>{ 409 | cache.set('myUpdateIn', ['hello', 'world', 'hello']); 410 | cache.updateIn('myUpdateIn', 'ciao', 'hello'); 411 | let result = cache.get('myUpdateIn'); 412 | console.log(result); 413 | be.err.equal(result[0], 'ciao'); 414 | be.err.equal(result[2], 'ciao'); 415 | }); 416 | it('undefined value, should be return error', (done)=>{ 417 | try { 418 | cache.set('myUpdateIn', 'hello world'); 419 | cache.updateIn('myUpdateIn'); 420 | } catch (e) { 421 | console.log(e.message); 422 | done(); 423 | } 424 | }); 425 | it('undefined where, should be return error', (done)=>{ 426 | try { 427 | cache.set('myUpdateIn', 'hello world'); 428 | cache.updateIn('myUpdateIn', 'ciao'); 429 | } catch (e) { 430 | console.log(e.message); 431 | done(); 432 | } 433 | }); 434 | it('should be return error', (done)=>{ 435 | try { 436 | cache.set('myUpdateIn', 'hello world'); 437 | cache.updateIn('myUpdateIn', 'world', 'hello'); 438 | } catch (e) { 439 | console.log(e.message); 440 | done(); 441 | } 442 | }); 443 | }); 444 | 445 | describe('clean', function() { 446 | it('should clean cache routes', function() { 447 | const exampleObject = { count: 3, rows: [{a: 1, b: 2, c: 3}, {a: 1, d: 4}, {b: 2}] }; 448 | cache.set('/api/users/0/10', exampleObject); 449 | cache.set('/api/users/1/10', exampleObject); 450 | cache.set('/api/posts/0/10', exampleObject); 451 | cache.clean('users'); 452 | let result = cache.get('/api/users/0/10'); 453 | let secondResult = cache.get('/api/users/1/10'); 454 | let unCleaned = cache.get('/api/posts/0/10'); 455 | be.err.undefined(result); 456 | be.err.undefined(secondResult); 457 | be.err.object(unCleaned); 458 | }); 459 | 460 | it('should be return error', (done) => { 461 | try { 462 | cache.set('myClean', 'hello world'); 463 | cache.clean(); 464 | } catch (e) { 465 | console.log(e.message); 466 | done(); 467 | } 468 | }); 469 | }); 470 | }); 471 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/issues/4.js: -------------------------------------------------------------------------------- 1 | const InCache = require('../../src/incache'); 2 | 3 | describe('issue 4', function () { 4 | 5 | describe('load', function () { 6 | it('should be return done, false', (done)=>{ 7 | const cache = new InCache({ 8 | autoLoad: true, 9 | filePath: false 10 | }); 11 | 12 | cache.load().then(()=>{ 13 | console.log('load nothing'); 14 | done(); 15 | }).catch(e => { 16 | console.log(e); 17 | }); 18 | 19 | }); 20 | 21 | it('should be return done, null', (done)=>{ 22 | const cache = new InCache({ 23 | autoLoad: true, 24 | filePath: null 25 | }); 26 | 27 | cache.load().then(()=>{ 28 | console.log('load nothing'); 29 | done(); 30 | }).catch(e => { 31 | console.log(e); 32 | }); 33 | 34 | }); 35 | 36 | it('should be return done, undefined', (done)=>{ 37 | const cache = new InCache({ 38 | autoLoad: true, 39 | filePath: undefined 40 | }); 41 | 42 | cache.load().then(()=>{ 43 | console.log('load nothing'); 44 | done(); 45 | }).catch(e => { 46 | console.log(e); 47 | }); 48 | 49 | }); 50 | 51 | it('should be return done, ""', (done)=>{ 52 | const cache = new InCache({ 53 | autoLoad: true, 54 | filePath: "" 55 | }); 56 | 57 | cache.load().then(()=>{ 58 | console.log('load nothing'); 59 | done(); 60 | }).catch(e => { 61 | console.log(e); 62 | }); 63 | 64 | }); 65 | }); 66 | 67 | describe('save', function () { 68 | it('should be return done, false', (done) => { 69 | const cache = new InCache({ 70 | filePath: false 71 | }); 72 | 73 | cache.save().then(() => { 74 | console.log('save nothing'); 75 | done(); 76 | }).catch(e => { 77 | console.log(e); 78 | }); 79 | 80 | }); 81 | 82 | }); 83 | 84 | }); -------------------------------------------------------------------------------- /test/performace/load.js: -------------------------------------------------------------------------------- 1 | const perf = require('execution-time')(); 2 | const InCache = require('../../'); 3 | 4 | perf.start(); 5 | console.log('start load'); 6 | 7 | const cache = new InCache(); 8 | 9 | console.log('result', cache.count()); 10 | console.log('finish load', perf.stop().time / 1000); 11 | -------------------------------------------------------------------------------- /test/performace/save.js: -------------------------------------------------------------------------------- 1 | const perf = require('execution-time')(); 2 | const InCache = require('../../'); 3 | 4 | console.log('start load'); 5 | perf.start(); 6 | 7 | const cache = new InCache(); 8 | 9 | console.log('finish load', perf.stop().time / 1000); 10 | 11 | perf.start(); 12 | console.log('start set'); 13 | 14 | for (let i = 0; i<1000000; i++) { 15 | cache.set('i' + i, { 16 | a: { 17 | b: { 18 | c: { 19 | d: { 20 | e: { 21 | f: { 22 | g: [ 23 | { 24 | h: { 25 | i: 'hello' 26 | } 27 | } 28 | ] 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | }); 36 | } 37 | console.log('result', cache.count()); 38 | console.log('finish set', perf.stop().time / 1000); 39 | 40 | perf.start(); 41 | console.log('start save'); 42 | cache.save().then(()=>{ 43 | console.log('finish save', perf.stop().time / 1000); 44 | }); 45 | -------------------------------------------------------------------------------- /version-to-tag.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | PACKAGE_VERSION=$(cat package.json | grep version | head -1 | awk -F= "{ print $2 }" | sed 's/[version:,\",]//g' | tr -d '[[:space:]]') 3 | git commit -a -m "v$PACKAGE_VERSION" 4 | git tag -a "v$PACKAGE_VERSION" -m "v$PACKAGE_VERSION" 5 | git push && git push --tags -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const unminifiedWebpackPlugin = require('unminified-webpack-plugin'); 3 | const WebpackAutoInject = require('webpack-auto-inject-version'); 4 | const pkg = require('./package.json'); 5 | 6 | const banner = ` 7 | ${pkg.name} - ${pkg.description} 8 | Author: ${pkg.author.name} 9 | Version: v${pkg.version} 10 | Url: ${pkg.homepage} 11 | License(s): ${pkg.license} 12 | `; 13 | 14 | module.exports = { 15 | entry: './index.js', 16 | output: { 17 | filename: './dist/incache.min.js', 18 | library: 'incache', 19 | umdNamedDefine: true, 20 | libraryTarget: 'umd' 21 | }, 22 | resolve: { 23 | modules: ['node_modules'], 24 | extensions: ['*', '.js'], 25 | }, 26 | module: { 27 | rules: [{ 28 | test: /\.js?$/, 29 | loader: 'babel-loader', 30 | options: { 31 | presets: ['es2015'], 32 | }, 33 | }], 34 | }, 35 | node: { 36 | fs: 'empty', 37 | child_process: 'empty' 38 | }, 39 | plugins: [ 40 | new webpack.optimize.UglifyJsPlugin({ 41 | mangle: true, 42 | comments: false, 43 | compress: { 44 | warnings: false 45 | }, include: /\.min\.js$/ 46 | }), 47 | new WebpackAutoInject({ 48 | PACKAGE_JSON_PATH: './package.json', 49 | components: { 50 | InjectAsComment: true, 51 | InjectByTag: true, 52 | }, 53 | componentsOptions: { 54 | InjectAsComment: { 55 | tag: 'InCache Build version: {version}' 56 | } 57 | } 58 | }), 59 | new unminifiedWebpackPlugin()/*, 60 | new webpack.BannerPlugin(banner)*/ 61 | ] 62 | }; 63 | --------------------------------------------------------------------------------