@onlineapps/conn-base-cache 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,383 @@
1
+ # @onlineapps/conn-base-cache
2
+
3
+ Redis cache connector with TTL, invalidation, and namespace support for OA Drive microservices.
4
+
5
+ ## Features
6
+
7
+ - ๐Ÿ”‘ **Automatic key prefixing** - All keys use `cache:` prefix
8
+ - โฑ๏ธ **TTL support** - Automatic expiration for cached data
9
+ - ๐Ÿ—‚๏ธ **Namespace isolation** - Separate cache spaces per service
10
+ - ๐Ÿ“Š **Built-in statistics** - Hit rate, miss tracking
11
+ - ๐Ÿ”„ **Atomic operations** - Increment, decrement support
12
+ - ๐ŸŽฏ **Pattern invalidation** - Delete by wildcard patterns
13
+ - ๐Ÿ” **Safe namespacing** - Never touches `obs:` monitoring keys
14
+ - ๐Ÿงช **Mock implementation** - For testing
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @onlineapps/conn-base-cache
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```javascript
25
+ const CacheConnector = require('@onlineapps/conn-base-cache');
26
+
27
+ const cache = new CacheConnector({
28
+ host: 'localhost',
29
+ port: 6379,
30
+ defaultTTL: 3600, // 1 hour
31
+ namespace: 'invoice-service'
32
+ });
33
+
34
+ await cache.connect();
35
+
36
+ // Set value with TTL
37
+ await cache.set('user:123', { name: 'John', role: 'admin' }, 600); // 10 min
38
+
39
+ // Get value
40
+ const user = await cache.get('user:123');
41
+
42
+ // Delete by pattern
43
+ await cache.deleteByPattern('user:*');
44
+
45
+ // Get statistics
46
+ console.log(cache.getStats());
47
+ // { hits: 1, misses: 0, sets: 1, deletes: 5, errors: 0, hitRate: '100%' }
48
+ ```
49
+
50
+ ## Configuration
51
+
52
+ | Option | Environment Variable | Default | Description |
53
+ |--------|---------------------|---------|-------------|
54
+ | `host` | `REDIS_HOST` | `localhost` | Redis server host |
55
+ | `port` | `REDIS_PORT` | `6379` | Redis server port |
56
+ | `password` | `REDIS_PASSWORD` | - | Redis password |
57
+ | `db` | `REDIS_DB` | `0` | Redis database number |
58
+ | `defaultTTL` | - | `3600` | Default TTL in seconds |
59
+ | `namespace` | - | - | Key namespace |
60
+ | `maxRetries` | - | `3` | Max connection retries |
61
+ | `retryDelay` | - | `100` | Retry delay in ms |
62
+
63
+ ## API Reference
64
+
65
+ ### Connection Management
66
+
67
+ #### `connect()`
68
+ Establish Redis connection.
69
+
70
+ ```javascript
71
+ await cache.connect();
72
+ ```
73
+
74
+ #### `disconnect()`
75
+ Close Redis connection.
76
+
77
+ ```javascript
78
+ await cache.disconnect();
79
+ ```
80
+
81
+ ### Basic Operations
82
+
83
+ #### `get(key)`
84
+ Get value from cache.
85
+
86
+ ```javascript
87
+ const value = await cache.get('key');
88
+ // Returns parsed object or string
89
+ ```
90
+
91
+ #### `set(key, value, ttl?)`
92
+ Set value in cache with optional TTL.
93
+
94
+ ```javascript
95
+ await cache.set('key', { data: 'value' }, 3600);
96
+ // Returns true on success
97
+ ```
98
+
99
+ #### `delete(key)`
100
+ Delete single key.
101
+
102
+ ```javascript
103
+ await cache.delete('key');
104
+ // Returns true if key existed
105
+ ```
106
+
107
+ #### `exists(key)`
108
+ Check if key exists.
109
+
110
+ ```javascript
111
+ const exists = await cache.exists('key');
112
+ // Returns boolean
113
+ ```
114
+
115
+ ### Pattern Operations
116
+
117
+ #### `deleteByPattern(pattern)`
118
+ Delete all keys matching pattern.
119
+
120
+ ```javascript
121
+ const deleted = await cache.deleteByPattern('session:*');
122
+ // Returns number of deleted keys
123
+ ```
124
+
125
+ ### TTL Management
126
+
127
+ #### `ttl(key)`
128
+ Get remaining TTL for key.
129
+
130
+ ```javascript
131
+ const seconds = await cache.ttl('key');
132
+ // Returns: seconds (-1 if no TTL, -2 if not exists)
133
+ ```
134
+
135
+ #### `expire(key, ttl)`
136
+ Update TTL for existing key.
137
+
138
+ ```javascript
139
+ await cache.expire('key', 7200); // 2 hours
140
+ // Returns true on success
141
+ ```
142
+
143
+ ### Atomic Operations
144
+
145
+ #### `incr(key, increment?)`
146
+ Increment numeric value.
147
+
148
+ ```javascript
149
+ const newValue = await cache.incr('counter', 5);
150
+ // Returns new value
151
+ ```
152
+
153
+ #### `decr(key, decrement?)`
154
+ Decrement numeric value.
155
+
156
+ ```javascript
157
+ const newValue = await cache.decr('counter', 1);
158
+ // Returns new value
159
+ ```
160
+
161
+ ### Batch Operations
162
+
163
+ #### `mget(keys)`
164
+ Get multiple values at once.
165
+
166
+ ```javascript
167
+ const values = await cache.mget(['key1', 'key2', 'key3']);
168
+ // Returns: { key1: value1, key2: value2, key3: value3 }
169
+ ```
170
+
171
+ #### `mset(keyValues, ttl?)`
172
+ Set multiple values at once.
173
+
174
+ ```javascript
175
+ await cache.mset({
176
+ 'key1': 'value1',
177
+ 'key2': { data: 'value2' }
178
+ }, 3600);
179
+ // Returns true on success
180
+ ```
181
+
182
+ ### Utility Methods
183
+
184
+ #### `withNamespace(namespace)`
185
+ Create namespaced instance.
186
+
187
+ ```javascript
188
+ const userCache = cache.withNamespace('users');
189
+ await userCache.set('123', userData);
190
+ // Actual key: cache:invoice-service:users:123
191
+ ```
192
+
193
+ #### `wrap(fn, options)`
194
+ Create cached function (memoization).
195
+
196
+ ```javascript
197
+ const cachedFetch = cache.wrap(async (userId) => {
198
+ return await fetchUserFromDB(userId);
199
+ }, {
200
+ ttl: 600,
201
+ keyPrefix: 'user'
202
+ });
203
+
204
+ const user = await cachedFetch(123);
205
+ // First call fetches from DB and caches
206
+ // Subsequent calls return from cache
207
+ ```
208
+
209
+ #### `flush(confirm)`
210
+ Clear all cache keys (dangerous!).
211
+
212
+ ```javascript
213
+ await cache.flush(true); // Must confirm with true
214
+ ```
215
+
216
+ #### `getStats()`
217
+ Get cache statistics.
218
+
219
+ ```javascript
220
+ const stats = cache.getStats();
221
+ // { hits: 50, misses: 10, sets: 30, deletes: 5, errors: 0, hitRate: '83.33%' }
222
+ ```
223
+
224
+ #### `healthCheck()`
225
+ Check Redis connection health.
226
+
227
+ ```javascript
228
+ const healthy = await cache.healthCheck();
229
+ // Returns boolean
230
+ ```
231
+
232
+ ## Usage Patterns
233
+
234
+ ### Service-Level Caching
235
+
236
+ ```javascript
237
+ class InvoiceService {
238
+ constructor() {
239
+ this.cache = new CacheConnector({
240
+ namespace: 'invoice-service'
241
+ });
242
+ }
243
+
244
+ async getInvoice(id) {
245
+ // Check cache first
246
+ const cached = await this.cache.get(`invoice:${id}`);
247
+ if (cached) return cached;
248
+
249
+ // Fetch from database
250
+ const invoice = await db.getInvoice(id);
251
+
252
+ // Cache for 1 hour
253
+ await this.cache.set(`invoice:${id}`, invoice, 3600);
254
+
255
+ return invoice;
256
+ }
257
+
258
+ async invalidateInvoice(id) {
259
+ await this.cache.delete(`invoice:${id}`);
260
+ }
261
+ }
262
+ ```
263
+
264
+ ### API Response Caching
265
+
266
+ ```javascript
267
+ // In service wrapper
268
+ async function callApiWithCache(operation, params) {
269
+ const cacheKey = `api:${operation}:${JSON.stringify(params)}`;
270
+
271
+ // Try cache
272
+ const cached = await cache.get(cacheKey);
273
+ if (cached) {
274
+ logger.debug('Cache hit for API call');
275
+ return cached;
276
+ }
277
+
278
+ // Make API call
279
+ const result = await apiCaller.call(operation, params);
280
+
281
+ // Cache result
282
+ await cache.set(cacheKey, result, 300); // 5 minutes
283
+
284
+ return result;
285
+ }
286
+ ```
287
+
288
+ ### Session Management
289
+
290
+ ```javascript
291
+ const sessionCache = cache.withNamespace('sessions');
292
+
293
+ // Store session
294
+ await sessionCache.set(sessionId, {
295
+ userId: 123,
296
+ roles: ['admin'],
297
+ createdAt: Date.now()
298
+ }, 1800); // 30 minutes
299
+
300
+ // Refresh session TTL
301
+ await sessionCache.expire(sessionId, 1800);
302
+
303
+ // Clear all sessions for user
304
+ await sessionCache.deleteByPattern(`*:user:123`);
305
+ ```
306
+
307
+ ## Testing
308
+
309
+ Use the built-in mock for testing:
310
+
311
+ ```javascript
312
+ const { MockCacheConnector } = require('@onlineapps/conn-base-cache');
313
+
314
+ describe('MyService', () => {
315
+ let cache;
316
+
317
+ beforeEach(() => {
318
+ cache = new MockCacheConnector();
319
+ });
320
+
321
+ it('should cache results', async () => {
322
+ await cache.set('test', 'value');
323
+ const value = await cache.get('test');
324
+ expect(value).toBe('value');
325
+ expect(cache.getStats().hits).toBe(1);
326
+ });
327
+ });
328
+ ```
329
+
330
+ ## Important Notes
331
+
332
+ 1. **Key Prefixing**: All keys automatically get `cache:` prefix
333
+ 2. **Namespace Isolation**: Use namespaces to avoid key collisions
334
+ 3. **TTL Best Practices**: Always set appropriate TTL to prevent memory issues
335
+ 4. **Pattern Deletion**: Use carefully as it can be expensive on large datasets
336
+ 5. **Never Access**: This connector never touches `obs:` namespace (monitoring)
337
+
338
+ ## Integration with Service Wrapper
339
+
340
+ ```javascript
341
+ class ServiceWrapper {
342
+ constructor(config) {
343
+ this.cache = new CacheConnector({
344
+ namespace: config.serviceName
345
+ });
346
+ }
347
+
348
+ async processWorkflow(message) {
349
+ // Cache workflow state
350
+ await this.cache.set(
351
+ `workflow:${message.workflowId}`,
352
+ message,
353
+ 600 // 10 minutes
354
+ );
355
+ }
356
+ }
357
+ ```
358
+
359
+ ## Error Handling
360
+
361
+ All methods throw errors with descriptive messages:
362
+
363
+ ```javascript
364
+ try {
365
+ await cache.get('key');
366
+ } catch (error) {
367
+ if (error.message.includes('Cache get failed')) {
368
+ // Handle cache failure
369
+ }
370
+ }
371
+ ```
372
+
373
+ ## Performance Tips
374
+
375
+ 1. **Use mget/mset** for batch operations
376
+ 2. **Enable pipelining** for multiple operations
377
+ 3. **Set appropriate TTL** to balance freshness and performance
378
+ 4. **Use namespaces** to organize keys
379
+ 5. **Monitor hit rate** with getStats()
380
+
381
+ ## License
382
+
383
+ MIT
@@ -0,0 +1,205 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <coverage generated="1758821391698" clover="3.2.0">
3
+ <project timestamp="1758821391699" name="All files">
4
+ <metrics statements="196" coveredstatements="164" conditionals="81" coveredconditionals="69" methods="42" coveredmethods="28" elements="319" coveredelements="261" complexity="0" loc="196" ncloc="196" packages="1" files="1" classes="1"/>
5
+ <file name="index.js" path="/var/www/html/oa_drive/shared/connector/conn-base-cache/src/index.js">
6
+ <metrics statements="196" coveredstatements="164" conditionals="81" coveredconditionals="69" methods="42" coveredmethods="28"/>
7
+ <line num="16" count="2" type="stmt"/>
8
+ <line num="17" count="2" type="stmt"/>
9
+ <line num="72" count="79" type="stmt"/>
10
+ <line num="86" count="79" type="cond" truecount="2" falsecount="0"/>
11
+ <line num="89" count="79" type="stmt"/>
12
+ <line num="92" count="79" type="stmt"/>
13
+ <line num="93" count="79" type="stmt"/>
14
+ <line num="96" count="79" type="stmt"/>
15
+ <line num="138" count="54" type="cond" truecount="4" falsecount="0"/>
16
+ <line num="139" count="1" type="stmt"/>
17
+ <line num="142" count="53" type="stmt"/>
18
+ <line num="144" count="53" type="stmt"/>
19
+ <line num="145" count="53" type="stmt"/>
20
+ <line num="152" count="0" type="cond" truecount="0" falsecount="2"/>
21
+ <line num="153" count="0" type="stmt"/>
22
+ <line num="155" count="0" type="stmt"/>
23
+ <line num="162" count="53" type="stmt"/>
24
+ <line num="163" count="0" type="stmt"/>
25
+ <line num="164" count="0" type="stmt"/>
26
+ <line num="165" count="0" type="stmt"/>
27
+ <line num="168" count="53" type="stmt"/>
28
+ <line num="169" count="0" type="stmt"/>
29
+ <line num="170" count="0" type="stmt"/>
30
+ <line num="173" count="53" type="stmt"/>
31
+ <line num="174" count="0" type="stmt"/>
32
+ <line num="175" count="0" type="stmt"/>
33
+ <line num="179" count="53" type="cond" truecount="1" falsecount="1"/>
34
+ <line num="180" count="53" type="stmt"/>
35
+ <line num="183" count="52" type="stmt"/>
36
+ <line num="184" count="52" type="stmt"/>
37
+ <line num="186" count="52" type="stmt"/>
38
+ <line num="188" count="1" type="stmt"/>
39
+ <line num="189" count="1" type="stmt"/>
40
+ <line num="205" count="15" type="cond" truecount="2" falsecount="0"/>
41
+ <line num="206" count="14" type="stmt"/>
42
+ <line num="207" count="14" type="stmt"/>
43
+ <line num="208" count="14" type="stmt"/>
44
+ <line num="217" count="98" type="cond" truecount="2" falsecount="0"/>
45
+ <line num="218" count="97" type="stmt"/>
46
+ <line num="220" count="1" type="stmt"/>
47
+ <line num="250" count="31" type="stmt"/>
48
+ <line num="251" count="31" type="stmt"/>
49
+ <line num="252" count="31" type="stmt"/>
50
+ <line num="254" count="29" type="cond" truecount="2" falsecount="0"/>
51
+ <line num="255" count="9" type="stmt"/>
52
+ <line num="256" count="9" type="stmt"/>
53
+ <line num="259" count="20" type="stmt"/>
54
+ <line num="262" count="20" type="stmt"/>
55
+ <line num="263" count="20" type="stmt"/>
56
+ <line num="266" count="11" type="stmt"/>
57
+ <line num="269" count="2" type="stmt"/>
58
+ <line num="270" count="2" type="stmt"/>
59
+ <line num="296" count="29" type="stmt"/>
60
+ <line num="297" count="29" type="stmt"/>
61
+ <line num="298" count="29" type="cond" truecount="2" falsecount="0"/>
62
+ <line num="299" count="28" type="cond" truecount="2" falsecount="0"/>
63
+ <line num="301" count="28" type="cond" truecount="1" falsecount="1"/>
64
+ <line num="302" count="28" type="stmt"/>
65
+ <line num="304" count="0" type="stmt"/>
66
+ <line num="307" count="26" type="stmt"/>
67
+ <line num="308" count="26" type="stmt"/>
68
+ <line num="310" count="3" type="stmt"/>
69
+ <line num="311" count="3" type="stmt"/>
70
+ <line num="332" count="8" type="stmt"/>
71
+ <line num="333" count="8" type="stmt"/>
72
+ <line num="334" count="8" type="stmt"/>
73
+ <line num="336" count="7" type="stmt"/>
74
+ <line num="337" count="7" type="stmt"/>
75
+ <line num="339" count="1" type="stmt"/>
76
+ <line num="340" count="1" type="stmt"/>
77
+ <line num="364" count="3" type="stmt"/>
78
+ <line num="365" count="3" type="stmt"/>
79
+ <line num="366" count="3" type="stmt"/>
80
+ <line num="368" count="2" type="cond" truecount="2" falsecount="0"/>
81
+ <line num="369" count="1" type="stmt"/>
82
+ <line num="373" count="2" type="stmt"/>
83
+ <line num="374" count="1" type="stmt"/>
84
+ <line num="376" count="1" type="stmt"/>
85
+ <line num="377" count="1" type="stmt"/>
86
+ <line num="379" count="1" type="stmt"/>
87
+ <line num="380" count="1" type="stmt"/>
88
+ <line num="400" count="3" type="stmt"/>
89
+ <line num="401" count="3" type="stmt"/>
90
+ <line num="402" count="3" type="stmt"/>
91
+ <line num="403" count="2" type="stmt"/>
92
+ <line num="405" count="1" type="stmt"/>
93
+ <line num="406" count="1" type="stmt"/>
94
+ <line num="431" count="4" type="stmt"/>
95
+ <line num="432" count="4" type="stmt"/>
96
+ <line num="433" count="4" type="stmt"/>
97
+ <line num="435" count="1" type="stmt"/>
98
+ <line num="436" count="1" type="stmt"/>
99
+ <line num="456" count="3" type="stmt"/>
100
+ <line num="457" count="3" type="stmt"/>
101
+ <line num="458" count="3" type="stmt"/>
102
+ <line num="459" count="2" type="stmt"/>
103
+ <line num="461" count="1" type="stmt"/>
104
+ <line num="462" count="1" type="stmt"/>
105
+ <line num="485" count="4" type="stmt"/>
106
+ <line num="486" count="4" type="stmt"/>
107
+ <line num="488" count="4" type="cond" truecount="2" falsecount="0"/>
108
+ <line num="489" count="3" type="stmt"/>
109
+ <line num="491" count="1" type="stmt"/>
110
+ <line num="494" count="1" type="stmt"/>
111
+ <line num="495" count="1" type="stmt"/>
112
+ <line num="517" count="3" type="stmt"/>
113
+ <line num="518" count="3" type="stmt"/>
114
+ <line num="520" count="3" type="cond" truecount="2" falsecount="0"/>
115
+ <line num="521" count="2" type="stmt"/>
116
+ <line num="523" count="1" type="stmt"/>
117
+ <line num="526" count="1" type="stmt"/>
118
+ <line num="527" count="1" type="stmt"/>
119
+ <line num="547" count="3" type="stmt"/>
120
+ <line num="548" count="7" type="stmt"/>
121
+ <line num="549" count="3" type="stmt"/>
122
+ <line num="551" count="2" type="stmt"/>
123
+ <line num="552" count="2" type="stmt"/>
124
+ <line num="553" count="6" type="cond" truecount="2" falsecount="0"/>
125
+ <line num="554" count="4" type="stmt"/>
126
+ <line num="555" count="4" type="stmt"/>
127
+ <line num="556" count="2" type="stmt"/>
128
+ <line num="558" count="2" type="stmt"/>
129
+ <line num="559" count="2" type="stmt"/>
130
+ <line num="562" count="2" type="stmt"/>
131
+ <line num="566" count="2" type="stmt"/>
132
+ <line num="568" count="1" type="stmt"/>
133
+ <line num="569" count="1" type="stmt"/>
134
+ <line num="592" count="2" type="stmt"/>
135
+ <line num="593" count="2" type="stmt"/>
136
+ <line num="595" count="2" type="stmt"/>
137
+ <line num="596" count="3" type="stmt"/>
138
+ <line num="597" count="3" type="cond" truecount="2" falsecount="0"/>
139
+ <line num="598" count="3" type="cond" truecount="2" falsecount="0"/>
140
+ <line num="600" count="3" type="cond" truecount="1" falsecount="1"/>
141
+ <line num="601" count="3" type="stmt"/>
142
+ <line num="603" count="0" type="stmt"/>
143
+ <line num="606" count="3" type="stmt"/>
144
+ <line num="609" count="2" type="stmt"/>
145
+ <line num="610" count="1" type="stmt"/>
146
+ <line num="612" count="1" type="stmt"/>
147
+ <line num="613" count="1" type="stmt"/>
148
+ <line num="635" count="4" type="cond" truecount="2" falsecount="0"/>
149
+ <line num="636" count="2" type="stmt"/>
150
+ <line num="639" count="2" type="stmt"/>
151
+ <line num="641" count="2" type="stmt"/>
152
+ <line num="643" count="1" type="cond" truecount="1" falsecount="1"/>
153
+ <line num="644" count="2" type="stmt"/>
154
+ <line num="645" count="1" type="stmt"/>
155
+ <line num="648" count="1" type="stmt"/>
156
+ <line num="650" count="1" type="stmt"/>
157
+ <line num="651" count="1" type="stmt"/>
158
+ <line num="673" count="5" type="stmt"/>
159
+ <line num="692" count="2" type="stmt"/>
160
+ <line num="717" count="1" type="stmt"/>
161
+ <line num="760" count="2" type="cond" truecount="2" falsecount="0"/>
162
+ <line num="761" count="2" type="cond" truecount="2" falsecount="1"/>
163
+ <line num="762" count="2" type="cond" truecount="2" falsecount="0"/>
164
+ <line num="763" count="3" type="stmt"/>
165
+ <line num="764" count="3" type="stmt"/>
166
+ <line num="765" count="3" type="stmt"/>
167
+ <line num="768" count="2" type="stmt"/>
168
+ <line num="769" count="3" type="stmt"/>
169
+ <line num="772" count="3" type="stmt"/>
170
+ <line num="773" count="3" type="cond" truecount="2" falsecount="0"/>
171
+ <line num="774" count="1" type="stmt"/>
172
+ <line num="778" count="2" type="stmt"/>
173
+ <line num="781" count="1" type="stmt"/>
174
+ <line num="783" count="1" type="stmt"/>
175
+ <line num="802" count="3" type="stmt"/>
176
+ <line num="803" count="3" type="stmt"/>
177
+ <line num="804" count="1" type="stmt"/>
178
+ <line num="806" count="2" type="stmt"/>
179
+ <line num="857" count="2" type="stmt"/>
180
+ <line num="872" count="2" type="stmt"/>
181
+ <line num="878" count="2" type="stmt"/>
182
+ <line num="881" count="2" type="stmt"/>
183
+ <line num="883" count="0" type="stmt"/>
184
+ <line num="884" count="0" type="stmt"/>
185
+ <line num="887" count="0" type="stmt"/>
186
+ <line num="888" count="0" type="stmt"/>
187
+ <line num="891" count="0" type="cond" truecount="0" falsecount="2"/>
188
+ <line num="892" count="0" type="stmt"/>
189
+ <line num="893" count="0" type="stmt"/>
190
+ <line num="895" count="0" type="stmt"/>
191
+ <line num="896" count="0" type="stmt"/>
192
+ <line num="900" count="0" type="stmt"/>
193
+ <line num="901" count="0" type="stmt"/>
194
+ <line num="903" count="0" type="cond" truecount="0" falsecount="2"/>
195
+ <line num="904" count="0" type="stmt"/>
196
+ <line num="906" count="0" type="stmt"/>
197
+ <line num="910" count="0" type="stmt"/>
198
+ <line num="911" count="0" type="stmt"/>
199
+ <line num="915" count="0" type="stmt"/>
200
+ <line num="916" count="0" type="stmt"/>
201
+ <line num="919" count="0" type="stmt"/>
202
+ <line num="921" count="0" type="stmt"/>
203
+ </file>
204
+ </project>
205
+ </coverage>