@expo/entity-cache-adapter-redis 0.31.0 → 0.32.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 +2 -3
- package/build/GenericRedisCacher.d.ts +11 -0
- package/build/GenericRedisCacher.js +6 -0
- package/build/GenericRedisCacher.js.map +1 -1
- package/build/RedisCacheAdapterProvider.d.ts +4 -4
- package/build/RedisCacheAdapterProvider.js +3 -2
- package/build/RedisCacheAdapterProvider.js.map +1 -1
- package/build/RedisCommon.js +1 -1
- package/build/RedisCommon.js.map +1 -1
- package/build/__integration-tests__/BatchedRedisCacheAdapter-integration-test.js +10 -11
- package/build/__integration-tests__/BatchedRedisCacheAdapter-integration-test.js.map +1 -1
- package/build/__integration-tests__/{RedisCacheAdapter-integration-test.js → GenericRedisCacher-full-integration-test.js} +20 -22
- package/build/__integration-tests__/GenericRedisCacher-full-integration-test.js.map +1 -0
- package/build/__integration-tests__/GenericRedisCacher-integration-test.js +11 -25
- package/build/__integration-tests__/GenericRedisCacher-integration-test.js.map +1 -1
- package/build/__integration-tests__/errors-test.js +5 -6
- package/build/__integration-tests__/errors-test.js.map +1 -1
- package/build/__tests__/{RedisCacheAdapter-test.js → GenericRedisCacher-test.js} +35 -35
- package/build/__tests__/GenericRedisCacher-test.js.map +1 -0
- package/build/index.d.ts +0 -2
- package/build/index.js +1 -4
- package/build/index.js.map +1 -1
- package/build/testfixtures/RedisTestEntity.d.ts +2 -2
- package/build/testfixtures/RedisTestEntity.js +6 -7
- package/build/testfixtures/RedisTestEntity.js.map +1 -1
- package/build/testfixtures/createRedisIntegrationTestEntityCompanionProvider.d.ts +2 -2
- package/build/testfixtures/createRedisIntegrationTestEntityCompanionProvider.js +2 -2
- package/package.json +4 -4
- package/src/GenericRedisCacher.ts +28 -0
- package/src/RedisCacheAdapterProvider.ts +10 -5
- package/src/__integration-tests__/BatchedRedisCacheAdapter-integration-test.ts +17 -15
- package/src/__integration-tests__/{RedisCacheAdapter-integration-test.ts → GenericRedisCacher-full-integration-test.ts} +26 -22
- package/src/__integration-tests__/GenericRedisCacher-integration-test.ts +12 -27
- package/src/__integration-tests__/errors-test.ts +5 -6
- package/src/__tests__/GenericRedisCacher-test.ts +193 -0
- package/src/index.ts +0 -2
- package/src/testfixtures/RedisTestEntity.ts +6 -8
- package/src/testfixtures/createRedisIntegrationTestEntityCompanionProvider.ts +3 -3
- package/build/RedisCacheAdapter.d.ts +0 -43
- package/build/RedisCacheAdapter.js +0 -44
- package/build/RedisCacheAdapter.js.map +0 -1
- package/build/__integration-tests__/RedisCacheAdapter-integration-test.js.map +0 -1
- package/build/__tests__/RedisCacheAdapter-test.js.map +0 -1
- package/src/RedisCacheAdapter.ts +0 -124
- package/src/__tests__/RedisCacheAdapter-test.ts +0 -169
- /package/build/__integration-tests__/{RedisCacheAdapter-integration-test.d.ts → GenericRedisCacher-full-integration-test.d.ts} +0 -0
- /package/build/__tests__/{RedisCacheAdapter-test.d.ts → GenericRedisCacher-test.d.ts} +0 -0
|
@@ -2,8 +2,7 @@ import { CacheStatus, ViewerContext } from '@expo/entity';
|
|
|
2
2
|
import Redis from 'ioredis';
|
|
3
3
|
import { URL } from 'url';
|
|
4
4
|
|
|
5
|
-
import GenericRedisCacher from '../GenericRedisCacher';
|
|
6
|
-
import { RedisCacheAdapterContext } from '../RedisCacheAdapter';
|
|
5
|
+
import GenericRedisCacher, { GenericRedisCacheContext } from '../GenericRedisCacher';
|
|
7
6
|
import RedisTestEntity, {
|
|
8
7
|
redisTestEntityConfiguration,
|
|
9
8
|
RedisTestEntityFields,
|
|
@@ -13,12 +12,11 @@ import { createRedisIntegrationTestEntityCompanionProvider } from '../testfixtur
|
|
|
13
12
|
class TestViewerContext extends ViewerContext {}
|
|
14
13
|
|
|
15
14
|
describe(GenericRedisCacher, () => {
|
|
16
|
-
|
|
17
|
-
let redisCacheAdapterContext: RedisCacheAdapterContext;
|
|
15
|
+
let genericRedisCacheContext: GenericRedisCacheContext;
|
|
18
16
|
|
|
19
17
|
beforeAll(() => {
|
|
20
|
-
|
|
21
|
-
redisClient,
|
|
18
|
+
genericRedisCacheContext = {
|
|
19
|
+
redisClient: new Redis(new URL(process.env['REDIS_URL']!).toString()),
|
|
22
20
|
makeKeyFn(...parts: string[]): string {
|
|
23
21
|
const delimiter = ':';
|
|
24
22
|
const escapedParts = parts.map((part) =>
|
|
@@ -27,29 +25,24 @@ describe(GenericRedisCacher, () => {
|
|
|
27
25
|
return escapedParts.join(delimiter);
|
|
28
26
|
},
|
|
29
27
|
cacheKeyPrefix: 'test-',
|
|
30
|
-
cacheKeyVersion: 1,
|
|
31
28
|
ttlSecondsPositive: 86400, // 1 day
|
|
32
29
|
ttlSecondsNegative: 600, // 10 minutes
|
|
33
30
|
};
|
|
34
31
|
});
|
|
35
32
|
|
|
36
33
|
beforeEach(async () => {
|
|
37
|
-
await redisClient.flushdb();
|
|
34
|
+
await (genericRedisCacheContext.redisClient as Redis).flushdb();
|
|
38
35
|
});
|
|
39
36
|
afterAll(async () => {
|
|
40
|
-
redisClient.disconnect();
|
|
37
|
+
(genericRedisCacheContext.redisClient as Redis).disconnect();
|
|
41
38
|
});
|
|
42
39
|
|
|
43
40
|
it('has correct caching and loading behavior', async () => {
|
|
44
41
|
const viewerContext = new TestViewerContext(
|
|
45
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
42
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
46
43
|
);
|
|
47
44
|
const genericRedisCacher = new GenericRedisCacher(
|
|
48
|
-
|
|
49
|
-
redisClient: redisCacheAdapterContext.redisClient,
|
|
50
|
-
ttlSecondsNegative: redisCacheAdapterContext.ttlSecondsNegative,
|
|
51
|
-
ttlSecondsPositive: redisCacheAdapterContext.ttlSecondsPositive,
|
|
52
|
-
},
|
|
45
|
+
genericRedisCacheContext,
|
|
53
46
|
redisTestEntityConfiguration
|
|
54
47
|
);
|
|
55
48
|
const date = new Date();
|
|
@@ -63,7 +56,7 @@ describe(GenericRedisCacher, () => {
|
|
|
63
56
|
]);
|
|
64
57
|
await genericRedisCacher.cacheManyAsync(objectMap);
|
|
65
58
|
|
|
66
|
-
const cachedJSON = await redisClient.get(testKey);
|
|
59
|
+
const cachedJSON = await (genericRedisCacheContext.redisClient as Redis).get(testKey);
|
|
67
60
|
const cachedValue = JSON.parse(cachedJSON!);
|
|
68
61
|
expect(cachedValue).toMatchObject({
|
|
69
62
|
id: entity1Created.getID(),
|
|
@@ -80,11 +73,7 @@ describe(GenericRedisCacher, () => {
|
|
|
80
73
|
});
|
|
81
74
|
it('has correct negative caching behaviour', async () => {
|
|
82
75
|
const genericRedisCacher = new GenericRedisCacher(
|
|
83
|
-
|
|
84
|
-
redisClient: redisCacheAdapterContext.redisClient,
|
|
85
|
-
ttlSecondsNegative: redisCacheAdapterContext.ttlSecondsNegative,
|
|
86
|
-
ttlSecondsPositive: redisCacheAdapterContext.ttlSecondsPositive,
|
|
87
|
-
},
|
|
76
|
+
genericRedisCacheContext,
|
|
88
77
|
redisTestEntityConfiguration
|
|
89
78
|
);
|
|
90
79
|
|
|
@@ -96,14 +85,10 @@ describe(GenericRedisCacher, () => {
|
|
|
96
85
|
});
|
|
97
86
|
it('has correct invalidation behaviour', async () => {
|
|
98
87
|
const viewerContext = new TestViewerContext(
|
|
99
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
88
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
100
89
|
);
|
|
101
90
|
const genericRedisCacher = new GenericRedisCacher(
|
|
102
|
-
|
|
103
|
-
redisClient: redisCacheAdapterContext.redisClient,
|
|
104
|
-
ttlSecondsNegative: redisCacheAdapterContext.ttlSecondsNegative,
|
|
105
|
-
ttlSecondsPositive: redisCacheAdapterContext.ttlSecondsPositive,
|
|
106
|
-
},
|
|
91
|
+
genericRedisCacheContext,
|
|
107
92
|
redisTestEntityConfiguration
|
|
108
93
|
);
|
|
109
94
|
const date = new Date();
|
|
@@ -2,18 +2,18 @@ import { EntityCacheAdapterTransientError, ViewerContext } from '@expo/entity';
|
|
|
2
2
|
import Redis from 'ioredis';
|
|
3
3
|
import { URL } from 'url';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import GenericRedisCacher, { GenericRedisCacheContext } from '../GenericRedisCacher';
|
|
6
6
|
import RedisTestEntity from '../testfixtures/RedisTestEntity';
|
|
7
7
|
import { createRedisIntegrationTestEntityCompanionProvider } from '../testfixtures/createRedisIntegrationTestEntityCompanionProvider';
|
|
8
8
|
|
|
9
9
|
class TestViewerContext extends ViewerContext {}
|
|
10
10
|
|
|
11
|
-
describe(
|
|
11
|
+
describe(GenericRedisCacher, () => {
|
|
12
12
|
const redisClient = new Redis(new URL(process.env['REDIS_URL']!).toString());
|
|
13
|
-
let
|
|
13
|
+
let genericRedisCacheContext: GenericRedisCacheContext;
|
|
14
14
|
|
|
15
15
|
beforeAll(() => {
|
|
16
|
-
|
|
16
|
+
genericRedisCacheContext = {
|
|
17
17
|
redisClient,
|
|
18
18
|
makeKeyFn(...parts: string[]): string {
|
|
19
19
|
const delimiter = ':';
|
|
@@ -23,7 +23,6 @@ describe(RedisCacheAdapter, () => {
|
|
|
23
23
|
return escapedParts.join(delimiter);
|
|
24
24
|
},
|
|
25
25
|
cacheKeyPrefix: 'test-',
|
|
26
|
-
cacheKeyVersion: 1,
|
|
27
26
|
ttlSecondsPositive: 86400, // 1 day
|
|
28
27
|
ttlSecondsNegative: 600, // 10 minutes
|
|
29
28
|
};
|
|
@@ -37,7 +36,7 @@ describe(RedisCacheAdapter, () => {
|
|
|
37
36
|
redisClient.disconnect();
|
|
38
37
|
|
|
39
38
|
const vc1 = new TestViewerContext(
|
|
40
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
39
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
41
40
|
);
|
|
42
41
|
|
|
43
42
|
await expect(
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { CacheStatus, UUIDField, EntityConfiguration } from '@expo/entity';
|
|
2
|
+
import { Redis, Pipeline } from 'ioredis';
|
|
3
|
+
import { mock, when, instance, anything, verify } from 'ts-mockito';
|
|
4
|
+
|
|
5
|
+
import GenericRedisCacher from '../GenericRedisCacher';
|
|
6
|
+
|
|
7
|
+
type BlahFields = {
|
|
8
|
+
id: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const entityConfiguration = new EntityConfiguration<BlahFields>({
|
|
12
|
+
idField: 'id',
|
|
13
|
+
tableName: 'blah',
|
|
14
|
+
schema: {
|
|
15
|
+
id: new UUIDField({ columnName: 'id', cache: true }),
|
|
16
|
+
},
|
|
17
|
+
databaseAdapterFlavor: 'postgres',
|
|
18
|
+
cacheAdapterFlavor: 'redis',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe(GenericRedisCacher, () => {
|
|
22
|
+
describe('loadManyAsync', () => {
|
|
23
|
+
it('returns appropriate cache results', async () => {
|
|
24
|
+
const redisResults = new Map();
|
|
25
|
+
|
|
26
|
+
const mockRedisClient = mock<Redis>();
|
|
27
|
+
|
|
28
|
+
// need to have one anything() for each element of spread, in this case 3
|
|
29
|
+
when(mockRedisClient.mget(anything(), anything(), anything())).thenCall(async (...keys) =>
|
|
30
|
+
keys.map((k) => redisResults.get(k) ?? null)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const genericCacher = new GenericRedisCacher(
|
|
34
|
+
{
|
|
35
|
+
redisClient: instance(mockRedisClient),
|
|
36
|
+
makeKeyFn: (...parts) => parts.join(':'),
|
|
37
|
+
cacheKeyPrefix: 'hello-',
|
|
38
|
+
ttlSecondsPositive: 1,
|
|
39
|
+
ttlSecondsNegative: 2,
|
|
40
|
+
},
|
|
41
|
+
entityConfiguration
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const cacheKeyWat = genericCacher['makeCacheKey']('id', 'wat');
|
|
45
|
+
const cacheKeyWho = genericCacher['makeCacheKey']('id', 'who');
|
|
46
|
+
const cacheKeyWhy = genericCacher['makeCacheKey']('id', 'why');
|
|
47
|
+
|
|
48
|
+
redisResults.set(cacheKeyWat, JSON.stringify({ id: 'wat' }));
|
|
49
|
+
redisResults.set(cacheKeyWho, '');
|
|
50
|
+
|
|
51
|
+
const results = await genericCacher.loadManyAsync([cacheKeyWat, cacheKeyWho, cacheKeyWhy]);
|
|
52
|
+
|
|
53
|
+
expect(results.get(cacheKeyWat)).toMatchObject({
|
|
54
|
+
status: CacheStatus.HIT,
|
|
55
|
+
item: { id: 'wat' },
|
|
56
|
+
});
|
|
57
|
+
expect(results.get(cacheKeyWho)).toMatchObject({ status: CacheStatus.NEGATIVE });
|
|
58
|
+
expect(results.get(cacheKeyWhy)).toMatchObject({ status: CacheStatus.MISS });
|
|
59
|
+
expect(results.size).toBe(3);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('returns empty map when passed empty array of fieldValues', async () => {
|
|
63
|
+
const genericCacher = new GenericRedisCacher(
|
|
64
|
+
{
|
|
65
|
+
redisClient: instance(mock<Redis>()),
|
|
66
|
+
makeKeyFn: (...parts) => parts.join(':'),
|
|
67
|
+
cacheKeyPrefix: 'hello-',
|
|
68
|
+
ttlSecondsPositive: 1,
|
|
69
|
+
ttlSecondsNegative: 2,
|
|
70
|
+
},
|
|
71
|
+
entityConfiguration
|
|
72
|
+
);
|
|
73
|
+
const results = await genericCacher.loadManyAsync([]);
|
|
74
|
+
expect(results).toEqual(new Map());
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('cacheManyAsync', () => {
|
|
79
|
+
it('correctly caches all objects', async () => {
|
|
80
|
+
const redisResults = new Map();
|
|
81
|
+
|
|
82
|
+
const mockPipeline = mock<Pipeline>();
|
|
83
|
+
when(mockPipeline.set(anything(), anything(), anything(), anything())).thenCall(
|
|
84
|
+
(key, value, code, ttl) => {
|
|
85
|
+
redisResults.set(key, { value, code, ttl });
|
|
86
|
+
return pipeline;
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
when(mockPipeline.exec()).thenResolve({} as any);
|
|
90
|
+
const pipeline = instance(mockPipeline);
|
|
91
|
+
|
|
92
|
+
const mockRedisClient = mock<Redis>();
|
|
93
|
+
when(mockRedisClient.multi()).thenReturn(pipeline);
|
|
94
|
+
|
|
95
|
+
const genericCacher = new GenericRedisCacher(
|
|
96
|
+
{
|
|
97
|
+
redisClient: instance(mockRedisClient),
|
|
98
|
+
makeKeyFn: (...parts) => parts.join(':'),
|
|
99
|
+
cacheKeyPrefix: 'hello-',
|
|
100
|
+
ttlSecondsPositive: 1,
|
|
101
|
+
ttlSecondsNegative: 2,
|
|
102
|
+
},
|
|
103
|
+
entityConfiguration
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
107
|
+
|
|
108
|
+
await genericCacher.cacheManyAsync(new Map([[cacheKey, { id: 'wat' }]]));
|
|
109
|
+
|
|
110
|
+
expect(redisResults.get(cacheKey)).toMatchObject({
|
|
111
|
+
value: JSON.stringify({ id: 'wat' }),
|
|
112
|
+
code: 'EX',
|
|
113
|
+
ttl: 1,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('cacheDBMissesAsync', () => {
|
|
119
|
+
it('correctly caches misses', async () => {
|
|
120
|
+
const redisResults = new Map();
|
|
121
|
+
const mockPipeline = mock<Pipeline>();
|
|
122
|
+
when(mockPipeline.set(anything(), anything(), anything(), anything())).thenCall(
|
|
123
|
+
(key, value, code, ttl) => {
|
|
124
|
+
redisResults.set(key, { value, code, ttl });
|
|
125
|
+
return pipeline;
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
when(mockPipeline.exec()).thenResolve({} as any);
|
|
129
|
+
const pipeline = instance(mockPipeline);
|
|
130
|
+
|
|
131
|
+
const mockRedisClient = mock<Redis>();
|
|
132
|
+
when(mockRedisClient.multi()).thenReturn(pipeline);
|
|
133
|
+
|
|
134
|
+
const genericCacher = new GenericRedisCacher(
|
|
135
|
+
{
|
|
136
|
+
redisClient: instance(mockRedisClient),
|
|
137
|
+
makeKeyFn: (...parts) => parts.join(':'),
|
|
138
|
+
cacheKeyPrefix: 'hello-',
|
|
139
|
+
ttlSecondsPositive: 1,
|
|
140
|
+
ttlSecondsNegative: 2,
|
|
141
|
+
},
|
|
142
|
+
entityConfiguration
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
146
|
+
|
|
147
|
+
await genericCacher.cacheDBMissesAsync([cacheKey]);
|
|
148
|
+
|
|
149
|
+
expect(redisResults.get(cacheKey)).toMatchObject({
|
|
150
|
+
value: '',
|
|
151
|
+
code: 'EX',
|
|
152
|
+
ttl: 2,
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('invalidateManyAsync', () => {
|
|
158
|
+
it('invalidates correctly', async () => {
|
|
159
|
+
const mockRedisClient = mock<Redis>();
|
|
160
|
+
when(mockRedisClient.del()).thenResolve(1);
|
|
161
|
+
|
|
162
|
+
const genericCacher = new GenericRedisCacher(
|
|
163
|
+
{
|
|
164
|
+
redisClient: instance(mockRedisClient),
|
|
165
|
+
makeKeyFn: (...parts) => parts.join(':'),
|
|
166
|
+
cacheKeyPrefix: 'hello-',
|
|
167
|
+
ttlSecondsPositive: 1,
|
|
168
|
+
ttlSecondsNegative: 2,
|
|
169
|
+
},
|
|
170
|
+
entityConfiguration
|
|
171
|
+
);
|
|
172
|
+
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
173
|
+
|
|
174
|
+
await genericCacher.invalidateManyAsync([cacheKey]);
|
|
175
|
+
|
|
176
|
+
verify(mockRedisClient.del(cacheKey)).once();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('returns when passed empty array of fieldValues', async () => {
|
|
180
|
+
const genericCacher = new GenericRedisCacher(
|
|
181
|
+
{
|
|
182
|
+
redisClient: instance(mock<Redis>()),
|
|
183
|
+
makeKeyFn: (...parts) => parts.join(':'),
|
|
184
|
+
cacheKeyPrefix: 'hello-',
|
|
185
|
+
ttlSecondsPositive: 1,
|
|
186
|
+
ttlSecondsNegative: 2,
|
|
187
|
+
},
|
|
188
|
+
entityConfiguration
|
|
189
|
+
);
|
|
190
|
+
await genericCacher.invalidateManyAsync([]);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
* @module @expo/entity-cache-adapter-redis
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export { default as RedisCacheAdapter } from './RedisCacheAdapter';
|
|
8
|
-
export * from './RedisCacheAdapter';
|
|
9
7
|
export { default as RedisCacheAdapterProvider } from './RedisCacheAdapterProvider';
|
|
10
8
|
export * from './RedisCommon';
|
|
11
9
|
export { default as GenericRedisCacher } from './GenericRedisCacher';
|
|
@@ -17,14 +17,18 @@ export type RedisTestEntityFields = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export default class RedisTestEntity extends Entity<RedisTestEntityFields, string, ViewerContext> {
|
|
20
|
-
static
|
|
20
|
+
static defineCompanionDefinition(): EntityCompanionDefinition<
|
|
21
21
|
RedisTestEntityFields,
|
|
22
22
|
string,
|
|
23
23
|
ViewerContext,
|
|
24
24
|
RedisTestEntity,
|
|
25
25
|
RedisTestEntityPrivacyPolicy
|
|
26
26
|
> {
|
|
27
|
-
return
|
|
27
|
+
return {
|
|
28
|
+
entityClass: RedisTestEntity,
|
|
29
|
+
entityConfiguration: redisTestEntityConfiguration,
|
|
30
|
+
privacyPolicyClass: RedisTestEntityPrivacyPolicy,
|
|
31
|
+
};
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -87,9 +91,3 @@ export const redisTestEntityConfiguration = new EntityConfiguration<RedisTestEnt
|
|
|
87
91
|
databaseAdapterFlavor: 'postgres',
|
|
88
92
|
cacheAdapterFlavor: 'redis',
|
|
89
93
|
});
|
|
90
|
-
|
|
91
|
-
const redisTestEntityCompanionDefinition = new EntityCompanionDefinition({
|
|
92
|
-
entityClass: RedisTestEntity,
|
|
93
|
-
entityConfiguration: redisTestEntityConfiguration,
|
|
94
|
-
privacyPolicyClass: RedisTestEntityPrivacyPolicy,
|
|
95
|
-
});
|
|
@@ -6,14 +6,14 @@ import {
|
|
|
6
6
|
StubDatabaseAdapterProvider,
|
|
7
7
|
} from '@expo/entity';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { GenericRedisCacheContext } from '../GenericRedisCacher';
|
|
10
10
|
import RedisCacheAdapterProvider from '../RedisCacheAdapterProvider';
|
|
11
11
|
|
|
12
12
|
// share across all in calls in test to simulate postgres
|
|
13
13
|
const adapterProvider = new StubDatabaseAdapterProvider();
|
|
14
14
|
|
|
15
15
|
export const createRedisIntegrationTestEntityCompanionProvider = (
|
|
16
|
-
|
|
16
|
+
genericRedisCacheContext: GenericRedisCacheContext,
|
|
17
17
|
metricsAdapter: IEntityMetricsAdapter = new NoOpEntityMetricsAdapter()
|
|
18
18
|
): EntityCompanionProvider => {
|
|
19
19
|
return new EntityCompanionProvider(
|
|
@@ -31,7 +31,7 @@ export const createRedisIntegrationTestEntityCompanionProvider = (
|
|
|
31
31
|
[
|
|
32
32
|
'redis',
|
|
33
33
|
{
|
|
34
|
-
cacheAdapterProvider: new RedisCacheAdapterProvider(
|
|
34
|
+
cacheAdapterProvider: new RedisCacheAdapterProvider(genericRedisCacheContext),
|
|
35
35
|
},
|
|
36
36
|
],
|
|
37
37
|
])
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { EntityCacheAdapter, EntityConfiguration, CacheLoadResult } from '@expo/entity';
|
|
2
|
-
import { IRedis } from './GenericRedisCacher';
|
|
3
|
-
export interface RedisCacheAdapterContext {
|
|
4
|
-
/**
|
|
5
|
-
* Instance of ioredis.Redis
|
|
6
|
-
*/
|
|
7
|
-
redisClient: IRedis;
|
|
8
|
-
/**
|
|
9
|
-
* Create a key string for key parts (cache key prefix, versions, entity name, etc).
|
|
10
|
-
* Most commonly a simple `parts.join(':')`. See integration test for example.
|
|
11
|
-
*/
|
|
12
|
-
makeKeyFn: (...parts: string[]) => string;
|
|
13
|
-
/**
|
|
14
|
-
* Global cache version for the entity framework. Bumping this version will
|
|
15
|
-
* invalidate the cache for all entities at once.
|
|
16
|
-
*/
|
|
17
|
-
cacheKeyVersion: number;
|
|
18
|
-
/**
|
|
19
|
-
* Prefix prepended to all entity cache keys. Useful for adding a short, human-readable
|
|
20
|
-
* distintion for entity keys, e.g. `ent-`
|
|
21
|
-
*/
|
|
22
|
-
cacheKeyPrefix: string;
|
|
23
|
-
/**
|
|
24
|
-
* TTL for caching database hits. Successive entity loads within this TTL
|
|
25
|
-
* will be read from cache (unless invalidated).
|
|
26
|
-
*/
|
|
27
|
-
ttlSecondsPositive: number;
|
|
28
|
-
/**
|
|
29
|
-
* TTL for negatively caching database misses. Successive entity loads within
|
|
30
|
-
* this TTL will be assumed not present in the database (unless invalidated).
|
|
31
|
-
*/
|
|
32
|
-
ttlSecondsNegative: number;
|
|
33
|
-
}
|
|
34
|
-
export default class RedisCacheAdapter<TFields> extends EntityCacheAdapter<TFields> {
|
|
35
|
-
private readonly context;
|
|
36
|
-
private readonly genericRedisCacher;
|
|
37
|
-
constructor(entityConfiguration: EntityConfiguration<TFields>, context: RedisCacheAdapterContext);
|
|
38
|
-
loadManyAsync<N extends keyof TFields>(fieldName: N, fieldValues: readonly NonNullable<TFields[N]>[]): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>>;
|
|
39
|
-
cacheManyAsync<N extends keyof TFields>(fieldName: N, objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>): Promise<void>;
|
|
40
|
-
cacheDBMissesAsync<N extends keyof TFields>(fieldName: N, fieldValues: readonly NonNullable<TFields[N]>[]): Promise<void>;
|
|
41
|
-
invalidateManyAsync<N extends keyof TFields>(fieldName: N, fieldValues: readonly NonNullable<TFields[N]>[]): Promise<void>;
|
|
42
|
-
private makeCacheKey;
|
|
43
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const entity_1 = require("@expo/entity");
|
|
7
|
-
const invariant_1 = __importDefault(require("invariant"));
|
|
8
|
-
const GenericRedisCacher_1 = __importDefault(require("./GenericRedisCacher"));
|
|
9
|
-
class RedisCacheAdapter extends entity_1.EntityCacheAdapter {
|
|
10
|
-
constructor(entityConfiguration, context) {
|
|
11
|
-
super(entityConfiguration);
|
|
12
|
-
this.context = context;
|
|
13
|
-
this.genericRedisCacher = new GenericRedisCacher_1.default({
|
|
14
|
-
redisClient: context.redisClient,
|
|
15
|
-
ttlSecondsNegative: context.ttlSecondsNegative,
|
|
16
|
-
ttlSecondsPositive: context.ttlSecondsPositive,
|
|
17
|
-
}, entityConfiguration);
|
|
18
|
-
}
|
|
19
|
-
async loadManyAsync(fieldName, fieldValues) {
|
|
20
|
-
const redisCacheKeyToFieldValueMapping = new Map(fieldValues.map((fieldValue) => [this.makeCacheKey(fieldName, fieldValue), fieldValue]));
|
|
21
|
-
const cacheResults = await this.genericRedisCacher.loadManyAsync(Array.from(redisCacheKeyToFieldValueMapping.keys()));
|
|
22
|
-
return (0, entity_1.mapKeys)(cacheResults, (redisCacheKey) => {
|
|
23
|
-
const fieldValue = redisCacheKeyToFieldValueMapping.get(redisCacheKey);
|
|
24
|
-
(0, invariant_1.default)(fieldValue !== undefined, 'Unspecified cache key %s returned from generic Redis cacher', redisCacheKey);
|
|
25
|
-
return fieldValue;
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
async cacheManyAsync(fieldName, objectMap) {
|
|
29
|
-
await this.genericRedisCacher.cacheManyAsync((0, entity_1.mapKeys)(objectMap, (fieldValue) => this.makeCacheKey(fieldName, fieldValue)));
|
|
30
|
-
}
|
|
31
|
-
async cacheDBMissesAsync(fieldName, fieldValues) {
|
|
32
|
-
await this.genericRedisCacher.cacheDBMissesAsync(fieldValues.map((fieldValue) => this.makeCacheKey(fieldName, fieldValue)));
|
|
33
|
-
}
|
|
34
|
-
async invalidateManyAsync(fieldName, fieldValues) {
|
|
35
|
-
await this.genericRedisCacher.invalidateManyAsync(fieldValues.map((fieldValue) => this.makeCacheKey(fieldName, fieldValue)));
|
|
36
|
-
}
|
|
37
|
-
makeCacheKey(fieldName, fieldValue) {
|
|
38
|
-
const columnName = this.entityConfiguration.entityToDBFieldsKeyMapping.get(fieldName);
|
|
39
|
-
(0, invariant_1.default)(columnName, `database field mapping missing for ${String(fieldName)}`);
|
|
40
|
-
return this.context.makeKeyFn(this.context.cacheKeyPrefix, this.entityConfiguration.tableName, `v2.${this.entityConfiguration.cacheKeyVersion}`, columnName, String(fieldValue));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
exports.default = RedisCacheAdapter;
|
|
44
|
-
//# sourceMappingURL=RedisCacheAdapter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RedisCacheAdapter.js","sourceRoot":"","sources":["../src/RedisCacheAdapter.ts"],"names":[],"mappings":";;;;;AAAA,yCAAiG;AACjG,0DAAkC;AAElC,8EAAkE;AAuClE,MAAqB,iBAA2B,SAAQ,2BAA2B;IAEjF,YACE,mBAAiD,EAChC,OAAiC;QAElD,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAFV,YAAO,GAAP,OAAO,CAA0B;QAIlD,IAAI,CAAC,kBAAkB,GAAG,IAAI,4BAAkB,CAC9C;YACE,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;YAC9C,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;SAC/C,EACD,mBAAmB,CACpB,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,aAAa,CACxB,SAAY,EACZ,WAA+C;QAE/C,MAAM,gCAAgC,GAAG,IAAI,GAAG,CAC9C,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC,CACxF,CAAC;QACF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAC9D,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,IAAI,EAAE,CAAC,CACpD,CAAC;QAEF,OAAO,IAAA,gBAAO,EAAC,YAAY,EAAE,CAAC,aAAa,EAAE,EAAE;YAC7C,MAAM,UAAU,GAAG,gCAAgC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACvE,IAAA,mBAAS,EACP,UAAU,KAAK,SAAS,EACxB,6DAA6D,EAC7D,aAAa,CACd,CAAC;YACF,OAAO,UAAU,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,cAAc,CACzB,SAAY,EACZ,SAAkE;QAElE,MAAM,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAC1C,IAAA,gBAAO,EAAC,SAAS,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAC7E,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,kBAAkB,CAC7B,SAAY,EACZ,WAA+C;QAE/C,MAAM,IAAI,CAAC,kBAAkB,CAAC,kBAAkB,CAC9C,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAC1E,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAC9B,SAAY,EACZ,WAA+C;QAE/C,MAAM,IAAI,CAAC,kBAAkB,CAAC,mBAAmB,CAC/C,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAC1E,CAAC;IACJ,CAAC;IAEO,YAAY,CAClB,SAAY,EACZ,UAAmC;QAEnC,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,0BAA0B,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtF,IAAA,mBAAS,EAAC,UAAU,EAAE,sCAAsC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAC3B,IAAI,CAAC,OAAO,CAAC,cAAc,EAC3B,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAClC,MAAM,IAAI,CAAC,mBAAmB,CAAC,eAAe,EAAE,EAChD,UAAU,EACV,MAAM,CAAC,UAAU,CAAC,CACnB,CAAC;IACJ,CAAC;CACF;AAjFD,oCAiFC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RedisCacheAdapter-integration-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/RedisCacheAdapter-integration-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RedisCacheAdapter-test.js","sourceRoot":"","sources":["../../src/__tests__/RedisCacheAdapter-test.ts"],"names":[],"mappings":"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"}
|
package/src/RedisCacheAdapter.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { EntityCacheAdapter, EntityConfiguration, CacheLoadResult, mapKeys } from '@expo/entity';
|
|
2
|
-
import invariant from 'invariant';
|
|
3
|
-
|
|
4
|
-
import GenericRedisCacher, { IRedis } from './GenericRedisCacher';
|
|
5
|
-
|
|
6
|
-
export interface RedisCacheAdapterContext {
|
|
7
|
-
/**
|
|
8
|
-
* Instance of ioredis.Redis
|
|
9
|
-
*/
|
|
10
|
-
redisClient: IRedis;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Create a key string for key parts (cache key prefix, versions, entity name, etc).
|
|
14
|
-
* Most commonly a simple `parts.join(':')`. See integration test for example.
|
|
15
|
-
*/
|
|
16
|
-
makeKeyFn: (...parts: string[]) => string;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Global cache version for the entity framework. Bumping this version will
|
|
20
|
-
* invalidate the cache for all entities at once.
|
|
21
|
-
*/
|
|
22
|
-
cacheKeyVersion: number;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Prefix prepended to all entity cache keys. Useful for adding a short, human-readable
|
|
26
|
-
* distintion for entity keys, e.g. `ent-`
|
|
27
|
-
*/
|
|
28
|
-
cacheKeyPrefix: string;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* TTL for caching database hits. Successive entity loads within this TTL
|
|
32
|
-
* will be read from cache (unless invalidated).
|
|
33
|
-
*/
|
|
34
|
-
ttlSecondsPositive: number;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* TTL for negatively caching database misses. Successive entity loads within
|
|
38
|
-
* this TTL will be assumed not present in the database (unless invalidated).
|
|
39
|
-
*/
|
|
40
|
-
ttlSecondsNegative: number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default class RedisCacheAdapter<TFields> extends EntityCacheAdapter<TFields> {
|
|
44
|
-
private readonly genericRedisCacher: GenericRedisCacher<TFields>;
|
|
45
|
-
constructor(
|
|
46
|
-
entityConfiguration: EntityConfiguration<TFields>,
|
|
47
|
-
private readonly context: RedisCacheAdapterContext
|
|
48
|
-
) {
|
|
49
|
-
super(entityConfiguration);
|
|
50
|
-
|
|
51
|
-
this.genericRedisCacher = new GenericRedisCacher(
|
|
52
|
-
{
|
|
53
|
-
redisClient: context.redisClient,
|
|
54
|
-
ttlSecondsNegative: context.ttlSecondsNegative,
|
|
55
|
-
ttlSecondsPositive: context.ttlSecondsPositive,
|
|
56
|
-
},
|
|
57
|
-
entityConfiguration
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
public async loadManyAsync<N extends keyof TFields>(
|
|
62
|
-
fieldName: N,
|
|
63
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
64
|
-
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>> {
|
|
65
|
-
const redisCacheKeyToFieldValueMapping = new Map(
|
|
66
|
-
fieldValues.map((fieldValue) => [this.makeCacheKey(fieldName, fieldValue), fieldValue])
|
|
67
|
-
);
|
|
68
|
-
const cacheResults = await this.genericRedisCacher.loadManyAsync(
|
|
69
|
-
Array.from(redisCacheKeyToFieldValueMapping.keys())
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
return mapKeys(cacheResults, (redisCacheKey) => {
|
|
73
|
-
const fieldValue = redisCacheKeyToFieldValueMapping.get(redisCacheKey);
|
|
74
|
-
invariant(
|
|
75
|
-
fieldValue !== undefined,
|
|
76
|
-
'Unspecified cache key %s returned from generic Redis cacher',
|
|
77
|
-
redisCacheKey
|
|
78
|
-
);
|
|
79
|
-
return fieldValue;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public async cacheManyAsync<N extends keyof TFields>(
|
|
84
|
-
fieldName: N,
|
|
85
|
-
objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
|
|
86
|
-
): Promise<void> {
|
|
87
|
-
await this.genericRedisCacher.cacheManyAsync(
|
|
88
|
-
mapKeys(objectMap, (fieldValue) => this.makeCacheKey(fieldName, fieldValue))
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
public async cacheDBMissesAsync<N extends keyof TFields>(
|
|
93
|
-
fieldName: N,
|
|
94
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
95
|
-
): Promise<void> {
|
|
96
|
-
await this.genericRedisCacher.cacheDBMissesAsync(
|
|
97
|
-
fieldValues.map((fieldValue) => this.makeCacheKey(fieldName, fieldValue))
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public async invalidateManyAsync<N extends keyof TFields>(
|
|
102
|
-
fieldName: N,
|
|
103
|
-
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
104
|
-
): Promise<void> {
|
|
105
|
-
await this.genericRedisCacher.invalidateManyAsync(
|
|
106
|
-
fieldValues.map((fieldValue) => this.makeCacheKey(fieldName, fieldValue))
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private makeCacheKey<N extends keyof TFields>(
|
|
111
|
-
fieldName: N,
|
|
112
|
-
fieldValue: NonNullable<TFields[N]>
|
|
113
|
-
): string {
|
|
114
|
-
const columnName = this.entityConfiguration.entityToDBFieldsKeyMapping.get(fieldName);
|
|
115
|
-
invariant(columnName, `database field mapping missing for ${String(fieldName)}`);
|
|
116
|
-
return this.context.makeKeyFn(
|
|
117
|
-
this.context.cacheKeyPrefix,
|
|
118
|
-
this.entityConfiguration.tableName,
|
|
119
|
-
`v2.${this.entityConfiguration.cacheKeyVersion}`,
|
|
120
|
-
columnName,
|
|
121
|
-
String(fieldValue)
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
}
|