@expo/entity-cache-adapter-redis 0.35.0 → 0.36.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/build/GenericRedisCacher.d.ts +1 -1
- package/build/GenericRedisCacher.js +2 -0
- package/build/GenericRedisCacher.js.map +1 -1
- package/build/RedisCacheAdapterProvider.d.ts +1 -1
- package/build/RedisCacheAdapterProvider.js +1 -0
- package/build/RedisCacheAdapterProvider.js.map +1 -1
- package/build/__integration-tests__/BatchedRedisCacheAdapter-integration-test.js +14 -7
- package/build/__integration-tests__/BatchedRedisCacheAdapter-integration-test.js.map +1 -1
- package/build/__integration-tests__/GenericRedisCacher-full-integration-test.js +10 -4
- package/build/__integration-tests__/GenericRedisCacher-full-integration-test.js.map +1 -1
- package/build/__integration-tests__/GenericRedisCacher-integration-test.js +1 -1
- package/build/__integration-tests__/GenericRedisCacher-integration-test.js.map +1 -1
- package/build/__integration-tests__/errors-test.js +1 -1
- package/build/__integration-tests__/errors-test.js.map +1 -1
- package/build/errors/__tests__/wrapNativeRedisCallAsync-test.js.map +1 -1
- package/build/errors/wrapNativeRedisCallAsync.js.map +1 -1
- package/build/testfixtures/RedisTestEntity.js +12 -15
- package/build/testfixtures/RedisTestEntity.js.map +1 -1
- package/package.json +3 -3
- package/src/GenericRedisCacher.ts +12 -10
- package/src/RedisCacheAdapterProvider.ts +2 -2
- package/src/__integration-tests__/BatchedRedisCacheAdapter-integration-test.ts +16 -14
- package/src/__integration-tests__/GenericRedisCacher-full-integration-test.ts +20 -18
- package/src/__integration-tests__/GenericRedisCacher-integration-test.ts +6 -6
- package/src/__integration-tests__/errors-test.ts +3 -3
- package/src/__tests__/GenericRedisCacher-test.ts +9 -9
- package/src/testfixtures/createRedisIntegrationTestEntityCompanionProvider.ts +2 -2
|
@@ -34,7 +34,7 @@ export interface GenericRedisCacheContext {
|
|
|
34
34
|
*/
|
|
35
35
|
ttlSecondsNegative: number;
|
|
36
36
|
}
|
|
37
|
-
export default class GenericRedisCacher<TFields
|
|
37
|
+
export default class GenericRedisCacher<TFields extends Record<string, any>> implements IEntityGenericCacher<TFields> {
|
|
38
38
|
private readonly context;
|
|
39
39
|
private readonly entityConfiguration;
|
|
40
40
|
constructor(context: GenericRedisCacheContext, entityConfiguration: EntityConfiguration<TFields>);
|
|
@@ -11,6 +11,8 @@ const wrapNativeRedisCallAsync_1 = __importDefault(require("./errors/wrapNativeR
|
|
|
11
11
|
// The sentinel value is distinct from any (positively) cached value.
|
|
12
12
|
const DOES_NOT_EXIST_REDIS = '';
|
|
13
13
|
class GenericRedisCacher {
|
|
14
|
+
context;
|
|
15
|
+
entityConfiguration;
|
|
14
16
|
constructor(context, entityConfiguration) {
|
|
15
17
|
this.context = context;
|
|
16
18
|
this.entityConfiguration = entityConfiguration;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenericRedisCacher.js","sourceRoot":"","sources":["../src/GenericRedisCacher.ts"],"names":[],"mappings":";;;;;AAAA,yCAOsB;AACtB,0DAAkC;AAElC,+CAAoD;AACpD,iGAAyE;AAEzE,wEAAwE;AACxE,qEAAqE;AACrE,MAAM,oBAAoB,GAAG,EAAE,CAAC;AA4ChC,MAAqB,kBAAkB;
|
|
1
|
+
{"version":3,"file":"GenericRedisCacher.js","sourceRoot":"","sources":["../src/GenericRedisCacher.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,5 @@ import { GenericRedisCacheContext } from './GenericRedisCacher';
|
|
|
3
3
|
export default class RedisCacheAdapterProvider implements IEntityCacheAdapterProvider {
|
|
4
4
|
private readonly context;
|
|
5
5
|
constructor(context: GenericRedisCacheContext);
|
|
6
|
-
getCacheAdapter<TFields
|
|
6
|
+
getCacheAdapter<TFields extends Record<string, any>>(entityConfiguration: EntityConfiguration<TFields>): IEntityCacheAdapter<TFields>;
|
|
7
7
|
}
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const entity_1 = require("@expo/entity");
|
|
7
7
|
const GenericRedisCacher_1 = __importDefault(require("./GenericRedisCacher"));
|
|
8
8
|
class RedisCacheAdapterProvider {
|
|
9
|
+
context;
|
|
9
10
|
constructor(context) {
|
|
10
11
|
this.context = context;
|
|
11
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedisCacheAdapterProvider.js","sourceRoot":"","sources":["../src/RedisCacheAdapterProvider.ts"],"names":[],"mappings":";;;;;AAAA,yCAKsB;AAEtB,8EAAoF;AAEpF,MAAqB,yBAAyB;
|
|
1
|
+
{"version":3,"file":"RedisCacheAdapterProvider.js","sourceRoot":"","sources":["../src/RedisCacheAdapterProvider.ts"],"names":[],"mappings":";;;;;AAAA,yCAKsB;AAEtB,8EAAoF;AAEpF,MAAqB,yBAAyB;IACf;IAA7B,YAA6B,OAAiC;QAAjC,YAAO,GAAP,OAAO,CAA0B;IAAG,CAAC;IAElE,eAAe,CACb,mBAAiD;QAEjD,OAAO,IAAI,kCAAyB,CAAC,IAAI,4BAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAClG,CAAC;CACF;AARD,4CAQC"}
|
|
@@ -14,11 +14,12 @@ const GenericRedisCacher_1 = __importDefault(require("../GenericRedisCacher"));
|
|
|
14
14
|
const RedisTestEntity_1 = __importDefault(require("../testfixtures/RedisTestEntity"));
|
|
15
15
|
const createRedisIntegrationTestEntityCompanionProvider_1 = require("../testfixtures/createRedisIntegrationTestEntityCompanionProvider");
|
|
16
16
|
class BatchedRedis {
|
|
17
|
+
redis;
|
|
18
|
+
mgetBatcher = new batcher_1.Batcher(this.batchMgetAsync.bind(this), {
|
|
19
|
+
maxBatchInterval: 0,
|
|
20
|
+
});
|
|
17
21
|
constructor(redis) {
|
|
18
22
|
this.redis = redis;
|
|
19
|
-
this.mgetBatcher = new batcher_1.Batcher(this.batchMgetAsync.bind(this), {
|
|
20
|
-
maxBatchInterval: 0,
|
|
21
|
-
});
|
|
22
23
|
}
|
|
23
24
|
async batchMgetAsync(keySets) {
|
|
24
25
|
// ordered distinct keys to fetch
|
|
@@ -57,7 +58,7 @@ describe(GenericRedisCacher_1.default, () => {
|
|
|
57
58
|
return escapedParts.join(delimiter);
|
|
58
59
|
},
|
|
59
60
|
cacheKeyPrefix: 'test-',
|
|
60
|
-
ttlSecondsPositive: 86400,
|
|
61
|
+
ttlSecondsPositive: 86400, // 1 day
|
|
61
62
|
ttlSecondsNegative: 600, // 10 minutes
|
|
62
63
|
};
|
|
63
64
|
});
|
|
@@ -106,16 +107,22 @@ describe(GenericRedisCacher_1.default, () => {
|
|
|
106
107
|
await expect(redis.get(cacheKeyEntity1NameField)).resolves.toEqual(cachedJSON);
|
|
107
108
|
// simulate non existent db fetch, should write negative result ('') to cache
|
|
108
109
|
const nonExistentId = (0, uuid_1.v4)();
|
|
109
|
-
const entityNonExistentResult = await RedisTestEntity_1.default.loader(viewerContext)
|
|
110
|
+
const entityNonExistentResult = await RedisTestEntity_1.default.loader(viewerContext)
|
|
111
|
+
.withAuthorizationResults()
|
|
112
|
+
.loadByIDAsync(nonExistentId);
|
|
110
113
|
expect(entityNonExistentResult.ok).toBe(false);
|
|
111
114
|
const cacheKeyNonExistent = cacheKeyMaker('id', nonExistentId);
|
|
112
115
|
const nonExistentCachedValue = await redis.get(cacheKeyNonExistent);
|
|
113
116
|
expect(nonExistentCachedValue).toEqual('');
|
|
114
117
|
// load again through entities framework to ensure it reads negative result
|
|
115
|
-
const entityNonExistentResult2 = await RedisTestEntity_1.default.loader(viewerContext)
|
|
118
|
+
const entityNonExistentResult2 = await RedisTestEntity_1.default.loader(viewerContext)
|
|
119
|
+
.withAuthorizationResults()
|
|
120
|
+
.loadByIDAsync(nonExistentId);
|
|
116
121
|
expect(entityNonExistentResult2.ok).toBe(false);
|
|
117
122
|
// invalidate from cache to ensure it invalidates correctly in both caches
|
|
118
|
-
await RedisTestEntity_1.default.loader(viewerContext)
|
|
123
|
+
await RedisTestEntity_1.default.loader(viewerContext)
|
|
124
|
+
.utils()
|
|
125
|
+
.invalidateFieldsAsync(entity1.getAllFields());
|
|
119
126
|
await expect(redis.get(cacheKeyEntity1)).resolves.toBeNull();
|
|
120
127
|
await expect(redis.get(cacheKeyEntity1NameField)).resolves.toBeNull();
|
|
121
128
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BatchedRedisCacheAdapter-integration-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/BatchedRedisCacheAdapter-integration-test.ts"],"names":[],"mappings":";;;;;AAAA,2CAAwC;AACxC,yCAAuD;AACvD,0DAAkC;AAClC,sDAA4B;AAC5B,4DAAoC;AACpC,6BAA0B;AAC1B,+BAAoC;AAEpC,+EAI+B;AAC/B,sFAA8D;AAC9D,yIAAsI;AAEtI,MAAM,YAAY;
|
|
1
|
+
{"version":3,"file":"BatchedRedisCacheAdapter-integration-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/BatchedRedisCacheAdapter-integration-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,7 +24,7 @@ describe(GenericRedisCacher_1.default, () => {
|
|
|
24
24
|
return escapedParts.join(delimiter);
|
|
25
25
|
},
|
|
26
26
|
cacheKeyPrefix: 'test-',
|
|
27
|
-
ttlSecondsPositive: 86400,
|
|
27
|
+
ttlSecondsPositive: 86400, // 1 day
|
|
28
28
|
ttlSecondsNegative: 600, // 10 minutes
|
|
29
29
|
};
|
|
30
30
|
});
|
|
@@ -53,15 +53,21 @@ describe(GenericRedisCacher_1.default, () => {
|
|
|
53
53
|
});
|
|
54
54
|
// simulate non existent db fetch, should write negative result ('') to cache
|
|
55
55
|
const nonExistentId = (0, uuid_1.v4)();
|
|
56
|
-
const entityNonExistentResult = await RedisTestEntity_1.default.loader(viewerContext)
|
|
56
|
+
const entityNonExistentResult = await RedisTestEntity_1.default.loader(viewerContext)
|
|
57
|
+
.withAuthorizationResults()
|
|
58
|
+
.loadByIDAsync(nonExistentId);
|
|
57
59
|
expect(entityNonExistentResult.ok).toBe(false);
|
|
58
60
|
const nonExistentCachedValue = await genericRedisCacheContext.redisClient.get(cacheKeyMaker('id', nonExistentId));
|
|
59
61
|
expect(nonExistentCachedValue).toEqual('');
|
|
60
62
|
// load again through entities framework to ensure it reads negative result
|
|
61
|
-
const entityNonExistentResult2 = await RedisTestEntity_1.default.loader(viewerContext)
|
|
63
|
+
const entityNonExistentResult2 = await RedisTestEntity_1.default.loader(viewerContext)
|
|
64
|
+
.withAuthorizationResults()
|
|
65
|
+
.loadByIDAsync(nonExistentId);
|
|
62
66
|
expect(entityNonExistentResult2.ok).toBe(false);
|
|
63
67
|
// invalidate from cache to ensure it invalidates correctly
|
|
64
|
-
await RedisTestEntity_1.default.loader(viewerContext)
|
|
68
|
+
await RedisTestEntity_1.default.loader(viewerContext)
|
|
69
|
+
.utils()
|
|
70
|
+
.invalidateFieldsAsync(entity1.getAllFields());
|
|
65
71
|
const cachedValueNull = await genericRedisCacheContext.redisClient.get(cacheKeyMaker('id', entity1.getID()));
|
|
66
72
|
expect(cachedValueNull).toBe(null);
|
|
67
73
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenericRedisCacher-full-integration-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/GenericRedisCacher-full-integration-test.ts"],"names":[],"mappings":";;;;;AAAA,yCAA6C;AAC7C,2CAAmD;AACnD,sDAA4B;AAC5B,6BAA0B;AAC1B,+BAAoC;AAEpC,+EAAqF;AACrF,sFAA8D;AAC9D,yIAAsI;AAEtI,MAAM,iBAAkB,SAAQ,sBAAa;CAAG;AAEhD,QAAQ,CAAC,4BAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,wBAAkD,CAAC;IAEvD,SAAS,CAAC,GAAG,EAAE;QACb,wBAAwB,GAAG;YACzB,WAAW,EAAE,IAAI,iBAAK,CAAC,IAAI,SAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;YACrE,SAAS,CAAC,GAAG,KAAe;gBAC1B,MAAM,SAAS,GAAG,GAAG,CAAC;gBACtB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACtC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,SAAS,EAAE,CAAC,CAChE,CAAC;gBACF,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,cAAc,EAAE,OAAO;YACvB,kBAAkB,EAAE,KAAK;
|
|
1
|
+
{"version":3,"file":"GenericRedisCacher-full-integration-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/GenericRedisCacher-full-integration-test.ts"],"names":[],"mappings":";;;;;AAAA,yCAA6C;AAC7C,2CAAmD;AACnD,sDAA4B;AAC5B,6BAA0B;AAC1B,+BAAoC;AAEpC,+EAAqF;AACrF,sFAA8D;AAC9D,yIAAsI;AAEtI,MAAM,iBAAkB,SAAQ,sBAAa;CAAG;AAEhD,QAAQ,CAAC,4BAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,wBAAkD,CAAC;IAEvD,SAAS,CAAC,GAAG,EAAE;QACb,wBAAwB,GAAG;YACzB,WAAW,EAAE,IAAI,iBAAK,CAAC,IAAI,SAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;YACrE,SAAS,CAAC,GAAG,KAAe;gBAC1B,MAAM,SAAS,GAAG,GAAG,CAAC;gBACtB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACtC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,SAAS,EAAE,CAAC,CAChE,CAAC;gBACF,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,cAAc,EAAE,OAAO;YACvB,kBAAkB,EAAE,KAAK,EAAE,QAAQ;YACnC,kBAAkB,EAAE,GAAG,EAAE,aAAa;SACvC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAO,wBAAwB,CAAC,WAAqB,CAAC,OAAO,EAAE,CAAC;IAClE,CAAC,CAAC,CAAC;IACH,QAAQ,CAAC,KAAK,IAAI,EAAE;QACjB,wBAAwB,CAAC,WAAqB,CAAC,UAAU,EAAE,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,aAAa,GAAG,IAAI,iBAAiB,CACzC,IAAA,qGAAiD,EAAC,wBAAwB,CAAC,CAC5E,CAAC;QACF,MAAM,aAAa,GACjB,aAAa,CAAC,uBAAuB,CAAC,qBAAqB,CAAC,yBAAe,CAAC,CAC1E,sBAAsB,CACvB,CAAC,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC;QACrC,MAAM,aAAa,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAExE,MAAM,cAAc,GAAG,MAAM,yBAAe,CAAC,OAAO,CAAC,aAAa,CAAC;aAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;aACxB,kBAAkB,EAAE,CAAC;QAExB,2CAA2C;QAC3C,MAAM,OAAO,GAAG,MAAM,yBAAe,CAAC,MAAM,CAAC,aAAa,CAAC;aACxD,SAAS,EAAE;aACX,aAAa,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;QAEzC,MAAM,UAAU,GAAG,MAAO,wBAAwB,CAAC,WAAqB,CAAC,GAAG,CAC1E,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CACrC,CAAC;QACF,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,UAAW,CAAC,CAAC;QAC5C,MAAM,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC;YAChC,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE;YACnB,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QAEH,6EAA6E;QAC7E,MAAM,aAAa,GAAG,IAAA,SAAM,GAAE,CAAC;QAE/B,MAAM,uBAAuB,GAAG,MAAM,yBAAe,CAAC,MAAM,CAAC,aAAa,CAAC;aACxE,wBAAwB,EAAE;aAC1B,aAAa,CAAC,aAAa,CAAC,CAAC;QAChC,MAAM,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE/C,MAAM,sBAAsB,GAAG,MAAO,wBAAwB,CAAC,WAAqB,CAAC,GAAG,CACtF,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CACnC,CAAC;QACF,MAAM,CAAC,sBAAsB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAE3C,2EAA2E;QAC3E,MAAM,wBAAwB,GAAG,MAAM,yBAAe,CAAC,MAAM,CAAC,aAAa,CAAC;aACzE,wBAAwB,EAAE;aAC1B,aAAa,CAAC,aAAa,CAAC,CAAC;QAChC,MAAM,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEhD,2DAA2D;QAC3D,MAAM,yBAAe,CAAC,MAAM,CAAC,aAAa,CAAC;aACxC,KAAK,EAAE;aACP,qBAAqB,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;QACjD,MAAM,eAAe,GAAG,MAAO,wBAAwB,CAAC,WAAqB,CAAC,GAAG,CAC/E,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CACrC,CAAC;QACF,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,aAAa,GAAG,IAAI,iBAAiB,CACzC,IAAA,qGAAiD,EAAC,wBAAwB,CAAC,CAC5E,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,MAAM,IAAA,4BAAkB,EACtC,yBAAe,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,WAAW,EAAE,CACjF,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEpD,MAAM,OAAO,GAAG,MAAM,yBAAe,CAAC,MAAM,CAAC,aAAa,CAAC;aACxD,SAAS,EAAE;aACX,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAClC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAEpD,uBAAuB;QACvB,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAC/B,IAAA,qGAAiD,EAAC,wBAAwB,CAAC,CAC5E,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,yBAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAC7F,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,aAAa,GAAG,IAAI,iBAAiB,CACzC,IAAA,qGAAiD,EAAC,wBAAwB,CAAC,CAC5E,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,IAAA,4BAAkB,EACtC,yBAAe,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAC1E,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,yBAAe,CAAC,MAAM,CAAC,aAAa,CAAC;aACxD,SAAS,EAAE;aACX,wBAAwB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAElD,uBAAuB;QACvB,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAC/B,IAAA,qGAAiD,EAAC,wBAAwB,CAAC,CAC5E,CAAC;QACF,MAAM,OAAO,GAAG,MAAM,yBAAe,CAAC,MAAM,CAAC,GAAG,CAAC;aAC9C,SAAS,EAAE;aACX,wBAAwB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenericRedisCacher-integration-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/GenericRedisCacher-integration-test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAA0D;AAC1D,sDAA4B;AAC5B,6BAA0B;AAE1B,+EAAqF;AACrF,mFAGyC;AACzC,yIAAsI;AAEtI,MAAM,iBAAkB,SAAQ,sBAAa;CAAG;AAEhD,QAAQ,CAAC,4BAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,wBAAkD,CAAC;IAEvD,SAAS,CAAC,GAAG,EAAE;QACb,wBAAwB,GAAG;YACzB,WAAW,EAAE,IAAI,iBAAK,CAAC,IAAI,SAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;YACrE,SAAS,CAAC,GAAG,KAAe;gBAC1B,MAAM,SAAS,GAAG,GAAG,CAAC;gBACtB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACtC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,SAAS,EAAE,CAAC,CAChE,CAAC;gBACF,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,cAAc,EAAE,OAAO;YACvB,kBAAkB,EAAE,KAAK;
|
|
1
|
+
{"version":3,"file":"GenericRedisCacher-integration-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/GenericRedisCacher-integration-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/errors-test.ts"],"names":[],"mappings":";;;;;AAAA,yCAA+E;AAC/E,sDAA4B;AAC5B,6BAA0B;AAE1B,+EAAqF;AACrF,sFAA8D;AAC9D,yIAAsI;AAEtI,MAAM,iBAAkB,SAAQ,sBAAa;CAAG;AAEhD,QAAQ,CAAC,4BAAkB,EAAE,GAAG,EAAE;IAChC,MAAM,WAAW,GAAG,IAAI,iBAAK,CAAC,IAAI,SAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7E,IAAI,wBAAkD,CAAC;IAEvD,SAAS,CAAC,GAAG,EAAE;QACb,wBAAwB,GAAG;YACzB,WAAW;YACX,SAAS,CAAC,GAAG,KAAe;gBAC1B,MAAM,SAAS,GAAG,GAAG,CAAC;gBACtB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACtC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,SAAS,EAAE,CAAC,CAChE,CAAC;gBACF,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,cAAc,EAAE,OAAO;YACvB,kBAAkB,EAAE,KAAK;
|
|
1
|
+
{"version":3,"file":"errors-test.js","sourceRoot":"","sources":["../../src/__integration-tests__/errors-test.ts"],"names":[],"mappings":";;;;;AAAA,yCAA+E;AAC/E,sDAA4B;AAC5B,6BAA0B;AAE1B,+EAAqF;AACrF,sFAA8D;AAC9D,yIAAsI;AAEtI,MAAM,iBAAkB,SAAQ,sBAAa;CAAG;AAEhD,QAAQ,CAAC,4BAAkB,EAAE,GAAG,EAAE;IAChC,MAAM,WAAW,GAAG,IAAI,iBAAK,CAAC,IAAI,SAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7E,IAAI,wBAAkD,CAAC;IAEvD,SAAS,CAAC,GAAG,EAAE;QACb,wBAAwB,GAAG;YACzB,WAAW;YACX,SAAS,CAAC,GAAG,KAAe;gBAC1B,MAAM,SAAS,GAAG,GAAG,CAAC;gBACtB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACtC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,SAAS,EAAE,CAAC,CAChE,CAAC;gBACF,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,CAAC;YACD,cAAc,EAAE,OAAO;YACvB,kBAAkB,EAAE,KAAK,EAAE,QAAQ;YACnC,kBAAkB,EAAE,GAAG,EAAE,aAAa;SACvC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,WAAW,CAAC,OAAO,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,WAAW,CAAC,UAAU,EAAE,CAAC;QAEzB,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAC/B,IAAA,qGAAiD,EAAC,wBAAwB,CAAC,CAC5E,CAAC;QAEF,MAAM,MAAM,CACV,yBAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,kBAAkB,EAAE,CAC3E,CAAC,OAAO,CAAC,OAAO,CAAC,yCAAgC,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapNativeRedisCallAsync-test.js","sourceRoot":"","sources":["../../../src/errors/__tests__/wrapNativeRedisCallAsync-test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAgE;AAEhE,2FAAmE;AAEnE,QAAQ,CAAC,kCAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,MAAM,UAAU,GAAG,KAAK,IAAmB,EAAE;YAC3C,gFAAgF;YAChF,MAAM,OAAO,CAAC;QAChB,CAAC,CAAC;QAEF,IAAI,mBAAwB,CAAC;QAC7B,IAAI;
|
|
1
|
+
{"version":3,"file":"wrapNativeRedisCallAsync-test.js","sourceRoot":"","sources":["../../../src/errors/__tests__/wrapNativeRedisCallAsync-test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAgE;AAEhE,2FAAmE;AAEnE,QAAQ,CAAC,kCAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,MAAM,UAAU,GAAG,KAAK,IAAmB,EAAE;YAC3C,gFAAgF;YAChF,MAAM,OAAO,CAAC;QAChB,CAAC,CAAC;QAEF,IAAI,mBAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,IAAA,kCAAwB,EAAC,UAAU,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,mBAAmB,GAAG,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACtD,MAAM,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,UAAU,GAAG,KAAK,IAAmB,EAAE;YAC3C,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC,CAAC,KAAK,GAAG,OAAO,CAAC;YAClB,MAAM,CAAC,CAAC;QACV,CAAC,CAAC;QAEF,IAAI,mBAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,IAAA,kCAAwB,EAAC,UAAU,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,mBAAmB,GAAG,CAAC,CAAC;QAC1B,CAAC;QACD,MAAM,CAAC,mBAAmB,CAAC,CAAC,cAAc,CAAC,yCAAgC,CAAC,CAAC;QAC7E,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapNativeRedisCallAsync.js","sourceRoot":"","sources":["../../src/errors/wrapNativeRedisCallAsync.ts"],"names":[],"mappings":";;AAAA,yCAAgE;AAEjD,KAAK,UAAU,wBAAwB,CAAI,EAAoB;IAC5E,IAAI;
|
|
1
|
+
{"version":3,"file":"wrapNativeRedisCallAsync.js","sourceRoot":"","sources":["../../src/errors/wrapNativeRedisCallAsync.ts"],"names":[],"mappings":";;AAAA,yCAAgE;AAEjD,KAAK,UAAU,wBAAwB,CAAI,EAAoB;IAC5E,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,CAAC;QACV,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,yCAAgC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACjE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACZ,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QACxB,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAdD,2CAcC"}
|
|
@@ -13,21 +13,18 @@ class RedisTestEntity extends entity_1.Entity {
|
|
|
13
13
|
}
|
|
14
14
|
exports.default = RedisTestEntity;
|
|
15
15
|
class RedisTestEntityPrivacyPolicy extends entity_1.EntityPrivacyPolicy {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
new entity_1.AlwaysAllowPrivacyPolicyRule(),
|
|
29
|
-
];
|
|
30
|
-
}
|
|
16
|
+
createRules = [
|
|
17
|
+
new entity_1.AlwaysAllowPrivacyPolicyRule(),
|
|
18
|
+
];
|
|
19
|
+
readRules = [
|
|
20
|
+
new entity_1.AlwaysAllowPrivacyPolicyRule(),
|
|
21
|
+
];
|
|
22
|
+
updateRules = [
|
|
23
|
+
new entity_1.AlwaysAllowPrivacyPolicyRule(),
|
|
24
|
+
];
|
|
25
|
+
deleteRules = [
|
|
26
|
+
new entity_1.AlwaysAllowPrivacyPolicyRule(),
|
|
27
|
+
];
|
|
31
28
|
}
|
|
32
29
|
exports.RedisTestEntityPrivacyPolicy = RedisTestEntityPrivacyPolicy;
|
|
33
30
|
exports.redisTestEntityConfiguration = new entity_1.EntityConfiguration({
|
|
@@ -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,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;
|
|
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;IAC6B,WAAW,GAAG;QACxC,IAAI,qCAA4B,EAK7B;KACJ,CAAC;IAC0B,SAAS,GAAG;QACtC,IAAI,qCAA4B,EAK7B;KACJ,CAAC;IAC0B,WAAW,GAAG;QACxC,IAAI,qCAA4B,EAK7B;KACJ,CAAC;IAC0B,WAAW,GAAG;QACxC,IAAI,qCAA4B,EAK7B;KACJ,CAAC;CACH;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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/entity-cache-adapter-redis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"description": "Redis cache adapter for @expo/entity",
|
|
5
5
|
"files": [
|
|
6
6
|
"build",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"ioredis": ">=5"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@expo/entity": "^0.
|
|
34
|
+
"@expo/entity": "^0.36.0",
|
|
35
35
|
"ioredis": "^5.2.5"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "f17a33c42874c0d9c46311d19847074ddafeb04e"
|
|
38
38
|
}
|
|
@@ -57,21 +57,23 @@ export interface GenericRedisCacheContext {
|
|
|
57
57
|
ttlSecondsNegative: number;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export default class GenericRedisCacher<TFields
|
|
60
|
+
export default class GenericRedisCacher<TFields extends Record<string, any>>
|
|
61
|
+
implements IEntityGenericCacher<TFields>
|
|
62
|
+
{
|
|
61
63
|
constructor(
|
|
62
64
|
private readonly context: GenericRedisCacheContext,
|
|
63
|
-
private readonly entityConfiguration: EntityConfiguration<TFields
|
|
65
|
+
private readonly entityConfiguration: EntityConfiguration<TFields>,
|
|
64
66
|
) {}
|
|
65
67
|
|
|
66
68
|
public async loadManyAsync(
|
|
67
|
-
keys: readonly string[]
|
|
69
|
+
keys: readonly string[],
|
|
68
70
|
): Promise<ReadonlyMap<string, CacheLoadResult<TFields>>> {
|
|
69
71
|
if (keys.length === 0) {
|
|
70
72
|
return new Map();
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
const redisResults = await wrapNativeRedisCallAsync(() =>
|
|
74
|
-
this.context.redisClient.mget(...keys)
|
|
76
|
+
this.context.redisClient.mget(...keys),
|
|
75
77
|
);
|
|
76
78
|
|
|
77
79
|
const results = new Map<string, CacheLoadResult<TFields>>();
|
|
@@ -89,7 +91,7 @@ export default class GenericRedisCacher<TFields> implements IEntityGenericCacher
|
|
|
89
91
|
item: transformCacheObjectToFields(
|
|
90
92
|
this.entityConfiguration,
|
|
91
93
|
redisTransformerMap,
|
|
92
|
-
JSON.parse(redisResult)
|
|
94
|
+
JSON.parse(redisResult),
|
|
93
95
|
),
|
|
94
96
|
});
|
|
95
97
|
} else {
|
|
@@ -111,10 +113,10 @@ export default class GenericRedisCacher<TFields> implements IEntityGenericCacher
|
|
|
111
113
|
redisTransaction = redisTransaction.set(
|
|
112
114
|
key,
|
|
113
115
|
JSON.stringify(
|
|
114
|
-
transformFieldsToCacheObject(this.entityConfiguration, redisTransformerMap, object)
|
|
116
|
+
transformFieldsToCacheObject(this.entityConfiguration, redisTransformerMap, object),
|
|
115
117
|
),
|
|
116
118
|
'EX',
|
|
117
|
-
this.context.ttlSecondsPositive
|
|
119
|
+
this.context.ttlSecondsPositive,
|
|
118
120
|
);
|
|
119
121
|
});
|
|
120
122
|
await wrapNativeRedisCallAsync(() => redisTransaction.exec());
|
|
@@ -131,7 +133,7 @@ export default class GenericRedisCacher<TFields> implements IEntityGenericCacher
|
|
|
131
133
|
key,
|
|
132
134
|
DOES_NOT_EXIST_REDIS,
|
|
133
135
|
'EX',
|
|
134
|
-
this.context.ttlSecondsNegative
|
|
136
|
+
this.context.ttlSecondsNegative,
|
|
135
137
|
);
|
|
136
138
|
});
|
|
137
139
|
await wrapNativeRedisCallAsync(() => redisTransaction.exec());
|
|
@@ -147,7 +149,7 @@ export default class GenericRedisCacher<TFields> implements IEntityGenericCacher
|
|
|
147
149
|
|
|
148
150
|
public makeCacheKey<N extends keyof TFields>(
|
|
149
151
|
fieldName: N,
|
|
150
|
-
fieldValue: NonNullable<TFields[N]
|
|
152
|
+
fieldValue: NonNullable<TFields[N]>,
|
|
151
153
|
): string {
|
|
152
154
|
const columnName = this.entityConfiguration.entityToDBFieldsKeyMapping.get(fieldName);
|
|
153
155
|
invariant(columnName, `database field mapping missing for ${String(fieldName)}`);
|
|
@@ -156,7 +158,7 @@ export default class GenericRedisCacher<TFields> implements IEntityGenericCacher
|
|
|
156
158
|
this.entityConfiguration.tableName,
|
|
157
159
|
`v2.${this.entityConfiguration.cacheKeyVersion}`,
|
|
158
160
|
columnName,
|
|
159
|
-
String(fieldValue)
|
|
161
|
+
String(fieldValue),
|
|
160
162
|
);
|
|
161
163
|
}
|
|
162
164
|
}
|
|
@@ -10,8 +10,8 @@ import GenericRedisCacher, { GenericRedisCacheContext } from './GenericRedisCach
|
|
|
10
10
|
export default class RedisCacheAdapterProvider implements IEntityCacheAdapterProvider {
|
|
11
11
|
constructor(private readonly context: GenericRedisCacheContext) {}
|
|
12
12
|
|
|
13
|
-
getCacheAdapter<TFields
|
|
14
|
-
entityConfiguration: EntityConfiguration<TFields
|
|
13
|
+
getCacheAdapter<TFields extends Record<string, any>>(
|
|
14
|
+
entityConfiguration: EntityConfiguration<TFields>,
|
|
15
15
|
): IEntityCacheAdapter<TFields> {
|
|
16
16
|
return new GenericEntityCacheAdapter(new GenericRedisCacher(this.context, entityConfiguration));
|
|
17
17
|
}
|
|
@@ -19,7 +19,7 @@ class BatchedRedis implements IRedis {
|
|
|
19
19
|
this.batchMgetAsync.bind(this),
|
|
20
20
|
{
|
|
21
21
|
maxBatchInterval: 0,
|
|
22
|
-
}
|
|
22
|
+
},
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
constructor(private readonly redis: Redis) {}
|
|
@@ -40,7 +40,7 @@ class BatchedRedis implements IRedis {
|
|
|
40
40
|
const result = keysToResults.get(key);
|
|
41
41
|
invariant(result !== undefined, 'result should not be undefined');
|
|
42
42
|
return result;
|
|
43
|
-
})
|
|
43
|
+
}),
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -69,7 +69,7 @@ describe(GenericRedisCacher, () => {
|
|
|
69
69
|
makeKeyFn(...parts: string[]): string {
|
|
70
70
|
const delimiter = ':';
|
|
71
71
|
const escapedParts = parts.map((part) =>
|
|
72
|
-
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`)
|
|
72
|
+
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`),
|
|
73
73
|
);
|
|
74
74
|
return escapedParts.join(delimiter);
|
|
75
75
|
},
|
|
@@ -90,7 +90,7 @@ describe(GenericRedisCacher, () => {
|
|
|
90
90
|
it('has correct caching behavior', async () => {
|
|
91
91
|
// simulate two requests
|
|
92
92
|
const viewerContext = new ViewerContext(
|
|
93
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
93
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
94
94
|
);
|
|
95
95
|
|
|
96
96
|
const mgetSpy = jest.spyOn(redis, 'mget');
|
|
@@ -108,13 +108,13 @@ describe(GenericRedisCacher, () => {
|
|
|
108
108
|
// loading an entity should put it in cache. load by multiple requests and multiple fields in same tick to ensure batch works
|
|
109
109
|
mgetSpy.mockClear();
|
|
110
110
|
const viewerContext1 = new ViewerContext(
|
|
111
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
111
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
112
112
|
);
|
|
113
113
|
const viewerContext2 = new ViewerContext(
|
|
114
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
114
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
115
115
|
);
|
|
116
116
|
const viewerContext3 = new ViewerContext(
|
|
117
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
117
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
118
118
|
);
|
|
119
119
|
const [entity1, entity2, entity3] = await Promise.all([
|
|
120
120
|
RedisTestEntity.loader(viewerContext1).enforcing().loadByIDAsync(entity1Created.getID()),
|
|
@@ -145,21 +145,23 @@ describe(GenericRedisCacher, () => {
|
|
|
145
145
|
|
|
146
146
|
// simulate non existent db fetch, should write negative result ('') to cache
|
|
147
147
|
const nonExistentId = uuidv4();
|
|
148
|
-
const entityNonExistentResult = await RedisTestEntity.loader(viewerContext)
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
const entityNonExistentResult = await RedisTestEntity.loader(viewerContext)
|
|
149
|
+
.withAuthorizationResults()
|
|
150
|
+
.loadByIDAsync(nonExistentId);
|
|
151
151
|
expect(entityNonExistentResult.ok).toBe(false);
|
|
152
152
|
const cacheKeyNonExistent = cacheKeyMaker('id', nonExistentId);
|
|
153
153
|
const nonExistentCachedValue = await redis.get(cacheKeyNonExistent);
|
|
154
154
|
expect(nonExistentCachedValue).toEqual('');
|
|
155
155
|
// load again through entities framework to ensure it reads negative result
|
|
156
|
-
const entityNonExistentResult2 = await RedisTestEntity.loader(viewerContext)
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
const entityNonExistentResult2 = await RedisTestEntity.loader(viewerContext)
|
|
157
|
+
.withAuthorizationResults()
|
|
158
|
+
.loadByIDAsync(nonExistentId);
|
|
159
159
|
expect(entityNonExistentResult2.ok).toBe(false);
|
|
160
160
|
|
|
161
161
|
// invalidate from cache to ensure it invalidates correctly in both caches
|
|
162
|
-
await RedisTestEntity.loader(viewerContext)
|
|
162
|
+
await RedisTestEntity.loader(viewerContext)
|
|
163
|
+
.utils()
|
|
164
|
+
.invalidateFieldsAsync(entity1.getAllFields());
|
|
163
165
|
await expect(redis.get(cacheKeyEntity1)).resolves.toBeNull();
|
|
164
166
|
await expect(redis.get(cacheKeyEntity1NameField)).resolves.toBeNull();
|
|
165
167
|
});
|
|
@@ -19,7 +19,7 @@ describe(GenericRedisCacher, () => {
|
|
|
19
19
|
makeKeyFn(...parts: string[]): string {
|
|
20
20
|
const delimiter = ':';
|
|
21
21
|
const escapedParts = parts.map((part) =>
|
|
22
|
-
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`)
|
|
22
|
+
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`),
|
|
23
23
|
);
|
|
24
24
|
return escapedParts.join(delimiter);
|
|
25
25
|
},
|
|
@@ -38,7 +38,7 @@ describe(GenericRedisCacher, () => {
|
|
|
38
38
|
|
|
39
39
|
it('has correct caching behavior', async () => {
|
|
40
40
|
const viewerContext = new TestViewerContext(
|
|
41
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
41
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
42
42
|
);
|
|
43
43
|
const genericCacher =
|
|
44
44
|
viewerContext.entityCompanionProvider.getCompanionForEntity(RedisTestEntity)[
|
|
@@ -56,7 +56,7 @@ describe(GenericRedisCacher, () => {
|
|
|
56
56
|
.loadByIDAsync(entity1Created.getID());
|
|
57
57
|
|
|
58
58
|
const cachedJSON = await (genericRedisCacheContext.redisClient as Redis).get(
|
|
59
|
-
cacheKeyMaker('id', entity1.getID())
|
|
59
|
+
cacheKeyMaker('id', entity1.getID()),
|
|
60
60
|
);
|
|
61
61
|
const cachedValue = JSON.parse(cachedJSON!);
|
|
62
62
|
expect(cachedValue).toMatchObject({
|
|
@@ -67,37 +67,39 @@ describe(GenericRedisCacher, () => {
|
|
|
67
67
|
// simulate non existent db fetch, should write negative result ('') to cache
|
|
68
68
|
const nonExistentId = uuidv4();
|
|
69
69
|
|
|
70
|
-
const entityNonExistentResult = await RedisTestEntity.loader(viewerContext)
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
const entityNonExistentResult = await RedisTestEntity.loader(viewerContext)
|
|
71
|
+
.withAuthorizationResults()
|
|
72
|
+
.loadByIDAsync(nonExistentId);
|
|
73
73
|
expect(entityNonExistentResult.ok).toBe(false);
|
|
74
74
|
|
|
75
75
|
const nonExistentCachedValue = await (genericRedisCacheContext.redisClient as Redis).get(
|
|
76
|
-
cacheKeyMaker('id', nonExistentId)
|
|
76
|
+
cacheKeyMaker('id', nonExistentId),
|
|
77
77
|
);
|
|
78
78
|
expect(nonExistentCachedValue).toEqual('');
|
|
79
79
|
|
|
80
80
|
// load again through entities framework to ensure it reads negative result
|
|
81
|
-
const entityNonExistentResult2 = await RedisTestEntity.loader(viewerContext)
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
const entityNonExistentResult2 = await RedisTestEntity.loader(viewerContext)
|
|
82
|
+
.withAuthorizationResults()
|
|
83
|
+
.loadByIDAsync(nonExistentId);
|
|
84
84
|
expect(entityNonExistentResult2.ok).toBe(false);
|
|
85
85
|
|
|
86
86
|
// invalidate from cache to ensure it invalidates correctly
|
|
87
|
-
await RedisTestEntity.loader(viewerContext)
|
|
87
|
+
await RedisTestEntity.loader(viewerContext)
|
|
88
|
+
.utils()
|
|
89
|
+
.invalidateFieldsAsync(entity1.getAllFields());
|
|
88
90
|
const cachedValueNull = await (genericRedisCacheContext.redisClient as Redis).get(
|
|
89
|
-
cacheKeyMaker('id', entity1.getID())
|
|
91
|
+
cacheKeyMaker('id', entity1.getID()),
|
|
90
92
|
);
|
|
91
93
|
expect(cachedValueNull).toBe(null);
|
|
92
94
|
});
|
|
93
95
|
|
|
94
96
|
it('caches and restores date fields', async () => {
|
|
95
97
|
const viewerContext = new TestViewerContext(
|
|
96
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
98
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
97
99
|
);
|
|
98
100
|
const date = new Date();
|
|
99
101
|
const entity1 = await enforceAsyncResult(
|
|
100
|
-
RedisTestEntity.creator(viewerContext).setField('dateField', date).createAsync()
|
|
102
|
+
RedisTestEntity.creator(viewerContext).setField('dateField', date).createAsync(),
|
|
101
103
|
);
|
|
102
104
|
expect(entity1.getField('dateField')).toEqual(date);
|
|
103
105
|
|
|
@@ -108,7 +110,7 @@ describe(GenericRedisCacher, () => {
|
|
|
108
110
|
|
|
109
111
|
// simulate new request
|
|
110
112
|
const vc2 = new TestViewerContext(
|
|
111
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
113
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
112
114
|
);
|
|
113
115
|
const entity3 = await RedisTestEntity.loader(vc2).enforcing().loadByIDAsync(entity1.getID());
|
|
114
116
|
expect(entity3.getField('dateField')).toEqual(date);
|
|
@@ -116,10 +118,10 @@ describe(GenericRedisCacher, () => {
|
|
|
116
118
|
|
|
117
119
|
it('caches and restores empty string field keys', async () => {
|
|
118
120
|
const viewerContext = new TestViewerContext(
|
|
119
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
121
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
120
122
|
);
|
|
121
123
|
const entity1 = await enforceAsyncResult(
|
|
122
|
-
RedisTestEntity.creator(viewerContext).setField('name', '').createAsync()
|
|
124
|
+
RedisTestEntity.creator(viewerContext).setField('name', '').createAsync(),
|
|
123
125
|
);
|
|
124
126
|
const entity2 = await RedisTestEntity.loader(viewerContext)
|
|
125
127
|
.enforcing()
|
|
@@ -128,7 +130,7 @@ describe(GenericRedisCacher, () => {
|
|
|
128
130
|
|
|
129
131
|
// simulate new request
|
|
130
132
|
const vc2 = new TestViewerContext(
|
|
131
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
133
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
132
134
|
);
|
|
133
135
|
const entity3 = await RedisTestEntity.loader(vc2)
|
|
134
136
|
.enforcing()
|
|
@@ -20,7 +20,7 @@ describe(GenericRedisCacher, () => {
|
|
|
20
20
|
makeKeyFn(...parts: string[]): string {
|
|
21
21
|
const delimiter = ':';
|
|
22
22
|
const escapedParts = parts.map((part) =>
|
|
23
|
-
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`)
|
|
23
|
+
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`),
|
|
24
24
|
);
|
|
25
25
|
return escapedParts.join(delimiter);
|
|
26
26
|
},
|
|
@@ -39,11 +39,11 @@ describe(GenericRedisCacher, () => {
|
|
|
39
39
|
|
|
40
40
|
it('has correct caching and loading behavior', async () => {
|
|
41
41
|
const viewerContext = new TestViewerContext(
|
|
42
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
42
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
43
43
|
);
|
|
44
44
|
const genericRedisCacher = new GenericRedisCacher(
|
|
45
45
|
genericRedisCacheContext,
|
|
46
|
-
redisTestEntityConfiguration
|
|
46
|
+
redisTestEntityConfiguration,
|
|
47
47
|
);
|
|
48
48
|
const date = new Date();
|
|
49
49
|
const entity1Created = await RedisTestEntity.creator(viewerContext)
|
|
@@ -74,7 +74,7 @@ describe(GenericRedisCacher, () => {
|
|
|
74
74
|
it('has correct negative caching behaviour', async () => {
|
|
75
75
|
const genericRedisCacher = new GenericRedisCacher(
|
|
76
76
|
genericRedisCacheContext,
|
|
77
|
-
redisTestEntityConfiguration
|
|
77
|
+
redisTestEntityConfiguration,
|
|
78
78
|
);
|
|
79
79
|
|
|
80
80
|
const testKey = `test-id-key-non-existent-id`;
|
|
@@ -85,11 +85,11 @@ describe(GenericRedisCacher, () => {
|
|
|
85
85
|
});
|
|
86
86
|
it('has correct invalidation behaviour', async () => {
|
|
87
87
|
const viewerContext = new TestViewerContext(
|
|
88
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
88
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
89
89
|
);
|
|
90
90
|
const genericRedisCacher = new GenericRedisCacher(
|
|
91
91
|
genericRedisCacheContext,
|
|
92
|
-
redisTestEntityConfiguration
|
|
92
|
+
redisTestEntityConfiguration,
|
|
93
93
|
);
|
|
94
94
|
const date = new Date();
|
|
95
95
|
const entity1Created = await RedisTestEntity.creator(viewerContext)
|
|
@@ -18,7 +18,7 @@ describe(GenericRedisCacher, () => {
|
|
|
18
18
|
makeKeyFn(...parts: string[]): string {
|
|
19
19
|
const delimiter = ':';
|
|
20
20
|
const escapedParts = parts.map((part) =>
|
|
21
|
-
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`)
|
|
21
|
+
part.replace('\\', '\\\\').replace(delimiter, `\\${delimiter}`),
|
|
22
22
|
);
|
|
23
23
|
return escapedParts.join(delimiter);
|
|
24
24
|
},
|
|
@@ -36,11 +36,11 @@ describe(GenericRedisCacher, () => {
|
|
|
36
36
|
redisClient.disconnect();
|
|
37
37
|
|
|
38
38
|
const vc1 = new TestViewerContext(
|
|
39
|
-
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext)
|
|
39
|
+
createRedisIntegrationTestEntityCompanionProvider(genericRedisCacheContext),
|
|
40
40
|
);
|
|
41
41
|
|
|
42
42
|
await expect(
|
|
43
|
-
RedisTestEntity.creator(vc1).setField('name', 'blah').enforceCreateAsync()
|
|
43
|
+
RedisTestEntity.creator(vc1).setField('name', 'blah').enforceCreateAsync(),
|
|
44
44
|
).rejects.toThrow(EntityCacheAdapterTransientError);
|
|
45
45
|
});
|
|
46
46
|
});
|
|
@@ -27,7 +27,7 @@ describe(GenericRedisCacher, () => {
|
|
|
27
27
|
|
|
28
28
|
// need to have one anything() for each element of spread, in this case 3
|
|
29
29
|
when(mockRedisClient.mget(anything(), anything(), anything())).thenCall(async (...keys) =>
|
|
30
|
-
keys.map((k) => redisResults.get(k) ?? null)
|
|
30
|
+
keys.map((k) => redisResults.get(k) ?? null),
|
|
31
31
|
);
|
|
32
32
|
|
|
33
33
|
const genericCacher = new GenericRedisCacher(
|
|
@@ -38,7 +38,7 @@ describe(GenericRedisCacher, () => {
|
|
|
38
38
|
ttlSecondsPositive: 1,
|
|
39
39
|
ttlSecondsNegative: 2,
|
|
40
40
|
},
|
|
41
|
-
entityConfiguration
|
|
41
|
+
entityConfiguration,
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
const cacheKeyWat = genericCacher['makeCacheKey']('id', 'wat');
|
|
@@ -68,7 +68,7 @@ describe(GenericRedisCacher, () => {
|
|
|
68
68
|
ttlSecondsPositive: 1,
|
|
69
69
|
ttlSecondsNegative: 2,
|
|
70
70
|
},
|
|
71
|
-
entityConfiguration
|
|
71
|
+
entityConfiguration,
|
|
72
72
|
);
|
|
73
73
|
const results = await genericCacher.loadManyAsync([]);
|
|
74
74
|
expect(results).toEqual(new Map());
|
|
@@ -84,7 +84,7 @@ describe(GenericRedisCacher, () => {
|
|
|
84
84
|
(key, value, code, ttl) => {
|
|
85
85
|
redisResults.set(key, { value, code, ttl });
|
|
86
86
|
return pipeline;
|
|
87
|
-
}
|
|
87
|
+
},
|
|
88
88
|
);
|
|
89
89
|
when(mockPipeline.exec()).thenResolve({} as any);
|
|
90
90
|
const pipeline = instance(mockPipeline);
|
|
@@ -100,7 +100,7 @@ describe(GenericRedisCacher, () => {
|
|
|
100
100
|
ttlSecondsPositive: 1,
|
|
101
101
|
ttlSecondsNegative: 2,
|
|
102
102
|
},
|
|
103
|
-
entityConfiguration
|
|
103
|
+
entityConfiguration,
|
|
104
104
|
);
|
|
105
105
|
|
|
106
106
|
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
@@ -123,7 +123,7 @@ describe(GenericRedisCacher, () => {
|
|
|
123
123
|
(key, value, code, ttl) => {
|
|
124
124
|
redisResults.set(key, { value, code, ttl });
|
|
125
125
|
return pipeline;
|
|
126
|
-
}
|
|
126
|
+
},
|
|
127
127
|
);
|
|
128
128
|
when(mockPipeline.exec()).thenResolve({} as any);
|
|
129
129
|
const pipeline = instance(mockPipeline);
|
|
@@ -139,7 +139,7 @@ describe(GenericRedisCacher, () => {
|
|
|
139
139
|
ttlSecondsPositive: 1,
|
|
140
140
|
ttlSecondsNegative: 2,
|
|
141
141
|
},
|
|
142
|
-
entityConfiguration
|
|
142
|
+
entityConfiguration,
|
|
143
143
|
);
|
|
144
144
|
|
|
145
145
|
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
@@ -167,7 +167,7 @@ describe(GenericRedisCacher, () => {
|
|
|
167
167
|
ttlSecondsPositive: 1,
|
|
168
168
|
ttlSecondsNegative: 2,
|
|
169
169
|
},
|
|
170
|
-
entityConfiguration
|
|
170
|
+
entityConfiguration,
|
|
171
171
|
);
|
|
172
172
|
const cacheKey = genericCacher['makeCacheKey']('id', 'wat');
|
|
173
173
|
|
|
@@ -185,7 +185,7 @@ describe(GenericRedisCacher, () => {
|
|
|
185
185
|
ttlSecondsPositive: 1,
|
|
186
186
|
ttlSecondsNegative: 2,
|
|
187
187
|
},
|
|
188
|
-
entityConfiguration
|
|
188
|
+
entityConfiguration,
|
|
189
189
|
);
|
|
190
190
|
await genericCacher.invalidateManyAsync([]);
|
|
191
191
|
});
|
|
@@ -14,7 +14,7 @@ const adapterProvider = new StubDatabaseAdapterProvider();
|
|
|
14
14
|
|
|
15
15
|
export const createRedisIntegrationTestEntityCompanionProvider = (
|
|
16
16
|
genericRedisCacheContext: GenericRedisCacheContext,
|
|
17
|
-
metricsAdapter: IEntityMetricsAdapter = new NoOpEntityMetricsAdapter()
|
|
17
|
+
metricsAdapter: IEntityMetricsAdapter = new NoOpEntityMetricsAdapter(),
|
|
18
18
|
): EntityCompanionProvider => {
|
|
19
19
|
return new EntityCompanionProvider(
|
|
20
20
|
metricsAdapter,
|
|
@@ -34,6 +34,6 @@ export const createRedisIntegrationTestEntityCompanionProvider = (
|
|
|
34
34
|
cacheAdapterProvider: new RedisCacheAdapterProvider(genericRedisCacheContext),
|
|
35
35
|
},
|
|
36
36
|
],
|
|
37
|
-
])
|
|
37
|
+
]),
|
|
38
38
|
);
|
|
39
39
|
};
|