UNPKG

6.06 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _Cache = require("./Cache");
8
9var _Cache2 = _interopRequireDefault(_Cache);
10
11var _CacheEntry = require("./CacheEntry");
12
13var _CacheEntry2 = _interopRequireDefault(_CacheEntry);
14
15function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
17/**
18 * Configurable generic implementation of the {@link Cache} interface.
19 *
20 * @example
21 * if (cache.has('model.articles')) {
22 * return cache.get('model.articles');
23 * } else {
24 * let articles = getArticlesFromStorage();
25 * // cache for an hour
26 * cache.set('model.articles', articles, 60 * 60 * 1000);
27 * }
28 * @extends Cache
29 */
30class CacheImpl extends _Cache2.default {
31 /**
32 * Initializes the cache.
33 *
34 * @param {Storage} cacheStorage The cache entry storage to use.
35 * @param {CacheFactory} factory Which create new instance of cache entry.
36 * @param {vendor.$Helper} Helper The IMA.js helper methods.
37 * @param {{ttl: number, enabled: boolean}} [config={ttl: 30000, enabled: false}]
38 * The cache configuration.
39 */
40 constructor(cacheStorage, factory, Helper, config = {
41 ttl: 30000,
42 enabled: false
43 }) {
44 super();
45 /**
46 * Cache entry storage.
47 *
48 * @type {Storage}
49 */
50
51 this._cache = cacheStorage;
52 /**
53 * @type {CacheFactory}
54 */
55
56 this._factory = factory;
57 /**
58 * Tha IMA.js helper methods.
59 *
60 * @type {vendor.$Helper}
61 */
62
63 this._Helper = Helper;
64 /**
65 * Default cache entry time to live in milliseconds.
66 *
67 * @type {number}
68 */
69
70 this._ttl = config.ttl;
71 /**
72 * Flag signalling whether the cache is currently enabled.
73 *
74 * @type {boolean}
75 */
76
77 this._enabled = config.enabled;
78 }
79 /**
80 * @inheritdoc
81 */
82
83
84 clear() {
85 this._cache.clear();
86 }
87 /**
88 * @inheritdoc
89 */
90
91
92 has(key) {
93 if (!this._enabled || !this._cache.has(key)) {
94 return false;
95 }
96
97 let cacheEntry = this._cache.get(key);
98
99 if (cacheEntry && !cacheEntry.isExpired()) {
100 return true;
101 }
102
103 this.delete(key);
104 return false;
105 }
106 /**
107 * @inheritdoc
108 */
109
110
111 get(key) {
112 if (this.has(key)) {
113 let value = this._cache.get(key).getValue();
114
115 return this._clone(value);
116 }
117
118 return null;
119 }
120 /**
121 * @inheritdoc
122 */
123
124
125 set(key, value, ttl = null) {
126 if (!this._enabled) {
127 return;
128 }
129
130 let cacheEntry = this._factory.createCacheEntry(this._clone(value), ttl || this._ttl);
131
132 this._cache.set(key, cacheEntry);
133 }
134 /**
135 * @inheritdoc
136 */
137
138
139 delete(key) {
140 this._cache.delete(key);
141 }
142 /**
143 * @inheritdoc
144 */
145
146
147 disable() {
148 this._enabled = false;
149 this.clear();
150 }
151 /**
152 * @inheritdoc
153 */
154
155
156 enable() {
157 this._enabled = true;
158 }
159 /**
160 * @inheritdoc
161 */
162
163
164 serialize() {
165 let dataToSerialize = {};
166
167 for (let key of this._cache.keys()) {
168 const currentValue = this._cache.get(key);
169
170 if (currentValue instanceof _CacheEntry2.default) {
171 const serializeEntry = currentValue.serialize();
172
173 if (serializeEntry.ttl === Infinity) {
174 serializeEntry.ttl = 'Infinity';
175 }
176
177 if ($Debug) {
178 if (!this._canSerializeValue(serializeEntry.value)) {
179 throw new Error(`ima.cache.CacheImpl:serialize An ` + `attempt to serialize ` + `${serializeEntry.value.toString()}, stored ` + `using the key ${key}, was made, but the value ` + `cannot be serialized. Remove this entry from ` + `the cache or change its type so that can be ` + `serialized using JSON.stringify().`);
180 }
181 }
182
183 dataToSerialize[key] = serializeEntry;
184 }
185 }
186
187 return JSON.stringify(dataToSerialize).replace(/<\/script/gi, '<\\/script');
188 }
189 /**
190 * @inheritdoc
191 */
192
193
194 deserialize(serializedData) {
195 for (let key of Object.keys(serializedData)) {
196 let cacheEntryItem = serializedData[key];
197
198 if (cacheEntryItem.ttl === 'Infinity') {
199 cacheEntryItem.ttl = Infinity;
200 }
201
202 this.set(key, cacheEntryItem.value, cacheEntryItem.ttl);
203 }
204 }
205 /**
206 * Tests whether the provided value can be serialized into JSON.
207 *
208 * @param {*} value The value to test whether or not it can be serialized.
209 * @return {boolean} `true` if the provided value can be serialized into JSON,
210 * `false` otherwise.
211 */
212
213
214 _canSerializeValue(value) {
215 if (value instanceof Date || value instanceof RegExp || value instanceof Promise || typeof value === 'function') {
216 console.warn('The provided value is not serializable: ', value);
217 return false;
218 }
219
220 if (!value) {
221 return true;
222 }
223
224 if (value.constructor === Array) {
225 for (let element of value) {
226 if (!this._canSerializeValue(element)) {
227 console.warn('The provided array is not serializable: ', value);
228 return false;
229 }
230 }
231 }
232
233 if (typeof value === 'object') {
234 for (let propertyName of Object.keys(value)) {
235 if (!this._canSerializeValue(value[propertyName])) {
236 console.warn('The provided object is not serializable due to the ' + 'following property: ', propertyName, value);
237 return false;
238 }
239 }
240 }
241
242 return true;
243 }
244 /**
245 * Attempts to clone the provided value, if possible. Values that cannot be
246 * cloned (e.g. promises) will be simply returned.
247 *
248 * @param {*} value The value to clone.
249 * @return {*} The created clone, or the provided value if the value cannot be
250 * cloned.
251 */
252
253
254 _clone(value) {
255 if (value !== null && typeof value === 'object' && !(value instanceof Promise)) {
256 return this._Helper.clone(value);
257 }
258
259 return value;
260 }
261
262}
263
264exports.default = CacheImpl;
265
266typeof $IMA !== 'undefined' && $IMA !== null && $IMA.Loader && $IMA.Loader.register('ima/cache/CacheImpl', [], function (_export, _context) {
267 'use strict';
268 return {
269 setters: [],
270 execute: function () {
271 _export('default', exports.default);
272 }
273 };
274});