@geekmidas/cache 0.0.7 → 0.2.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.
Files changed (73) hide show
  1. package/dist/{chunk-DWy1uDak.cjs → chunk-CUT6urMc.cjs} +0 -9
  2. package/dist/expo.cjs +4 -3
  3. package/dist/expo.cjs.map +1 -0
  4. package/dist/expo.d.cts +8 -5
  5. package/dist/expo.d.cts.map +1 -0
  6. package/dist/expo.d.mts +8 -5
  7. package/dist/expo.d.mts.map +1 -0
  8. package/dist/expo.mjs +3 -2
  9. package/dist/expo.mjs.map +1 -0
  10. package/dist/{index-B6eF5Yxi.d.cts → index-BSYYdwRm.d.cts} +8 -5
  11. package/dist/index-BSYYdwRm.d.cts.map +1 -0
  12. package/dist/{index-Bv61mxVT.d.mts → index-Dx96gr-9.d.mts} +8 -5
  13. package/dist/index-Dx96gr-9.d.mts.map +1 -0
  14. package/dist/index.cjs +1 -1
  15. package/dist/index.d.cts +1 -1
  16. package/dist/index.d.mts +1 -1
  17. package/dist/index.mjs +1 -1
  18. package/dist/memory.cjs +35 -3
  19. package/dist/memory.cjs.map +1 -0
  20. package/dist/memory.d.cts +8 -5
  21. package/dist/memory.d.cts.map +1 -0
  22. package/dist/memory.d.mts +8 -5
  23. package/dist/memory.d.mts.map +1 -0
  24. package/dist/memory.mjs +34 -3
  25. package/dist/memory.mjs.map +1 -0
  26. package/dist/{src-DVpoP03o.mjs → src-CrE4Nl5T.mjs} +2 -1
  27. package/dist/src-CrE4Nl5T.mjs.map +1 -0
  28. package/dist/{src-C7d6HaTp.cjs → src-zfYb7mdS.cjs} +3 -2
  29. package/dist/src-zfYb7mdS.cjs.map +1 -0
  30. package/dist/upstash.cjs +32 -2
  31. package/dist/upstash.cjs.map +1 -0
  32. package/dist/upstash.d.cts +8 -5
  33. package/dist/upstash.d.cts.map +1 -0
  34. package/dist/upstash.d.mts +8 -5
  35. package/dist/upstash.d.mts.map +1 -0
  36. package/dist/upstash.mjs +31 -2
  37. package/dist/upstash.mjs.map +1 -0
  38. package/package.json +6 -2
  39. package/src/__benchmarks__/memory.bench.ts +51 -0
  40. package/src/__tests__/cache.spec.ts +138 -105
  41. package/src/__tests__/integration.spec.ts +277 -268
  42. package/src/__tests__/memory.spec.ts +129 -129
  43. package/src/__tests__/upstash.spec.ts +209 -180
  44. package/src/expo.ts +45 -46
  45. package/src/index.ts +37 -36
  46. package/src/memory.ts +28 -27
  47. package/src/upstash.ts +28 -28
  48. package/tsconfig.json +9 -0
  49. package/tsdown.config.ts +1 -1
  50. package/dist/__tests__/cache.spec.cjs +0 -77
  51. package/dist/__tests__/cache.spec.d.cts +0 -1
  52. package/dist/__tests__/cache.spec.d.mts +0 -1
  53. package/dist/__tests__/cache.spec.mjs +0 -77
  54. package/dist/__tests__/integration.spec.cjs +0 -235
  55. package/dist/__tests__/integration.spec.d.cts +0 -1
  56. package/dist/__tests__/integration.spec.d.mts +0 -1
  57. package/dist/__tests__/integration.spec.mjs +0 -235
  58. package/dist/__tests__/memory.spec.cjs +0 -126
  59. package/dist/__tests__/memory.spec.d.cts +0 -1
  60. package/dist/__tests__/memory.spec.d.mts +0 -1
  61. package/dist/__tests__/memory.spec.mjs +0 -126
  62. package/dist/__tests__/upstash.spec.cjs +0 -201
  63. package/dist/__tests__/upstash.spec.d.cts +0 -1
  64. package/dist/__tests__/upstash.spec.d.mts +0 -1
  65. package/dist/__tests__/upstash.spec.mjs +0 -201
  66. package/dist/magic-string.es-CBih0MJw.mjs +0 -1014
  67. package/dist/magic-string.es-KiPEzMtt.cjs +0 -1015
  68. package/dist/memory-Csy6J-Ak.cjs +0 -39
  69. package/dist/memory-QDTnSEX5.mjs +0 -33
  70. package/dist/upstash-CXy_duOa.mjs +0 -31
  71. package/dist/upstash-u8Hs4sZG.cjs +0 -37
  72. package/dist/vi.bdSIJ99Y-B-qkABPq.cjs +0 -14955
  73. package/dist/vi.bdSIJ99Y-CB5havZF.mjs +0 -14951
