@expo/entity-cache-adapter-local-memory 0.51.0 → 0.54.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.
@@ -1,17 +1,38 @@
1
1
  import { CacheLoadResult, EntityConfiguration, IEntityGenericCacher, IEntityLoadKey, IEntityLoadValue } from '@expo/entity';
2
- import LRUCache from 'lru-cache';
3
2
  export declare const DOES_NOT_EXIST_LOCAL_MEMORY_CACHE: unique symbol;
3
+ /**
4
+ * Type of value stored in the local memory cache. This is either the cached fields, or the
5
+ * DOES_NOT_EXIST_LOCAL_MEMORY_CACHE sentinel value.
6
+ */
4
7
  export type LocalMemoryCacheValue<TFields extends Record<string, any>> = Readonly<TFields> | typeof DOES_NOT_EXIST_LOCAL_MEMORY_CACHE;
5
- export type LocalMemoryCache<TFields extends Record<string, any>> = LRUCache<string, LocalMemoryCacheValue<TFields>>;
8
+ /**
9
+ * Interface for a local memory cache used by GenericLocalMemoryCacher. Most often, this is something like
10
+ * a TTLCache from the `@isaacs/ttlcache` package or an lru-cache.
11
+ */
12
+ export interface ILocalMemoryCache<TFields extends Record<string, any>> {
13
+ /**
14
+ * Gets a value from the cache for specified key.
15
+ * @param key - key to get
16
+ * @returns the cached value, or undefined if not present
17
+ */
18
+ get(key: string): LocalMemoryCacheValue<TFields> | undefined;
19
+ /**
20
+ * Sets a value in the cache for specified key.
21
+ * @param key - key to set
22
+ * @param value - value to set
23
+ */
24
+ set(key: string, value: LocalMemoryCacheValue<TFields>): void;
25
+ /**
26
+ * Deletes a value from the cache for specified key.
27
+ * @param key - key to delete
28
+ */
29
+ delete(key: string): void;
30
+ }
6
31
  export declare class GenericLocalMemoryCacher<TFields extends Record<string, any>, TIDField extends keyof TFields> implements IEntityGenericCacher<TFields, TIDField> {
7
32
  private readonly entityConfiguration;
8
33
  private readonly localMemoryCache;
9
- constructor(entityConfiguration: EntityConfiguration<TFields, TIDField>, localMemoryCache: LocalMemoryCache<TFields>);
10
- static createLRUCache<TFields extends Record<string, any>>(options?: {
11
- maxSize?: number;
12
- ttlSeconds?: number;
13
- }): LocalMemoryCache<TFields>;
14
- static createNoOpCache<TFields extends Record<string, any>>(): LocalMemoryCache<TFields>;
34
+ constructor(entityConfiguration: EntityConfiguration<TFields, TIDField>, localMemoryCache: ILocalMemoryCache<TFields>);
35
+ static createNoOpCache<TFields extends Record<string, any>>(): ILocalMemoryCache<TFields>;
15
36
  loadManyAsync(keys: readonly string[]): Promise<ReadonlyMap<string, CacheLoadResult<TFields>>>;
16
37
  cacheManyAsync(objectMap: ReadonlyMap<string, Readonly<TFields>>): Promise<void>;
17
38
  cacheDBMissesAsync(keys: readonly string[]): Promise<void>;
@@ -1,11 +1,7 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.GenericLocalMemoryCacher = exports.DOES_NOT_EXIST_LOCAL_MEMORY_CACHE = void 0;
7
4
  const entity_1 = require("@expo/entity");
8
- const lru_cache_1 = __importDefault(require("lru-cache"));
9
5
  // Sentinel value we store in local memory to negatively cache a database miss.
10
6
  // The sentinel value is distinct from any (positively) cached value.
11
7
  exports.DOES_NOT_EXIST_LOCAL_MEMORY_CACHE = Symbol('doesNotExist');
@@ -16,21 +12,14 @@ class GenericLocalMemoryCacher {
16
12
  this.entityConfiguration = entityConfiguration;
17
13
  this.localMemoryCache = localMemoryCache;
18
14
  }
19
- static createLRUCache(options = {}) {
20
- const DEFAULT_LRU_CACHE_MAX_AGE_SECONDS = 10;
21
- const DEFAULT_LRU_CACHE_SIZE = 10000;
22
- const maxAgeSeconds = options.ttlSeconds ?? DEFAULT_LRU_CACHE_MAX_AGE_SECONDS;
23
- return new lru_cache_1.default({
24
- max: options.maxSize ?? DEFAULT_LRU_CACHE_SIZE,
25
- length: (value) => (value === exports.DOES_NOT_EXIST_LOCAL_MEMORY_CACHE ? 0 : 1),
26
- maxAge: maxAgeSeconds * 1000, // convert to ms
27
- });
28
- }
29
15
  static createNoOpCache() {
30
- return new lru_cache_1.default({
31
- max: 0,
32
- maxAge: -1,
33
- });
16
+ return {
17
+ get(_key) {
18
+ return undefined;
19
+ },
20
+ set(_key, _value) { },
21
+ delete(_key) { },
22
+ };
34
23
  }
35
24
  async loadManyAsync(keys) {
36
25
  const cacheResults = new Map();
@@ -67,7 +56,7 @@ class GenericLocalMemoryCacher {
67
56
  }
68
57
  async invalidateManyAsync(keys) {
69
58
  for (const key of keys) {
70
- this.localMemoryCache.del(key);
59
+ this.localMemoryCache.delete(key);
71
60
  }
72
61
  }
73
62
  makeCacheKeyForStorage(key, value) {
@@ -1 +1 @@
1
- {"version":3,"file":"GenericLocalMemoryCacher.js","sourceRoot":"","sources":["../../src/GenericLocalMemoryCacher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GenericLocalMemoryCacher.js","sourceRoot":"","sources":["../../src/GenericLocalMemoryCacher.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import { EntityConfiguration, IEntityCacheAdapter, IEntityCacheAdapterProvider } from '@expo/entity';
2
+ import { ILocalMemoryCache } from './GenericLocalMemoryCacher';
3
+ export type LocalMemoryCacheCreator = <TFields extends Record<string, any>>() => ILocalMemoryCache<TFields>;
2
4
  /**
3
5
  * Vends local memory cache adapters. An instance of this class may be shared across requests to
4
6
  * share the local memory cache.
@@ -6,16 +8,13 @@ import { EntityConfiguration, IEntityCacheAdapter, IEntityCacheAdapterProvider }
6
8
  export declare class LocalMemoryCacheAdapterProvider implements IEntityCacheAdapterProvider {
7
9
  private readonly localMemoryCacheCreator;
8
10
  /**
9
- * @returns a no-op local memory cache adapter provider, or one that doesn't cache locally.
11
+ * @returns a no-op local memory cache adapter provider, or one that doesn't cache at all.
10
12
  */
11
13
  static createNoOpProvider(): IEntityCacheAdapterProvider;
12
14
  /**
13
- * @returns a local memory cache adapter provider configured with the supplied options.
15
+ * @returns a local memory cache adapter provider configured with the supplied local memory cache creator function.
14
16
  */
15
- static createProviderWithOptions(options?: {
16
- maxSize?: number;
17
- ttlSeconds?: number;
18
- }): IEntityCacheAdapterProvider;
17
+ static createProviderWithCacheCreator(cacheCreator: LocalMemoryCacheCreator): IEntityCacheAdapterProvider;
19
18
  private readonly localMemoryCacheAdapterMap;
20
19
  private constructor();
21
20
  getCacheAdapter<TFields extends Record<string, any>, TIDField extends keyof TFields>(entityConfiguration: EntityConfiguration<TFields, TIDField>): IEntityCacheAdapter<TFields, TIDField>;
@@ -10,16 +10,16 @@ const GenericLocalMemoryCacher_1 = require("./GenericLocalMemoryCacher");
10
10
  class LocalMemoryCacheAdapterProvider {
11
11
  localMemoryCacheCreator;
12
12
  /**
13
- * @returns a no-op local memory cache adapter provider, or one that doesn't cache locally.
13
+ * @returns a no-op local memory cache adapter provider, or one that doesn't cache at all.
14
14
  */
15
15
  static createNoOpProvider() {
16
16
  return new LocalMemoryCacheAdapterProvider(() => GenericLocalMemoryCacher_1.GenericLocalMemoryCacher.createNoOpCache());
17
17
  }
18
18
  /**
19
- * @returns a local memory cache adapter provider configured with the supplied options.
19
+ * @returns a local memory cache adapter provider configured with the supplied local memory cache creator function.
20
20
  */
21
- static createProviderWithOptions(options = {}) {
22
- return new LocalMemoryCacheAdapterProvider(() => GenericLocalMemoryCacher_1.GenericLocalMemoryCacher.createLRUCache(options));
21
+ static createProviderWithCacheCreator(cacheCreator) {
22
+ return new LocalMemoryCacheAdapterProvider(cacheCreator);
23
23
  }
24
24
  localMemoryCacheAdapterMap = new Map();
25
25
  constructor(localMemoryCacheCreator) {
@@ -1 +1 @@
1
- {"version":3,"file":"LocalMemoryCacheAdapterProvider.js","sourceRoot":"","sources":["../../src/LocalMemoryCacheAdapterProvider.ts"],"names":[],"mappings":";;;AAAA,yCAMsB;AAEtB,yEAAwF;AAExF;;;GAGG;AACH,MAAa,+BAA+B;IA2BvB;IA1BnB;;OAEG;IACH,MAAM,CAAC,kBAAkB;QACvB,OAAO,IAAI,+BAA+B,CAAC,GAAwC,EAAE,CACnF,mDAAwB,CAAC,eAAe,EAAW,CACpD,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,yBAAyB,CAC9B,UAAqD,EAAE;QAEvD,OAAO,IAAI,+BAA+B,CAAC,GAAwC,EAAE,CACnF,mDAAwB,CAAC,cAAc,CAAU,OAAO,CAAC,CAC1D,CAAC;IACJ,CAAC;IAEgB,0BAA0B,GAAG,IAAI,GAAG,EAGlD,CAAC;IAEJ,YACmB,uBAEe;QAFf,4BAAuB,GAAvB,uBAAuB,CAER;IAC/B,CAAC;IAEG,eAAe,CACpB,mBAA2D;QAE3D,OAAO,IAAA,wBAAe,EAAC,IAAI,CAAC,0BAA0B,EAAE,mBAAmB,CAAC,SAAS,EAAE,GAAG,EAAE;YAC1F,MAAM,gBAAgB,GAAG,IAAI,CAAC,uBAAuB,EAAW,CAAC;YACjE,OAAO,IAAI,kCAAyB,CAClC,IAAI,mDAAwB,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CACpE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA1CD,0EA0CC"}
1
+ {"version":3,"file":"LocalMemoryCacheAdapterProvider.js","sourceRoot":"","sources":["../../src/LocalMemoryCacheAdapterProvider.ts"],"names":[],"mappings":";;;AAAA,yCAMsB;AAEtB,yEAAyF;AAKzF;;;GAGG;AACH,MAAa,+BAA+B;IAwBL;IAvBrC;;OAEG;IACH,MAAM,CAAC,kBAAkB;QACvB,OAAO,IAAI,+BAA+B,CAAC,GAAwC,EAAE,CACnF,mDAAwB,CAAC,eAAe,EAAW,CACpD,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,8BAA8B,CACnC,YAAqC;QAErC,OAAO,IAAI,+BAA+B,CAAC,YAAY,CAAC,CAAC;IAC3D,CAAC;IAEgB,0BAA0B,GAAG,IAAI,GAAG,EAGlD,CAAC;IAEJ,YAAqC,uBAAgD;QAAhD,4BAAuB,GAAvB,uBAAuB,CAAyB;IAAG,CAAC;IAElF,eAAe,CACpB,mBAA2D;QAE3D,OAAO,IAAA,wBAAe,EAAC,IAAI,CAAC,0BAA0B,EAAE,mBAAmB,CAAC,SAAS,EAAE,GAAG,EAAE;YAC1F,MAAM,gBAAgB,GAAG,IAAI,CAAC,uBAAuB,EAAW,CAAC;YACjE,OAAO,IAAI,kCAAyB,CAClC,IAAI,mDAAwB,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CACpE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AApCD,0EAoCC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/entity-cache-adapter-local-memory",
3
- "version": "0.51.0",
3
+ "version": "0.54.0",
4
4
  "description": "Cross-request local memory cache adapter for @expo/entity",
5
5
  "files": [
6
6
  "build",
@@ -28,14 +28,13 @@
28
28
  "author": "Expo",
29
29
  "license": "MIT",
30
30
  "dependencies": {
31
- "@expo/entity": "^0.51.0",
32
- "lru-cache": "^6.0.0"
31
+ "@expo/entity": "^0.54.0"
33
32
  },
34
33
  "devDependencies": {
35
- "@expo/entity-testing-utils": "^0.51.0",
36
- "@jest/globals": "^30.2.0",
37
- "@types/lru-cache": "^5.1.1",
38
- "typescript": "^5.9.3"
34
+ "@expo/entity-testing-utils": "^0.54.0",
35
+ "@isaacs/ttlcache": "2.1.4",
36
+ "@jest/globals": "30.2.0",
37
+ "typescript": "5.9.3"
39
38
  },
40
- "gitHead": "9140938e1cd20bab7e89224b9e5670e963d735d9"
39
+ "gitHead": "283c02eedbd4f5721afad96f31ada85bf92afb41"
41
40
  }
@@ -6,47 +6,62 @@ import {
6
6
  IEntityLoadKey,
7
7
  IEntityLoadValue,
8
8
  } from '@expo/entity';
9
- import LRUCache from 'lru-cache';
10
9
 
11
10
  // Sentinel value we store in local memory to negatively cache a database miss.
12
11
  // The sentinel value is distinct from any (positively) cached value.
13
12
  export const DOES_NOT_EXIST_LOCAL_MEMORY_CACHE = Symbol('doesNotExist');
13
+
14
+ /**
15
+ * Type of value stored in the local memory cache. This is either the cached fields, or the
16
+ * DOES_NOT_EXIST_LOCAL_MEMORY_CACHE sentinel value.
17
+ */
14
18
  export type LocalMemoryCacheValue<TFields extends Record<string, any>> =
15
19
  | Readonly<TFields>
16
20
  | typeof DOES_NOT_EXIST_LOCAL_MEMORY_CACHE;
17
- export type LocalMemoryCache<TFields extends Record<string, any>> = LRUCache<
18
- string,
19
- LocalMemoryCacheValue<TFields>
20
- >;
21
+
22
+ /**
23
+ * Interface for a local memory cache used by GenericLocalMemoryCacher. Most often, this is something like
24
+ * a TTLCache from the `@isaacs/ttlcache` package or an lru-cache.
25
+ */
26
+ export interface ILocalMemoryCache<TFields extends Record<string, any>> {
27
+ /**
28
+ * Gets a value from the cache for specified key.
29
+ * @param key - key to get
30
+ * @returns the cached value, or undefined if not present
31
+ */
32
+ get(key: string): LocalMemoryCacheValue<TFields> | undefined;
33
+
34
+ /**
35
+ * Sets a value in the cache for specified key.
36
+ * @param key - key to set
37
+ * @param value - value to set
38
+ */
39
+ set(key: string, value: LocalMemoryCacheValue<TFields>): void;
40
+
41
+ /**
42
+ * Deletes a value from the cache for specified key.
43
+ * @param key - key to delete
44
+ */
45
+ delete(key: string): void;
46
+ }
21
47
 
22
48
  export class GenericLocalMemoryCacher<
23
49
  TFields extends Record<string, any>,
24
50
  TIDField extends keyof TFields,
25
- > implements IEntityGenericCacher<TFields, TIDField>
26
- {
51
+ > implements IEntityGenericCacher<TFields, TIDField> {
27
52
  constructor(
28
53
  private readonly entityConfiguration: EntityConfiguration<TFields, TIDField>,
29
- private readonly localMemoryCache: LocalMemoryCache<TFields>,
54
+ private readonly localMemoryCache: ILocalMemoryCache<TFields>,
30
55
  ) {}
31
56
 
32
- static createLRUCache<TFields extends Record<string, any>>(
33
- options: { maxSize?: number; ttlSeconds?: number } = {},
34
- ): LocalMemoryCache<TFields> {
35
- const DEFAULT_LRU_CACHE_MAX_AGE_SECONDS = 10;
36
- const DEFAULT_LRU_CACHE_SIZE = 10000;
37
- const maxAgeSeconds = options.ttlSeconds ?? DEFAULT_LRU_CACHE_MAX_AGE_SECONDS;
38
- return new LRUCache<string, LocalMemoryCacheValue<TFields>>({
39
- max: options.maxSize ?? DEFAULT_LRU_CACHE_SIZE,
40
- length: (value) => (value === DOES_NOT_EXIST_LOCAL_MEMORY_CACHE ? 0 : 1),
41
- maxAge: maxAgeSeconds * 1000, // convert to ms
42
- });
43
- }
44
-
45
- static createNoOpCache<TFields extends Record<string, any>>(): LocalMemoryCache<TFields> {
46
- return new LRUCache<string, LocalMemoryCacheValue<TFields>>({
47
- max: 0,
48
- maxAge: -1,
49
- });
57
+ static createNoOpCache<TFields extends Record<string, any>>(): ILocalMemoryCache<TFields> {
58
+ return {
59
+ get(_key: string): LocalMemoryCacheValue<TFields> | undefined {
60
+ return undefined;
61
+ },
62
+ set(_key: string, _value: LocalMemoryCacheValue<TFields>): void {},
63
+ delete(_key: string): void {},
64
+ };
50
65
  }
51
66
 
52
67
  public async loadManyAsync(
@@ -87,7 +102,7 @@ export class GenericLocalMemoryCacher<
87
102
 
88
103
  public async invalidateManyAsync(keys: readonly string[]): Promise<void> {
89
104
  for (const key of keys) {
90
- this.localMemoryCache.del(key);
105
+ this.localMemoryCache.delete(key);
91
106
  }
92
107
  }
93
108
 
@@ -6,15 +6,18 @@ import {
6
6
  IEntityCacheAdapterProvider,
7
7
  } from '@expo/entity';
8
8
 
9
- import { GenericLocalMemoryCacher, LocalMemoryCache } from './GenericLocalMemoryCacher';
9
+ import { GenericLocalMemoryCacher, ILocalMemoryCache } from './GenericLocalMemoryCacher';
10
10
 
11
+ export type LocalMemoryCacheCreator = <
12
+ TFields extends Record<string, any>,
13
+ >() => ILocalMemoryCache<TFields>;
11
14
  /**
12
15
  * Vends local memory cache adapters. An instance of this class may be shared across requests to
13
16
  * share the local memory cache.
14
17
  */
15
18
  export class LocalMemoryCacheAdapterProvider implements IEntityCacheAdapterProvider {
16
19
  /**
17
- * @returns a no-op local memory cache adapter provider, or one that doesn't cache locally.
20
+ * @returns a no-op local memory cache adapter provider, or one that doesn't cache at all.
18
21
  */
19
22
  static createNoOpProvider(): IEntityCacheAdapterProvider {
20
23
  return new LocalMemoryCacheAdapterProvider(<TFields extends Record<string, any>>() =>
@@ -23,14 +26,12 @@ export class LocalMemoryCacheAdapterProvider implements IEntityCacheAdapterProvi
23
26
  }
24
27
 
25
28
  /**
26
- * @returns a local memory cache adapter provider configured with the supplied options.
29
+ * @returns a local memory cache adapter provider configured with the supplied local memory cache creator function.
27
30
  */
28
- static createProviderWithOptions(
29
- options: { maxSize?: number; ttlSeconds?: number } = {},
31
+ static createProviderWithCacheCreator(
32
+ cacheCreator: LocalMemoryCacheCreator,
30
33
  ): IEntityCacheAdapterProvider {
31
- return new LocalMemoryCacheAdapterProvider(<TFields extends Record<string, any>>() =>
32
- GenericLocalMemoryCacher.createLRUCache<TFields>(options),
33
- );
34
+ return new LocalMemoryCacheAdapterProvider(cacheCreator);
34
35
  }
35
36
 
36
37
  private readonly localMemoryCacheAdapterMap = new Map<
@@ -38,11 +39,7 @@ export class LocalMemoryCacheAdapterProvider implements IEntityCacheAdapterProvi
38
39
  GenericEntityCacheAdapter<any, any>
39
40
  >();
40
41
 
41
- private constructor(
42
- private readonly localMemoryCacheCreator: <
43
- TFields extends Record<string, any>,
44
- >() => LocalMemoryCache<TFields>,
45
- ) {}
42
+ private constructor(private readonly localMemoryCacheCreator: LocalMemoryCacheCreator) {}
46
43
 
47
44
  public getCacheAdapter<TFields extends Record<string, any>, TIDField extends keyof TFields>(
48
45
  entityConfiguration: EntityConfiguration<TFields, TIDField>,
@@ -4,11 +4,26 @@ import {
4
4
  NoOpEntityMetricsAdapter,
5
5
  } from '@expo/entity';
6
6
  import { StubDatabaseAdapterProvider, StubQueryContextProvider } from '@expo/entity-testing-utils';
7
+ import { TTLCache } from '@isaacs/ttlcache';
7
8
 
9
+ import { ILocalMemoryCache, LocalMemoryCacheValue } from '../GenericLocalMemoryCacher';
8
10
  import { LocalMemoryCacheAdapterProvider } from '../LocalMemoryCacheAdapterProvider';
9
11
 
10
12
  const queryContextProvider = new StubQueryContextProvider();
11
13
 
14
+ function createTTLCache<TFields extends Record<string, any>>(
15
+ options: { maxSize?: number; ttlSeconds?: number } = {},
16
+ ): ILocalMemoryCache<TFields> {
17
+ const DEFAULT_LRU_CACHE_MAX_AGE_SECONDS = 10;
18
+ const DEFAULT_LRU_CACHE_SIZE = 10000;
19
+ const maxAgeSeconds = options.ttlSeconds ?? DEFAULT_LRU_CACHE_MAX_AGE_SECONDS;
20
+ return new TTLCache<string, LocalMemoryCacheValue<TFields>>({
21
+ max: options.maxSize ?? DEFAULT_LRU_CACHE_SIZE,
22
+ ttl: maxAgeSeconds * 1000, // convert to ms
23
+ updateAgeOnGet: true,
24
+ });
25
+ }
26
+
12
27
  export const createLocalMemoryTestEntityCompanionProvider = (
13
28
  localMemoryOptions: { maxSize?: number; ttlSeconds?: number } = {},
14
29
  metricsAdapter: IEntityMetricsAdapter = new NoOpEntityMetricsAdapter(),
@@ -16,7 +31,9 @@ export const createLocalMemoryTestEntityCompanionProvider = (
16
31
  const localMemoryCacheAdapterProvider =
17
32
  localMemoryOptions.maxSize === 0 && localMemoryOptions.ttlSeconds === 0
18
33
  ? LocalMemoryCacheAdapterProvider.createNoOpProvider()
19
- : LocalMemoryCacheAdapterProvider.createProviderWithOptions(localMemoryOptions);
34
+ : LocalMemoryCacheAdapterProvider.createProviderWithCacheCreator(() =>
35
+ createTTLCache(localMemoryOptions),
36
+ );
20
37
  return new EntityCompanionProvider(
21
38
  metricsAdapter,
22
39
  new Map([
@@ -7,11 +7,14 @@ import {
7
7
  SingleFieldValueHolderMap,
8
8
  UUIDField,
9
9
  } from '@expo/entity';
10
+ import { TTLCache } from '@isaacs/ttlcache';
10
11
  import { describe, expect, it } from '@jest/globals';
11
12
 
12
13
  import {
13
14
  DOES_NOT_EXIST_LOCAL_MEMORY_CACHE,
14
15
  GenericLocalMemoryCacher,
16
+ ILocalMemoryCache,
17
+ LocalMemoryCacheValue,
15
18
  } from '../GenericLocalMemoryCacher';
16
19
 
17
20
  type BlahFields = {
@@ -28,41 +31,19 @@ const entityConfiguration = new EntityConfiguration<BlahFields, 'id'>({
28
31
  cacheAdapterFlavor: 'local-memory',
29
32
  });
30
33
 
31
- describe(GenericLocalMemoryCacher, () => {
32
- describe(GenericLocalMemoryCacher.createLRUCache, () => {
33
- it('creates a cache with default options', () => {
34
- const cache = GenericLocalMemoryCacher.createLRUCache();
35
- expect(cache.max).toBe(10000);
36
- expect(cache.maxAge).toBe(10000);
37
- });
38
-
39
- it('respects specified options', () => {
40
- const cache = GenericLocalMemoryCacher.createLRUCache({
41
- ttlSeconds: 3,
42
- maxSize: 10,
43
- });
44
- expect(cache.max).toBe(10);
45
- expect(cache.maxAge).toBe(3000);
46
- });
34
+ function createTTLCache<TFields extends Record<string, any>>(): ILocalMemoryCache<TFields> {
35
+ return new TTLCache<string, LocalMemoryCacheValue<TFields>>({
36
+ max: 10000,
37
+ ttl: 10 * 1000, // convert to ms
38
+ updateAgeOnGet: true,
47
39
  });
48
-
49
- describe(GenericLocalMemoryCacher.createNoOpCache, () => {
50
- it('creates a no-op cache', () => {
51
- const cache = GenericLocalMemoryCacher.createNoOpCache<{ hello: 'world' }>();
52
- cache.set('a', { hello: 'world' });
53
- expect(cache.get('a')).toBeUndefined();
54
- });
55
- });
56
- });
40
+ }
57
41
 
58
42
  describe('Use within GenericEntityCacheAdapter', () => {
59
43
  describe('loadManyAsync', () => {
60
44
  it('returns appropriate cache results', async () => {
61
45
  const cacheAdapter = new GenericEntityCacheAdapter(
62
- new GenericLocalMemoryCacher(
63
- entityConfiguration,
64
- GenericLocalMemoryCacher.createLRUCache(),
65
- ),
46
+ new GenericLocalMemoryCacher(entityConfiguration, createTTLCache()),
66
47
  );
67
48
 
68
49
  const cacheHits = new Map<SingleFieldValueHolder<BlahFields, 'id'>, Readonly<BlahFields>>([
@@ -97,10 +78,7 @@ describe('Use within GenericEntityCacheAdapter', () => {
97
78
 
98
79
  it('returns empty map when passed empty array of values', async () => {
99
80
  const cacheAdapter = new GenericEntityCacheAdapter(
100
- new GenericLocalMemoryCacher(
101
- entityConfiguration,
102
- GenericLocalMemoryCacher.createLRUCache(),
103
- ),
81
+ new GenericLocalMemoryCacher(entityConfiguration, createTTLCache()),
104
82
  );
105
83
  const results = await cacheAdapter.loadManyAsync(
106
84
  new SingleFieldHolder<BlahFields, 'id', 'id'>('id'),
@@ -112,7 +90,7 @@ describe('Use within GenericEntityCacheAdapter', () => {
112
90
 
113
91
  describe('cacheManyAsync', () => {
114
92
  it('correctly caches all objects', async () => {
115
- const localMemoryCache = GenericLocalMemoryCacher.createLRUCache<BlahFields>({});
93
+ const localMemoryCache = createTTLCache<BlahFields>();
116
94
 
117
95
  const localMemoryCacher = new GenericLocalMemoryCacher(entityConfiguration, localMemoryCache);
118
96
  const cacheAdapter = new GenericEntityCacheAdapter(localMemoryCacher);
@@ -133,7 +111,7 @@ describe('Use within GenericEntityCacheAdapter', () => {
133
111
 
134
112
  describe('cacheDBMissesAsync', () => {
135
113
  it('correctly caches misses', async () => {
136
- const localMemoryCache = GenericLocalMemoryCacher.createLRUCache<BlahFields>({});
114
+ const localMemoryCache = createTTLCache<BlahFields>();
137
115
 
138
116
  const localMemoryCacher = new GenericLocalMemoryCacher(entityConfiguration, localMemoryCache);
139
117
  const cacheAdapter = new GenericEntityCacheAdapter(localMemoryCacher);
@@ -151,7 +129,7 @@ describe('Use within GenericEntityCacheAdapter', () => {
151
129
 
152
130
  describe('invalidateManyAsync', () => {
153
131
  it('invalidates correctly', async () => {
154
- const localMemoryCache = GenericLocalMemoryCacher.createLRUCache<BlahFields>({});
132
+ const localMemoryCache = createTTLCache<BlahFields>();
155
133
 
156
134
  const cacheAdapter = new GenericEntityCacheAdapter(
157
135
  new GenericLocalMemoryCacher(entityConfiguration, localMemoryCache),
@@ -182,10 +160,7 @@ describe('Use within GenericEntityCacheAdapter', () => {
182
160
 
183
161
  it('returns when passed empty array of values', async () => {
184
162
  const cacheAdapter = new GenericEntityCacheAdapter(
185
- new GenericLocalMemoryCacher(
186
- entityConfiguration,
187
- GenericLocalMemoryCacher.createLRUCache<BlahFields>({}),
188
- ),
163
+ new GenericLocalMemoryCacher(entityConfiguration, createTTLCache<BlahFields>()),
189
164
  );
190
165
  await cacheAdapter.invalidateManyAsync(
191
166
  new SingleFieldHolder<BlahFields, 'id', 'id'>('id'),