@expo/entity-cache-adapter-redis 0.31.1 → 0.33.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
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const entity_1 = require("@expo/entity");
|
|
7
7
|
const ts_mockito_1 = require("ts-mockito");
|
|
8
|
-
const
|
|
8
|
+
const GenericRedisCacher_1 = __importDefault(require("../GenericRedisCacher"));
|
|
9
9
|
const entityConfiguration = new entity_1.EntityConfiguration({
|
|
10
10
|
idField: 'id',
|
|
11
11
|
tableName: 'blah',
|
|
@@ -15,39 +15,43 @@ const entityConfiguration = new entity_1.EntityConfiguration({
|
|
|
15
15
|
databaseAdapterFlavor: 'postgres',
|
|
16
16
|
cacheAdapterFlavor: 'redis',
|
|
17
17
|
});
|
|
18
|
-
describe(
|
|
18
|
+
describe(GenericRedisCacher_1.default, () => {
|
|
19
19
|
describe('loadManyAsync', () => {
|
|
20
20
|
it('returns appropriate cache results', async () => {
|
|
21
21
|
const redisResults = new Map();
|
|
22
22
|
const mockRedisClient = (0, ts_mockito_1.mock)();
|
|
23
23
|
// need to have one anything() for each element of spread, in this case 3
|
|
24
|
-
(0, ts_mockito_1.when)(mockRedisClient.mget((0, ts_mockito_1.anything)(), (0, ts_mockito_1.anything)(), (0, ts_mockito_1.anything)())).thenCall(async (...keys) => keys.map((k) =>
|
|
25
|
-
const
|
|
24
|
+
(0, ts_mockito_1.when)(mockRedisClient.mget((0, ts_mockito_1.anything)(), (0, ts_mockito_1.anything)(), (0, ts_mockito_1.anything)())).thenCall(async (...keys) => keys.map((k) => redisResults.get(k) ?? null));
|
|
25
|
+
const genericCacher = new GenericRedisCacher_1.default({
|
|
26
26
|
redisClient: (0, ts_mockito_1.instance)(mockRedisClient),
|
|
27
27
|
makeKeyFn: (...parts) => parts.join(':'),
|
|
28
|
-
cacheKeyVersion: 1,
|
|
29
28
|
cacheKeyPrefix: 'hello-',
|
|
30
29
|
ttlSecondsPositive: 1,
|
|
31
30
|
ttlSecondsNegative: 2,
|
|
31
|
+
}, entityConfiguration);
|
|
32
|
+
const cacheKeyWat = genericCacher['makeCacheKey']('id', 'wat');
|
|
33
|
+
const cacheKeyWho = genericCacher['makeCacheKey']('id', 'who');
|
|
34
|
+
const cacheKeyWhy = genericCacher['makeCacheKey']('id', 'why');
|
|
35
|
+
redisResults.set(cacheKeyWat, JSON.stringify({ id: 'wat' }));
|
|
36
|
+
redisResults.set(cacheKeyWho, '');
|
|
37
|
+
const results = await genericCacher.loadManyAsync([cacheKeyWat, cacheKeyWho, cacheKeyWhy]);
|
|
38
|
+
expect(results.get(cacheKeyWat)).toMatchObject({
|
|
39
|
+
status: entity_1.CacheStatus.HIT,
|
|
40
|
+
item: { id: 'wat' },
|
|
32
41
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const results = await cacheAdapter.loadManyAsync('id', ['wat', 'who', 'why']);
|
|
36
|
-
expect(results.get('wat')).toMatchObject({ status: entity_1.CacheStatus.HIT, item: { id: 'wat' } });
|
|
37
|
-
expect(results.get('who')).toMatchObject({ status: entity_1.CacheStatus.NEGATIVE });
|
|
38
|
-
expect(results.get('why')).toMatchObject({ status: entity_1.CacheStatus.MISS });
|
|
42
|
+
expect(results.get(cacheKeyWho)).toMatchObject({ status: entity_1.CacheStatus.NEGATIVE });
|
|
43
|
+
expect(results.get(cacheKeyWhy)).toMatchObject({ status: entity_1.CacheStatus.MISS });
|
|
39
44
|
expect(results.size).toBe(3);
|
|
40
45
|
});
|
|
41
46
|
it('returns empty map when passed empty array of fieldValues', async () => {
|
|
42
|
-
const
|
|
47
|
+
const genericCacher = new GenericRedisCacher_1.default({
|
|
43
48
|
redisClient: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)()),
|
|
44
49
|
makeKeyFn: (...parts) => parts.join(':'),
|
|
45
|
-
cacheKeyVersion: 1,
|
|
46
50
|
cacheKeyPrefix: 'hello-',
|
|
47
51
|
ttlSecondsPositive: 1,
|
|
48
52
|
ttlSecondsNegative: 2,
|
|
49
|
-
});
|
|
50
|
-
const results = await
|
|
53
|
+
}, entityConfiguration);
|
|
54
|
+
const results = await genericCacher.loadManyAsync([]);
|
|
51
55
|
expect(results).toEqual(new Map());
|
|
52
56
|
});
|
|
53
57
|
});
|
|
@@ -63,16 +67,15 @@ describe(RedisCacheAdapter_1.default, () => {
|
|
|
63
67
|
const pipeline = (0, ts_mockito_1.instance)(mockPipeline);
|
|
64
68
|
const mockRedisClient = (0, ts_mockito_1.mock)();
|
|
65
69
|
(0, ts_mockito_1.when)(mockRedisClient.multi()).thenReturn(pipeline);
|
|
66
|
-
const
|
|
70
|
+
const genericCacher = new GenericRedisCacher_1.default({
|
|
67
71
|
redisClient: (0, ts_mockito_1.instance)(mockRedisClient),
|
|
68
72
|
makeKeyFn: (...parts) => parts.join(':'),
|
|
69
|
-
cacheKeyVersion: 1,
|
|
70
73
|
cacheKeyPrefix: 'hello-',
|
|
71
74
|
ttlSecondsPositive: 1,
|
|
72
75
|
ttlSecondsNegative: 2,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
}, entityConfiguration);
|
|
77
|
+
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
78
|
+
await genericCacher.cacheManyAsync(new Map([[cacheKey, { id: 'wat' }]]));
|
|
76
79
|
expect(redisResults.get(cacheKey)).toMatchObject({
|
|
77
80
|
value: JSON.stringify({ id: 'wat' }),
|
|
78
81
|
code: 'EX',
|
|
@@ -92,16 +95,15 @@ describe(RedisCacheAdapter_1.default, () => {
|
|
|
92
95
|
const pipeline = (0, ts_mockito_1.instance)(mockPipeline);
|
|
93
96
|
const mockRedisClient = (0, ts_mockito_1.mock)();
|
|
94
97
|
(0, ts_mockito_1.when)(mockRedisClient.multi()).thenReturn(pipeline);
|
|
95
|
-
const
|
|
98
|
+
const genericCacher = new GenericRedisCacher_1.default({
|
|
96
99
|
redisClient: (0, ts_mockito_1.instance)(mockRedisClient),
|
|
97
100
|
makeKeyFn: (...parts) => parts.join(':'),
|
|
98
|
-
cacheKeyVersion: 1,
|
|
99
101
|
cacheKeyPrefix: 'hello-',
|
|
100
102
|
ttlSecondsPositive: 1,
|
|
101
103
|
ttlSecondsNegative: 2,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
}, entityConfiguration);
|
|
105
|
+
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
106
|
+
await genericCacher.cacheDBMissesAsync([cacheKey]);
|
|
105
107
|
expect(redisResults.get(cacheKey)).toMatchObject({
|
|
106
108
|
value: '',
|
|
107
109
|
code: 'EX',
|
|
@@ -113,29 +115,27 @@ describe(RedisCacheAdapter_1.default, () => {
|
|
|
113
115
|
it('invalidates correctly', async () => {
|
|
114
116
|
const mockRedisClient = (0, ts_mockito_1.mock)();
|
|
115
117
|
(0, ts_mockito_1.when)(mockRedisClient.del()).thenResolve(1);
|
|
116
|
-
const
|
|
118
|
+
const genericCacher = new GenericRedisCacher_1.default({
|
|
117
119
|
redisClient: (0, ts_mockito_1.instance)(mockRedisClient),
|
|
118
120
|
makeKeyFn: (...parts) => parts.join(':'),
|
|
119
|
-
cacheKeyVersion: 1,
|
|
120
121
|
cacheKeyPrefix: 'hello-',
|
|
121
122
|
ttlSecondsPositive: 1,
|
|
122
123
|
ttlSecondsNegative: 2,
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
}, entityConfiguration);
|
|
125
|
+
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
126
|
+
await genericCacher.invalidateManyAsync([cacheKey]);
|
|
126
127
|
(0, ts_mockito_1.verify)(mockRedisClient.del(cacheKey)).once();
|
|
127
128
|
});
|
|
128
129
|
it('returns when passed empty array of fieldValues', async () => {
|
|
129
|
-
const
|
|
130
|
+
const genericCacher = new GenericRedisCacher_1.default({
|
|
130
131
|
redisClient: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)()),
|
|
131
132
|
makeKeyFn: (...parts) => parts.join(':'),
|
|
132
|
-
cacheKeyVersion: 1,
|
|
133
133
|
cacheKeyPrefix: 'hello-',
|
|
134
134
|
ttlSecondsPositive: 1,
|
|
135
135
|
ttlSecondsNegative: 2,
|
|
136
|
-
});
|
|
137
|
-
await
|
|
136
|
+
}, entityConfiguration);
|
|
137
|
+
await genericCacher.invalidateManyAsync([]);
|
|
138
138
|
});
|
|
139
139
|
});
|
|
140
140
|
});
|
|
141
|
-
//# sourceMappingURL=
|
|
141
|
+
//# sourceMappingURL=GenericRedisCacher-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenericRedisCacher-test.js","sourceRoot":"","sources":["../../src/__tests__/GenericRedisCacher-test.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* @packageDocumentation
|
|
3
3
|
* @module @expo/entity-cache-adapter-redis
|
|
4
4
|
*/
|
|
5
|
-
export { default as RedisCacheAdapter } from './RedisCacheAdapter';
|
|
6
|
-
export * from './RedisCacheAdapter';
|
|
7
5
|
export { default as RedisCacheAdapterProvider } from './RedisCacheAdapterProvider';
|
|
8
6
|
export * from './RedisCommon';
|
|
9
7
|
export { default as GenericRedisCacher } from './GenericRedisCacher';
|
package/build/index.js
CHANGED
|
@@ -22,10 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.GenericRedisCacher = exports.RedisCacheAdapterProvider =
|
|
26
|
-
var RedisCacheAdapter_1 = require("./RedisCacheAdapter");
|
|
27
|
-
Object.defineProperty(exports, "RedisCacheAdapter", { enumerable: true, get: function () { return __importDefault(RedisCacheAdapter_1).default; } });
|
|
28
|
-
__exportStar(require("./RedisCacheAdapter"), exports);
|
|
25
|
+
exports.GenericRedisCacher = exports.RedisCacheAdapterProvider = void 0;
|
|
29
26
|
var RedisCacheAdapterProvider_1 = require("./RedisCacheAdapterProvider");
|
|
30
27
|
Object.defineProperty(exports, "RedisCacheAdapterProvider", { enumerable: true, get: function () { return __importDefault(RedisCacheAdapterProvider_1).default; } });
|
|
31
28
|
__exportStar(require("./RedisCommon"), exports);
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,iCAAiC;AACjC;;;GAGG;;;;;;;;;;;;;;;;;;;;AAEH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,iCAAiC;AACjC;;;GAGG;;;;;;;;;;;;;;;;;;;;AAEH,yEAAmF;AAA1E,uJAAA,OAAO,OAA6B;AAC7C,gDAA8B;AAC9B,2DAAqE;AAA5D,yIAAA,OAAO,OAAsB;AACtC,uDAAqC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { AlwaysAllowPrivacyPolicyRule, EntityPrivacyPolicy, ViewerContext, EntityConfiguration, EntityCompanionDefinition, Entity } from '@expo/entity';
|
|
2
|
-
export
|
|
2
|
+
export type RedisTestEntityFields = {
|
|
3
3
|
id: string;
|
|
4
4
|
name: string;
|
|
5
5
|
dateField: Date | null;
|
|
6
6
|
};
|
|
7
7
|
export default class RedisTestEntity extends Entity<RedisTestEntityFields, string, ViewerContext> {
|
|
8
|
-
static
|
|
8
|
+
static defineCompanionDefinition(): EntityCompanionDefinition<RedisTestEntityFields, string, ViewerContext, RedisTestEntity, RedisTestEntityPrivacyPolicy>;
|
|
9
9
|
}
|
|
10
10
|
export declare class RedisTestEntityPrivacyPolicy extends EntityPrivacyPolicy<RedisTestEntityFields, string, ViewerContext, RedisTestEntity> {
|
|
11
11
|
protected readonly createRules: AlwaysAllowPrivacyPolicyRule<RedisTestEntityFields, string, ViewerContext, RedisTestEntity, keyof RedisTestEntityFields>[];
|
|
@@ -3,8 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.redisTestEntityConfiguration = exports.RedisTestEntityPrivacyPolicy = void 0;
|
|
4
4
|
const entity_1 = require("@expo/entity");
|
|
5
5
|
class RedisTestEntity extends entity_1.Entity {
|
|
6
|
-
static
|
|
7
|
-
return
|
|
6
|
+
static defineCompanionDefinition() {
|
|
7
|
+
return {
|
|
8
|
+
entityClass: RedisTestEntity,
|
|
9
|
+
entityConfiguration: exports.redisTestEntityConfiguration,
|
|
10
|
+
privacyPolicyClass: RedisTestEntityPrivacyPolicy,
|
|
11
|
+
};
|
|
8
12
|
}
|
|
9
13
|
}
|
|
10
14
|
exports.default = RedisTestEntity;
|
|
@@ -45,9 +49,4 @@ exports.redisTestEntityConfiguration = new entity_1.EntityConfiguration({
|
|
|
45
49
|
databaseAdapterFlavor: 'postgres',
|
|
46
50
|
cacheAdapterFlavor: 'redis',
|
|
47
51
|
});
|
|
48
|
-
const redisTestEntityCompanionDefinition = new entity_1.EntityCompanionDefinition({
|
|
49
|
-
entityClass: RedisTestEntity,
|
|
50
|
-
entityConfiguration: exports.redisTestEntityConfiguration,
|
|
51
|
-
privacyPolicyClass: RedisTestEntityPrivacyPolicy,
|
|
52
|
-
});
|
|
53
52
|
//# sourceMappingURL=RedisTestEntity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedisTestEntity.js","sourceRoot":"","sources":["../../src/testfixtures/RedisTestEntity.ts"],"names":[],"mappings":";;;AAAA,yCAUsB;AAQtB,MAAqB,eAAgB,SAAQ,eAAoD;IAC/F,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"RedisTestEntity.js","sourceRoot":"","sources":["../../src/testfixtures/RedisTestEntity.ts"],"names":[],"mappings":";;;AAAA,yCAUsB;AAQtB,MAAqB,eAAgB,SAAQ,eAAoD;IAC/F,MAAM,CAAC,yBAAyB;QAO9B,OAAO;YACL,WAAW,EAAE,eAAe;YAC5B,mBAAmB,EAAE,oCAA4B;YACjD,kBAAkB,EAAE,4BAA4B;SACjD,CAAC;IACJ,CAAC;CACF;AAdD,kCAcC;AAED,MAAa,4BAA6B,SAAQ,4BAKjD;IALD;;QAM8B,gBAAW,GAAG;YACxC,IAAI,qCAA4B,EAK7B;SACJ,CAAC;QAC0B,cAAS,GAAG;YACtC,IAAI,qCAA4B,EAK7B;SACJ,CAAC;QAC0B,gBAAW,GAAG;YACxC,IAAI,qCAA4B,EAK7B;SACJ,CAAC;QAC0B,gBAAW,GAAG;YACxC,IAAI,qCAA4B,EAK7B;SACJ,CAAC;IACJ,CAAC;CAAA;AAtCD,oEAsCC;AAEY,QAAA,4BAA4B,GAAG,IAAI,4BAAmB,CAAwB;IACzF,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,qBAAqB;IAChC,MAAM,EAAE;QACN,EAAE,EAAE,IAAI,kBAAS,CAAC;YAChB,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE,IAAI;SACZ,CAAC;QACF,IAAI,EAAE,IAAI,oBAAW,CAAC;YACpB,UAAU,EAAE,MAAM;YAClB,KAAK,EAAE,IAAI;SACZ,CAAC;QACF,SAAS,EAAE,IAAI,kBAAS,CAAC;YACvB,UAAU,EAAE,YAAY;SACzB,CAAC;KACH;IACD,qBAAqB,EAAE,UAAU;IACjC,kBAAkB,EAAE,OAAO;CAC5B,CAAC,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { IEntityMetricsAdapter, EntityCompanionProvider } from '@expo/entity';
|
|
2
|
-
import {
|
|
3
|
-
export declare const createRedisIntegrationTestEntityCompanionProvider: (
|
|
2
|
+
import { GenericRedisCacheContext } from '../GenericRedisCacher';
|
|
3
|
+
export declare const createRedisIntegrationTestEntityCompanionProvider: (genericRedisCacheContext: GenericRedisCacheContext, metricsAdapter?: IEntityMetricsAdapter) => EntityCompanionProvider;
|
|
@@ -8,7 +8,7 @@ const entity_1 = require("@expo/entity");
|
|
|
8
8
|
const RedisCacheAdapterProvider_1 = __importDefault(require("../RedisCacheAdapterProvider"));
|
|
9
9
|
// share across all in calls in test to simulate postgres
|
|
10
10
|
const adapterProvider = new entity_1.StubDatabaseAdapterProvider();
|
|
11
|
-
const createRedisIntegrationTestEntityCompanionProvider = (
|
|
11
|
+
const createRedisIntegrationTestEntityCompanionProvider = (genericRedisCacheContext, metricsAdapter = new entity_1.NoOpEntityMetricsAdapter()) => {
|
|
12
12
|
return new entity_1.EntityCompanionProvider(metricsAdapter, new Map([
|
|
13
13
|
[
|
|
14
14
|
'postgres',
|
|
@@ -21,7 +21,7 @@ const createRedisIntegrationTestEntityCompanionProvider = (redisCacheAdapterCont
|
|
|
21
21
|
[
|
|
22
22
|
'redis',
|
|
23
23
|
{
|
|
24
|
-
cacheAdapterProvider: new RedisCacheAdapterProvider_1.default(
|
|
24
|
+
cacheAdapterProvider: new RedisCacheAdapterProvider_1.default(genericRedisCacheContext),
|
|
25
25
|
},
|
|
26
26
|
],
|
|
27
27
|
]));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/entity-cache-adapter-redis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Redis cache adapter for @expo/entity",
|
|
5
5
|
"files": [
|
|
6
6
|
"build",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"barrelsby": "barrelsby --directory src --location top --exclude tests__ --singleQuotes --exportDefault --delete"
|
|
20
20
|
},
|
|
21
21
|
"engines": {
|
|
22
|
-
"node": ">=
|
|
22
|
+
"node": ">=16"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"entity"
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"ioredis": ">=5"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@expo/entity": "^0.
|
|
34
|
+
"@expo/entity": "^0.33.0",
|
|
35
35
|
"ioredis": "^5.2.5"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "659e08386f2c5e33e9ac4c670fd832a62a2b6382"
|
|
38
38
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
transformFieldsToCacheObject,
|
|
7
7
|
IEntityGenericCacher,
|
|
8
8
|
} from '@expo/entity';
|
|
9
|
+
import invariant from 'invariant';
|
|
9
10
|
|
|
10
11
|
import { redisTransformerMap } from './RedisCommon';
|
|
11
12
|
import wrapNativeRedisCallAsync from './errors/wrapNativeRedisCallAsync';
|
|
@@ -31,6 +32,18 @@ export interface GenericRedisCacheContext {
|
|
|
31
32
|
*/
|
|
32
33
|
redisClient: IRedis;
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Create a key string for key parts (cache key prefix, versions, entity name, etc).
|
|
37
|
+
* Most commonly a simple `parts.join(':')`. See integration test for example.
|
|
38
|
+
*/
|
|
39
|
+
makeKeyFn: (...parts: string[]) => string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Prefix prepended to all entity cache keys. Useful for adding a short, human-readable
|
|
43
|
+
* distintion for entity keys, e.g. `ent-`
|
|
44
|
+
*/
|
|
45
|
+
cacheKeyPrefix: string;
|
|
46
|
+
|
|
34
47
|
/**
|
|
35
48
|
* TTL for caching database hits. Successive entity loads within this TTL
|
|
36
49
|
* will be read from cache (unless invalidated).
|
|
@@ -131,4 +144,19 @@ export default class GenericRedisCacher<TFields> implements IEntityGenericCacher
|
|
|
131
144
|
|
|
132
145
|
await wrapNativeRedisCallAsync(() => this.context.redisClient.del(...keys));
|
|
133
146
|
}
|
|
147
|
+
|
|
148
|
+
public makeCacheKey<N extends keyof TFields>(
|
|
149
|
+
fieldName: N,
|
|
150
|
+
fieldValue: NonNullable<TFields[N]>
|
|
151
|
+
): string {
|
|
152
|
+
const columnName = this.entityConfiguration.entityToDBFieldsKeyMapping.get(fieldName);
|
|
153
|
+
invariant(columnName, `database field mapping missing for ${String(fieldName)}`);
|
|
154
|
+
return this.context.makeKeyFn(
|
|
155
|
+
this.context.cacheKeyPrefix,
|
|
156
|
+
this.entityConfiguration.tableName,
|
|
157
|
+
`v2.${this.entityConfiguration.cacheKeyVersion}`,
|
|
158
|
+
columnName,
|
|
159
|
+
String(fieldValue)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
134
162
|
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
IEntityCacheAdapterProvider,
|
|
3
|
+
EntityConfiguration,
|
|
4
|
+
IEntityCacheAdapter,
|
|
5
|
+
GenericEntityCacheAdapter,
|
|
6
|
+
} from '@expo/entity';
|
|
2
7
|
|
|
3
|
-
import
|
|
8
|
+
import GenericRedisCacher, { GenericRedisCacheContext } from './GenericRedisCacher';
|
|
4
9
|
|
|
5
10
|
export default class RedisCacheAdapterProvider implements IEntityCacheAdapterProvider {
|
|
6
|
-
constructor(private readonly context:
|
|
11
|
+
constructor(private readonly context: GenericRedisCacheContext) {}
|
|
7
12
|
|
|
8
13
|
getCacheAdapter<TFields>(
|
|
9
14
|
entityConfiguration: EntityConfiguration<TFields>
|
|
10
|
-
):
|
|
11
|
-
return new
|
|
15
|
+
): IEntityCacheAdapter<TFields> {
|
|
16
|
+
return new GenericEntityCacheAdapter(new GenericRedisCacher(this.context, entityConfiguration));
|
|
12
17
|
}
|
|
13
18
|
}
|
|
@@ -6,8 +6,11 @@ import nullthrows from 'nullthrows';
|
|
|
6
6
|
import { URL } from 'url';
|
|
7
7
|
import { v4 as uuidv4 } from 'uuid';
|
|
8
8
|
|
|
9
|
-
import
|
|
10
|
-
|
|
9
|
+
import GenericRedisCacher, {
|
|
10
|
+
IRedis,
|
|
11
|
+
IRedisTransaction,
|
|
12
|
+
GenericRedisCacheContext,
|
|
13
|
+
} from '../GenericRedisCacher';
|
|
11
14
|
import RedisTestEntity from '../testfixtures/RedisTestEntity';
|
|
12
15
|
import { createRedisIntegrationTestEntityCompanionProvider } from '../testfixtures/createRedisIntegrationTestEntityCompanionProvider';
|
|
13
16
|
|
|
@@ -54,14 +57,14 @@ class BatchedRedis implements IRedis {
|
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
describe(
|
|
60
|
+
describe(GenericRedisCacher, () => {
|
|
58
61
|
const redis = new Redis(new URL(process.env['REDIS_URL']!).toString());
|
|
59
62
|
const redisClient = new BatchedRedis(redis);
|
|
60
63
|
|
|
61
|
-
let
|
|
64
|
+
let genericRedisCacheContext: GenericRedisCacheContext;
|
|
62
65
|
|
|
63
66
|
beforeAll(() => {
|
|
64
|
-
|
|
67
|
+
genericRedisCacheContext = {
|
|
65
68
|
redisClient,
|
|
66
69
|
makeKeyFn(...parts: string[]): string {
|
|
67
70
|
const delimiter = ':';
|
|
@@ -71,7 +74,6 @@ describe(RedisCacheAdapter, () => {
|
|
|
71
74
|
return escapedParts.join(delimiter);
|
|
72
75
|
},
|
|
73
76
|
cacheKeyPrefix: 'test-',
|
|
74
|
-
cacheKeyVersion: 1,
|
|
75
77
|
ttlSecondsPositive: 86400, // 1 day
|
|
76
78
|
ttlSecondsNegative: 600, // 10 minutes
|
|
77
79
|
};
|
|
@@ -88,16 +90,16 @@ describe(RedisCacheAdapter, () => {
|
|
|
88
90
|
it('has correct caching behavior', async () => {
|
|
89
91
|
// simulate two requests
|
|
90
92
|
const viewerContext = new ViewerContext(
|
|
91
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
93
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
92
94
|
);
|
|
93
95
|
|
|
94
96
|
const mgetSpy = jest.spyOn(redis, 'mget');
|
|
95
97
|
|
|
96
|
-
const
|
|
97
|
-
RedisTestEntity
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const cacheKeyMaker =
|
|
98
|
+
const genericCacher =
|
|
99
|
+
viewerContext.entityCompanionProvider.getCompanionForEntity(RedisTestEntity)[
|
|
100
|
+
'tableDataCoordinator'
|
|
101
|
+
]['cacheAdapter']['genericCacher'];
|
|
102
|
+
const cacheKeyMaker = genericCacher['makeCacheKey'].bind(genericCacher);
|
|
101
103
|
|
|
102
104
|
const entity1Created = await RedisTestEntity.creator(viewerContext)
|
|
103
105
|
.setField('name', 'blah')
|
|
@@ -106,13 +108,13 @@ describe(RedisCacheAdapter, () => {
|
|
|
106
108
|
// loading an entity should put it in cache. load by multiple requests and multiple fields in same tick to ensure batch works
|
|
107
109
|
mgetSpy.mockClear();
|
|
108
110
|
const viewerContext1 = new ViewerContext(
|
|
109
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
111
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
110
112
|
);
|
|
111
113
|
const viewerContext2 = new ViewerContext(
|
|
112
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
114
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
113
115
|
);
|
|
114
116
|
const viewerContext3 = new ViewerContext(
|
|
115
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
117
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
116
118
|
);
|
|
117
119
|
const [entity1, entity2, entity3] = await Promise.all([
|
|
118
120
|
RedisTestEntity.loader(viewerContext1).enforcing().loadByIDAsync(entity1Created.getID()),
|
|
@@ -4,19 +4,18 @@ import Redis from 'ioredis';
|
|
|
4
4
|
import { URL } from 'url';
|
|
5
5
|
import { v4 as uuidv4 } from 'uuid';
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import GenericRedisCacher, { GenericRedisCacheContext } from '../GenericRedisCacher';
|
|
8
8
|
import RedisTestEntity from '../testfixtures/RedisTestEntity';
|
|
9
9
|
import { createRedisIntegrationTestEntityCompanionProvider } from '../testfixtures/createRedisIntegrationTestEntityCompanionProvider';
|
|
10
10
|
|
|
11
11
|
class TestViewerContext extends ViewerContext {}
|
|
12
12
|
|
|
13
|
-
describe(
|
|
14
|
-
|
|
15
|
-
let redisCacheAdapterContext: RedisCacheAdapterContext;
|
|
13
|
+
describe(GenericRedisCacher, () => {
|
|
14
|
+
let genericRedisCacheContext: GenericRedisCacheContext;
|
|
16
15
|
|
|
17
16
|
beforeAll(() => {
|
|
18
|
-
|
|
19
|
-
redisClient,
|
|
17
|
+
genericRedisCacheContext = {
|
|
18
|
+
redisClient: new Redis(new URL(process.env['REDIS_URL']!).toString()),
|
|
20
19
|
makeKeyFn(...parts: string[]): string {
|
|
21
20
|
const delimiter = ':';
|
|
22
21
|
const escapedParts = parts.map((part) =>
|
|
@@ -25,28 +24,27 @@ describe(RedisCacheAdapter, () => {
|
|
|
25
24
|
return escapedParts.join(delimiter);
|
|
26
25
|
},
|
|
27
26
|
cacheKeyPrefix: 'test-',
|
|
28
|
-
cacheKeyVersion: 1,
|
|
29
27
|
ttlSecondsPositive: 86400, // 1 day
|
|
30
28
|
ttlSecondsNegative: 600, // 10 minutes
|
|
31
29
|
};
|
|
32
30
|
});
|
|
33
31
|
|
|
34
32
|
beforeEach(async () => {
|
|
35
|
-
await redisClient.flushdb();
|
|
33
|
+
await (genericRedisCacheContext.redisClient as Redis).flushdb();
|
|
36
34
|
});
|
|
37
35
|
afterAll(async () => {
|
|
38
|
-
redisClient.disconnect();
|
|
36
|
+
(genericRedisCacheContext.redisClient as Redis).disconnect();
|
|
39
37
|
});
|
|
40
38
|
|
|
41
39
|
it('has correct caching behavior', async () => {
|
|
42
40
|
const viewerContext = new TestViewerContext(
|
|
43
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
41
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
44
42
|
);
|
|
45
|
-
const
|
|
46
|
-
RedisTestEntity
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const cacheKeyMaker =
|
|
43
|
+
const genericCacher =
|
|
44
|
+
viewerContext.entityCompanionProvider.getCompanionForEntity(RedisTestEntity)[
|
|
45
|
+
'tableDataCoordinator'
|
|
46
|
+
]['cacheAdapter']['genericCacher'];
|
|
47
|
+
const cacheKeyMaker = genericCacher['makeCacheKey'].bind(genericCacher);
|
|
50
48
|
|
|
51
49
|
const entity1Created = await RedisTestEntity.creator(viewerContext)
|
|
52
50
|
.setField('name', 'blah')
|
|
@@ -57,7 +55,9 @@ describe(RedisCacheAdapter, () => {
|
|
|
57
55
|
.enforcing()
|
|
58
56
|
.loadByIDAsync(entity1Created.getID());
|
|
59
57
|
|
|
60
|
-
const cachedJSON = await redisClient.get(
|
|
58
|
+
const cachedJSON = await (genericRedisCacheContext.redisClient as Redis).get(
|
|
59
|
+
cacheKeyMaker('id', entity1.getID())
|
|
60
|
+
);
|
|
61
61
|
const cachedValue = JSON.parse(cachedJSON!);
|
|
62
62
|
expect(cachedValue).toMatchObject({
|
|
63
63
|
id: entity1.getID(),
|
|
@@ -72,7 +72,9 @@ describe(RedisCacheAdapter, () => {
|
|
|
72
72
|
);
|
|
73
73
|
expect(entityNonExistentResult.ok).toBe(false);
|
|
74
74
|
|
|
75
|
-
const nonExistentCachedValue = await redisClient.get(
|
|
75
|
+
const nonExistentCachedValue = await (genericRedisCacheContext.redisClient as Redis).get(
|
|
76
|
+
cacheKeyMaker('id', nonExistentId)
|
|
77
|
+
);
|
|
76
78
|
expect(nonExistentCachedValue).toEqual('');
|
|
77
79
|
|
|
78
80
|
// load again through entities framework to ensure it reads negative result
|
|
@@ -83,13 +85,15 @@ describe(RedisCacheAdapter, () => {
|
|
|
83
85
|
|
|
84
86
|
// invalidate from cache to ensure it invalidates correctly
|
|
85
87
|
await RedisTestEntity.loader(viewerContext).invalidateFieldsAsync(entity1.getAllFields());
|
|
86
|
-
const cachedValueNull = await redisClient.get(
|
|
88
|
+
const cachedValueNull = await (genericRedisCacheContext.redisClient as Redis).get(
|
|
89
|
+
cacheKeyMaker('id', entity1.getID())
|
|
90
|
+
);
|
|
87
91
|
expect(cachedValueNull).toBe(null);
|
|
88
92
|
});
|
|
89
93
|
|
|
90
94
|
it('caches and restores date fields', async () => {
|
|
91
95
|
const viewerContext = new TestViewerContext(
|
|
92
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
96
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
93
97
|
);
|
|
94
98
|
const date = new Date();
|
|
95
99
|
const entity1 = await enforceAsyncResult(
|
|
@@ -104,7 +108,7 @@ describe(RedisCacheAdapter, () => {
|
|
|
104
108
|
|
|
105
109
|
// simulate new request
|
|
106
110
|
const vc2 = new TestViewerContext(
|
|
107
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
111
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
108
112
|
);
|
|
109
113
|
const entity3 = await RedisTestEntity.loader(vc2).enforcing().loadByIDAsync(entity1.getID());
|
|
110
114
|
expect(entity3.getField('dateField')).toEqual(date);
|
|
@@ -112,7 +116,7 @@ describe(RedisCacheAdapter, () => {
|
|
|
112
116
|
|
|
113
117
|
it('caches and restores empty string field keys', async () => {
|
|
114
118
|
const viewerContext = new TestViewerContext(
|
|
115
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
119
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
116
120
|
);
|
|
117
121
|
const entity1 = await enforceAsyncResult(
|
|
118
122
|
RedisTestEntity.creator(viewerContext).setField('name', '').createAsync()
|
|
@@ -124,7 +128,7 @@ describe(RedisCacheAdapter, () => {
|
|
|
124
128
|
|
|
125
129
|
// simulate new request
|
|
126
130
|
const vc2 = new TestViewerContext(
|
|
127
|
-
createRedisIntegrationTestEntityCompanionProvider(
|
|
131
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
128
132
|
);
|
|
129
133
|
const entity3 = await RedisTestEntity.loader(vc2)
|
|
130
134
|
.enforcing()
|