@@ -1,273 +1,282 @@
1
1
  import { beforeEach, describe, expect, it } from 'vitest';
2
- import type { Cache } from '../cache';
2
+ import type { Cache } from '../';
3
3
  import { InMemoryCache } from '../memory';
4
4
 
5
5
  describe('Cache Integration Tests', () => {
6
- let memoryCache: Cache<any>;
7
-
8
- beforeEach(() => {
9
- memoryCache = new InMemoryCache();
10
- });
11
-
12
- describe('cross-cache behavior consistency', () => {
13
- const testCases = [
14
- { name: 'InMemoryCache', cache: () => new InMemoryCache() },
15
- ];
16
-
17
- testCases.forEach(({ name, cache }) => {
18
- describe(name, () => {
19
- let cacheInstance: Cache<any>;
20
-
21
- beforeEach(() => {
22
- cacheInstance = cache();
23
- });
24
-
25
- it('should handle basic CRUD operations', async () => {
26
- // Create
27
- await cacheInstance.set('user:1', { id: 1, name: 'John' });
28
-
29
- // Read
30
- const user = await cacheInstance.get('user:1');
31
- expect(user).toEqual({ id: 1, name: 'John' });
32
-
33
- // Update
34
- await cacheInstance.set('user:1', { id: 1, name: 'Jane' });
35
- const updatedUser = await cacheInstance.get('user:1');
36
- expect(updatedUser).toEqual({ id: 1, name: 'Jane' });
37
-
38
- // Delete
39
- await cacheInstance.delete('user:1');
40
- const deletedUser = await cacheInstance.get('user:1');
41
- expect(deletedUser).toBeUndefined();
42
- });
43
-
44
- it('should handle concurrent operations', async () => {
45
- const operations = [
46
- cacheInstance.set('key1', 'value1'),
47
- cacheInstance.set('key2', 'value2'),
48
- cacheInstance.set('key3', 'value3'),
49
- ];
50
-
51
- await Promise.all(operations);
52
-
53
- const results = await Promise.all([
54
- cacheInstance.get('key1'),
55
- cacheInstance.get('key2'),
56
- cacheInstance.get('key3'),
57
- ]);
58
-
59
- expect(results).toEqual(['value1', 'value2', 'value3']);
60
- });
61
-
62
- it('should handle data type preservation', async () => {
63
- const testData = {
64
- string: 'hello',
65
- number: 42,
66
- boolean: true,
67
- object: { nested: true },
68
- array: [1, 2, 3],
69
- null: null,
70
- };
71
-
72
- // Store all data types
73
- await Promise.all(
74
- Object.entries(testData).map(([key, value]) =>
75
- cacheInstance.set(key, value),
76
- ),
77
- );
78
-
79
- // Retrieve and verify
80
- const results = await Promise.all(
81
- Object.keys(testData).map((key) => cacheInstance.get(key)),
82
- );
83
-
84
- expect(results[0]).toBe('hello');
85
- expect(results[1]).toBe(42);
86
- expect(results[2]).toBe(true);
87
- expect(results[3]).toEqual({ nested: true });
88
- expect(results[4]).toEqual([1, 2, 3]);
89
- expect(results[5]).toBeNull();
90
- });
91
-
92
- it('should handle key isolation', async () => {
93
- await cacheInstance.set('user:1', 'User One');
94
- await cacheInstance.set('user:2', 'User Two');
95
- await cacheInstance.set('session:1', 'Session One');
96
-
97
- await cacheInstance.delete('user:1');
98
-
99
- expect(await cacheInstance.get('user:1')).toBeUndefined();
100
- expect(await cacheInstance.get('user:2')).toBe('User Two');
101
- expect(await cacheInstance.get('session:1')).toBe('Session One');
102
- });
103
- });
104
- });
105
- });
106
-
107
- describe('cache migration scenarios', () => {
108
- it('should support migrating data between cache implementations', async () => {
109
- const sourceCache = new InMemoryCache<any>();
110
- const targetCache = new InMemoryCache<any>();
111
-
112
- // Populate source cache
113
- const testData = {
114
- 'user:1': { id: 1, name: 'John' },
115
- 'user:2': { id: 2, name: 'Jane' },
116
- 'config:app': { theme: 'dark', notifications: true },
117
- };
118
-
119
- for (const [key, value] of Object.entries(testData)) {
120
- await sourceCache.set(key, value);
121
- }
122
-
123
- // Simulate migration by reading from source and writing to target
124
- const migrationKeys = Object.keys(testData);
125
- for (const key of migrationKeys) {
126
- const value = await sourceCache.get(key);
127
- if (value !== undefined) {
128
- await targetCache.set(key, value);
129
- }
130
- }
131
-
132
- // Verify migration
133
- for (const [key, expectedValue] of Object.entries(testData)) {
134
- const migratedValue = await targetCache.get(key);
135
- expect(migratedValue).toEqual(expectedValue);
136
- }
137
- });
138
- });
139
-
140
- describe('cache abstraction patterns', () => {
141
- it('should support cache factory pattern', async () => {
142
- const createCache = <T>(type: 'memory'): Cache<T> => {
143
- switch (type) {
144
- case 'memory':
145
- return new InMemoryCache<T>();
146
- default:
147
- throw new Error(`Unknown cache type: ${type}`);
148
- }
149
- };
150
-
151
- const userCache = createCache<{ id: number; name: string }>('memory');
152
- const sessionCache = createCache<string>('memory');
153
-
154
- await userCache.set('user:1', { id: 1, name: 'John' });
155
- await sessionCache.set('session:abc', 'active');
156
-
157
- expect(await userCache.get('user:1')).toEqual({ id: 1, name: 'John' });
158
- expect(await sessionCache.get('session:abc')).toBe('active');
159
- });
160
-
161
- it('should support cache wrapper pattern', async () => {
162
- class LoggingCache<T> implements Cache<T> {
163
- private logs: string[] = [];
164
-
165
- constructor(private underlying: Cache<T>) {}
166
-
167
- async get(key: string): Promise<T | undefined> {
168
- this.logs.push(`GET ${key}`);
169
- return this.underlying.get(key);
170
- }
171
-
172
- async set(key: string, value: T): Promise<void> {
173
- this.logs.push(`SET ${key}`);
174
- return this.underlying.set(key, value);
175
- }
176
-
177
- async delete(key: string): Promise<void> {
178
- this.logs.push(`DELETE ${key}`);
179
- return this.underlying.delete(key);
180
- }
181
-
182
- getLogs(): string[] {
183
- return [...this.logs];
184
- }
185
- }
186
-
187
- const baseCache = new InMemoryCache<string>();
188
- const loggingCache = new LoggingCache(baseCache);
189
-
190
- await loggingCache.set('test', 'value');
191
- await loggingCache.get('test');
192
- await loggingCache.delete('test');
193
-
194
- const logs = loggingCache.getLogs();
195
- expect(logs).toEqual(['SET test', 'GET test', 'DELETE test']);
196
- });
197
- });
198
-
199
- describe('performance and stress tests', () => {
200
- it('should handle large number of operations', async () => {
201
- const cache = new InMemoryCache<number>();
202
- const operationCount = 1000;
203
-
204
- // Bulk insert
205
- const insertPromises = Array.from({ length: operationCount }, (_, i) =>
206
- cache.set(`key:${i}`, i),
207
- );
208
- await Promise.all(insertPromises);
209
-
210
- // Bulk read
211
- const readPromises = Array.from({ length: operationCount }, (_, i) =>
212
- cache.get(`key:${i}`),
213
- );
214
- const results = await Promise.all(readPromises);
215
-
216
- // Verify all values
217
- for (let i = 0; i < operationCount; i++) {
218
- expect(results[i]).toBe(i);
219
- }
220
-
221
- // Bulk delete
222
- const deletePromises = Array.from({ length: operationCount }, (_, i) =>
223
- cache.delete(`key:${i}`),
224
- );
225
- await Promise.all(deletePromises);
226
-
227
- // Verify deletion
228
- const postDeleteRead = await cache.get('key:0');
229
- expect(postDeleteRead).toBeUndefined();
230
- });
231
-
232
- it('should handle large objects efficiently', async () => {
233
- const cache = new InMemoryCache<any>();
234
-
235
- const largeObject = {
236
- id: 1,
237
- data: Array.from({ length: 1000 }, (_, i) => ({
238
- index: i,
239
- value: `value-${i}`,
240
- metadata: {
241
- timestamp: Date.now(),
242
- random: Math.random(),
243
- },
244
- })),
245
- };
246
-
247
- const startTime = Date.now();
248
- await cache.set('large-object', largeObject);
249
- const result = await cache.get('large-object');
250
- const endTime = Date.now();
251
-
252
- expect(result).toEqual(largeObject);
253
- expect(endTime - startTime).toBeLessThan(100); // Should complete within 100ms
254
- });
255
- });
256
-
257
- describe('error scenarios', () => {
258
- it('should handle operations after errors gracefully', async () => {
259
- const cache = new InMemoryCache<string>();
260
-
261
- // Successful operations
262
- await cache.set('valid-key', 'valid-value');
263
- expect(await cache.get('valid-key')).toBe('valid-value');
264
-
265
- // Operations should continue working normally
266
- await cache.set('another-key', 'another-value');
267
- expect(await cache.get('another-key')).toBe('another-value');
268
-
269
- await cache.delete('valid-key');
270
- expect(await cache.get('valid-key')).toBeUndefined();
271
- });
272
- });
6
+ let _memoryCache: Cache;
7
+
8
+ beforeEach(() => {
9
+ _memoryCache = new InMemoryCache();
10
+ });
11
+
12
+ describe('cross-cache behavior consistency', () => {
13
+ const testCases = [
14
+ { name: 'InMemoryCache', cache: () => new InMemoryCache() },
15
+ ];
16
+
17
+ testCases.forEach(({ name, cache }) => {
18
+ describe(name, () => {
19
+ let cacheInstance: Cache;
20
+
21
+ beforeEach(() => {
22
+ cacheInstance = cache();
23
+ });
24
+
25
+ it('should handle basic CRUD operations', async () => {
26
+ // Create
27
+ await cacheInstance.set('user:1', { id: 1, name: 'John' });
28
+
29
+ // Read
30
+ const user = await cacheInstance.get('user:1');
31
+ expect(user).toEqual({ id: 1, name: 'John' });
32
+
33
+ // Update
34
+ await cacheInstance.set('user:1', { id: 1, name: 'Jane' });
35
+ const updatedUser = await cacheInstance.get('user:1');
36
+ expect(updatedUser).toEqual({ id: 1, name: 'Jane' });
37
+
38
+ // Delete
39
+ await cacheInstance.delete('user:1');
40
+ const deletedUser = await cacheInstance.get('user:1');
41
+ expect(deletedUser).toBeUndefined();
42
+ });
43
+
44
+ it('should handle concurrent operations', async () => {
45
+ const operations = [
46
+ cacheInstance.set('key1', 'value1'),
47
+ cacheInstance.set('key2', 'value2'),
48
+ cacheInstance.set('key3', 'value3'),
49
+ ];
50
+
51
+ await Promise.all(operations);
52
+
53
+ const results = await Promise.all([
54
+ cacheInstance.get('key1'),
55
+ cacheInstance.get('key2'),
56
+ cacheInstance.get('key3'),
57
+ ]);
58
+
59
+ expect(results).toEqual(['value1', 'value2', 'value3']);
60
+ });
61
+
62
+ it('should handle data type preservation', async () => {
63
+ const testData = {
64
+ string: 'hello',
65
+ number: 42,
66
+ boolean: true,
67
+ object: { nested: true },
68
+ array: [1, 2, 3],
69
+ null: null,
70
+ };
71
+
72
+ // Store all data types
73
+ await Promise.all(
74
+ Object.entries(testData).map(([key, value]) =>
75
+ cacheInstance.set(key, value),
76
+ ),
77
+ );
78
+
79
+ // Retrieve and verify
80
+ const results = await Promise.all(
81
+ Object.keys(testData).map((key) => cacheInstance.get(key)),
82
+ );
83
+
84
+ expect(results[0]).toBe('hello');
85
+ expect(results[1]).toBe(42);
86
+ expect(results[2]).toBe(true);
87
+ expect(results[3]).toEqual({ nested: true });
88
+ expect(results[4]).toEqual([1, 2, 3]);
89
+ expect(results[5]).toBeNull();
90
+ });
91
+
92
+ it('should handle key isolation', async () => {
93
+ await cacheInstance.set('user:1', 'User One');
94
+ await cacheInstance.set('user:2', 'User Two');
95
+ await cacheInstance.set('session:1', 'Session One');
96
+
97
+ await cacheInstance.delete('user:1');
98
+
99
+ expect(await cacheInstance.get('user:1')).toBeUndefined();
100
+ expect(await cacheInstance.get('user:2')).toBe('User Two');
101
+ expect(await cacheInstance.get('session:1')).toBe('Session One');
102
+ });
103
+ });
104
+ });
105
+ });
106
+
107
+ describe('cache migration scenarios', () => {
108
+ it('should support migrating data between cache implementations', async () => {
109
+ const sourceCache = new InMemoryCache();
110
+ const targetCache = new InMemoryCache();
111
+
112
+ // Populate source cache
113
+ const testData = {
114
+ 'user:1': { id: 1, name: 'John' },
115
+ 'user:2': { id: 2, name: 'Jane' },
116
+ 'config:app': { theme: 'dark', notifications: true },
117
+ };
118
+
119
+ for (const [key, value] of Object.entries(testData)) {
120
+ await sourceCache.set(key, value);
121
+ }
122
+
123
+ // Simulate migration by reading from source and writing to target
124
+ const migrationKeys = Object.keys(testData);
125
+ for (const key of migrationKeys) {
126
+ const value = await sourceCache.get(key);
127
+ if (value !== undefined) {
128
+ await targetCache.set(key, value);
129
+ }
130
+ }
131
+
132
+ // Verify migration
133
+ for (const [key, expectedValue] of Object.entries(testData)) {
134
+ const migratedValue = await targetCache.get(key);
135
+ expect(migratedValue).toEqual(expectedValue);
136
+ }
137
+ });
138
+ });
139
+
140
+ describe('cache abstraction patterns', () => {
141
+ it('should support cache factory pattern', async () => {
142
+ const createCache = (type: 'memory'): Cache => {
143
+ switch (type) {
144
+ case 'memory':
145
+ return new InMemoryCache();
146
+ default:
147
+ throw new Error(`Unknown cache type: ${type}`);
148
+ }
149
+ };
150
+
151
+ const userCache = createCache('memory');
152
+ const sessionCache = createCache('memory');
153
+
154
+ await userCache.set<{ id: number; name: string }>('user:1', {
155
+ id: 1,
156
+ name: 'John',
157
+ });
158
+ await sessionCache.set<string>('session:abc', 'active');
159
+
160
+ expect(
161
+ await userCache.get<{ id: number; name: string }>('user:1'),
162
+ ).toEqual({ id: 1, name: 'John' });
163
+ expect(await sessionCache.get<string>('session:abc')).toBe('active');
164
+ });
165
+
166
+ it('should support cache wrapper pattern', async () => {
167
+ class LoggingCache implements Cache {
168
+ private logs: string[] = [];
169
+
170
+ constructor(private underlying: Cache) {}
171
+
172
+ async get<T>(key: string): Promise<T | undefined> {
173
+ this.logs.push(`GET ${key}`);
174
+ return this.underlying.get<T>(key);
175
+ }
176
+
177
+ async set<T>(key: string, value: T, ttl?: number): Promise<void> {
178
+ this.logs.push(`SET ${key}`);
179
+ return this.underlying.set<T>(key, value, ttl);
180
+ }
181
+
182
+ async delete(key: string): Promise<void> {
183
+ this.logs.push(`DELETE ${key}`);
184
+ return this.underlying.delete(key);
185
+ }
186
+
187
+ async ttl(key: string): Promise<number> {
188
+ return this.underlying.ttl(key);
189
+ }
190
+
191
+ getLogs(): string[] {
192
+ return [...this.logs];
193
+ }
194
+ }
195
+
196
+ const baseCache = new InMemoryCache();
197
+ const loggingCache = new LoggingCache(baseCache);
198
+
199
+ await loggingCache.set('test', 'value');
200
+ await loggingCache.get('test');
201
+ await loggingCache.delete('test');
202
+
203
+ const logs = loggingCache.getLogs();
204
+ expect(logs).toEqual(['SET test', 'GET test', 'DELETE test']);
205
+ });
206
+ });
207
+
208
+ describe('performance and stress tests', () => {
209
+ it('should handle large number of operations', async () => {
210
+ const cache = new InMemoryCache();
211
+ const operationCount = 1000;
212
+
213
+ // Bulk insert
214
+ const insertPromises = Array.from({ length: operationCount }, (_, i) =>
215
+ cache.set(`key:${i}`, i),
216
+ );
217
+ await Promise.all(insertPromises);
218
+
219
+ // Bulk read
220
+ const readPromises = Array.from({ length: operationCount }, (_, i) =>
221
+ cache.get(`key:${i}`),
222
+ );
223
+ const results = await Promise.all(readPromises);
224
+
225
+ // Verify all values
226
+ for (let i = 0; i < operationCount; i++) {
227
+ expect(results[i]).toBe(i);
228
+ }
229
+
230
+ // Bulk delete
231
+ const deletePromises = Array.from({ length: operationCount }, (_, i) =>
232
+ cache.delete(`key:${i}`),
233
+ );
234
+ await Promise.all(deletePromises);
235
+
236
+ // Verify deletion
237
+ const postDeleteRead = await cache.get('key:0');
238
+ expect(postDeleteRead).toBeUndefined();
239
+ });
240
+
241
+ it('should handle large objects efficiently', async () => {
242
+ const cache = new InMemoryCache();
243
+
244
+ const largeObject = {
245
+ id: 1,
246
+ data: Array.from({ length: 1000 }, (_, i) => ({
247
+ index: i,
248
+ value: `value-${i}`,
249
+ metadata: {
250
+ timestamp: Date.now(),
251
+ random: Math.random(),
252
+ },
253
+ })),
254
+ };
255
+
256
+ const startTime = Date.now();
257
+ await cache.set('large-object', largeObject);
258
+ const result = await cache.get('large-object');
259
+ const endTime = Date.now();
260
+
261
+ expect(result).toEqual(largeObject);
262
+ expect(endTime - startTime).toBeLessThan(100); // Should complete within 100ms
263
+ });
264
+ });
265
+
266
+ describe('error scenarios', () => {
267
+ it('should handle operations after errors gracefully', async () => {
268
+ const cache = new InMemoryCache();
269
+
270
+ // Successful operations
271
+ await cache.set('valid-key', 'valid-value');
272
+ expect(await cache.get('valid-key')).toBe('valid-value');
273
+
274
+ // Operations should continue working normally
275
+ await cache.set('another-key', 'another-value');
276
+ expect(await cache.get('another-key')).toBe('another-value');
277
+
278
+ await cache.delete('valid-key');
279
+ expect(await cache.get('valid-key')).toBeUndefined();
280
+ });
281
+ });
273
282
  });