0.3.1 • Published 22 days ago

@seedcompany/cache v0.3.1

Weekly downloads
-
License
MIT
Repository
github
Last release
22 days ago

Yet another cache library for NestJS

This is for data that will be shared across multiple processes. Thus, the keys are strings and the values are serializable.

The goals of this library are:

  • Provide a nice interface for usage in Nestjs classes
  • Integrate easily with the existing Nestjs ecosystem
  • Leverage existing npm ecosystem for storage implementations

Setup

Import the module in your app.

CacheModule.registerAsync({
  inject: [/* config */],
  useFactory: (/* config */): CacheModuleOptions => ({
    store: // create store implementation from config
  }),
})

Usage

Decorators

@Injectable()
class Service {

  @Cache({
    key: 'foo-bar',
    ttl: { minutes: 5 },
  })
  async fooBar() {
    // ...
  }

}

However, you will probably need to cache based on the args given, so:

@Injectable()
class Service {

  @Cache((id: string, year: number) => ({
    key: `foo-bar:${id}-${year}`,
    ttl: { minutes: 5 },
  }))
  async fooBar(id: string, year: number) {
    // ...
  }

}

Service

The task you always most always want to do is skip expensive calculation if possible. So the most useful method is getOrCalculate, which saves you the boilerplate for this logic.

declare const cache: CacheService; // injected somewhere

const result = await cache.getOrCalculate({
  key: `fooBar:${id}`,
  calculate: async () => {
    // do expensive calculation
  },
  ttl: { hour: 1 },
});

Naive functionality exists as well:

await cache.get('foo');
await cache.set('foo', 'bar');
await cache.delete('foo');

Namespaces

A common use case is to namespace your cache keys, to help segment your cache store. There's a namespace method which returns a modified cache service with the given prefix.

const usersCache = cache.namespace('users:');

Note that chaining these will stack the prefixes, not override them.

cache.namespace('foo:').namespace('bar:').get('baz'); // foo:bar:baz

CacheItem

A wrapper is provided around a single cache keys as well. This could help prevent having to store another variable for a computed key, or allow it to be passed around.

const cached = cache.item('1234');
const value = cached.getOrCalculate(async () => {
  // do expensive calculation
});
handleInvalidation(cached);
function handleInvalidation(cached: CacheItem) {
  if (isStale) {
    cached.delete();
  }
}

Stores

Stores are the actual storage implementations the CacheService is backed by.

We provide stores for ioredis, keyv, lru-cache. This should cover most use cases, but you can also implement your own.

LRU / In Memory

import { LruStore } from '@seedcompany/cache/store/lru';

CacheModule.register({
  store: new LruStore({
    // options
  })
})

Redis

import { RedisStore } from '@seedcompany/cache/store/redis';
import Redis from 'ioredis';

CacheModule.register({
  store: new RedisStore(
    new Redis('redis://localhost:6379')
  )
})

Keyv

import { KeyvStore } from '@seedcompany/cache/store/keyv';
import Keyv from 'keyv';

CacheModule.register({
  store: new KeyvStore(
    new Keyv()
  )
})

Chaining Multiple Stores

Multiple stores can be chained together with the ChainStore. This could provide faster in memory cache falling back to a shared network cache.

import { ChainStore } from '@seedcompany/cache/store/chain';

CacheModule.register({
  store: new ChainStore([
    new LruStore({ max: 100 }),
    new RedisStore(),
  ])
})

Adapters

We provide a few adapters to help integrate with other libraries.

NestJS Cache Manager

Here's how to set up the NestJS Cache Manager module to be based on this one.

import { CacheModule as NestHttpCacheModule } from '@nestjs/cache-manager';
import { CacheModule, CacheService } from '@seedcompany/cache';

NestHttpCacheModule.registerAsync({
  imports: [CacheModule],
  inject: [CacheService],
  useFactory: (cache: CacheService): CacheModuleOptions => ({
    store: cache.namespace('http:').adaptTo.cacheManager(),
  }),
});

Continue on with the NestJS docs: https://docs.nestjs.com/techniques/caching#interacting-with-the-cache-store

Apollo Cache

Here's how to set up the Apollo cache to be based on this one.

GraphQLModule.forRootAsync<ApolloDriverConfig>({
  driver: ApolloDriver,
  imports: [CacheModule],
  inject: [CacheService],
  useFactory: (cache: CacheService) => ({
    cache: cache.namespace('apollo:').adaptTo.apollo(),
  }),
});

Keyv Cache

Keyv cache is a very popular cache library. Here's how to adapt our cache to its interface.

declare const cache: CacheService;

const kv = new Keyv({
  store: cache.adaptTo.keyv(),
});
0.3.1

22 days ago

0.3.0

10 months ago

0.2.0

1 year ago

0.1.9

1 year ago

0.1.8

1 year ago

0.1.7

1 year ago

0.1.6

1 year ago

0.1.5

1 year ago

0.1.1

1 year ago

0.1.0

1 year ago