From 7e8a7173e2c10778617e64259ff1199c5bbca934 Mon Sep 17 00:00:00 2001 From: ben-pr-p Date: Fri, 17 Jan 2020 18:55:25 -0500 Subject: [PATCH] docs: a little more readme --- README.md | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/README.md b/README.md index d15a307..556cd3c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,121 @@ # redis-memoize-invalidate Redis memoization library with good Typescript generics, locking, and argument-wide bulk invalidation + +# Usage + +``` +yarn add memoredis +``` + +## Initialization + +```typescript +import memoredis from 'memoredis'; + +// pass options as they would directly to redis.createClient +const memoizer = memoredis({ clientOpts: 'redis://' }); + +// or pass in an existing client +const client = redis.createClient(); +const memoizer = memoredis({ client }); +``` + +## Basic Usage + +```typescript +const expensiveDatabaseLookup = async ({ authorId, genre }) => { + // some expensive database lookup + return { countOfBooks: n }; +}; + +const countOfBooksPublishedByAuthorInGenre = memoizer.memoize( + expensiveDatabaseLookup, + { key: 'genre-author-count', ttl: 60 * 1000 } +); + +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'fiction' }); // goes to the database +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'fiction' }); // served from redis! +``` + +## Basic Invalidation + +```typescript +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'fiction' }); // goes to the database +await memoizer.invalidate('genre-author-count', { + authorId: 4, + genre: 'fiction' +}); +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'fiction' }); // goes to the database +``` + +## Bulk Partial Invalidation + +```typescript +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'fiction' }); // goes to the database +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'biology' }); // goes to the database +await memoizer.invalidate('genre-author-count', { + authorId: 4 +}); +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'fiction' }); // goes to the database +await countOfBooksPublishedByAuthorInGenre({ authorId: 4, genre: 'biology' }); // goes to the database +``` + +## Prefixes + +```typescript +// optionally include a prefix for namespacing caches +const libraryA = memoredis({ prefix: 'a' }); +const libraryB = memoredis({ prefix: 'b' }); + +const expensiveDatabaseLookup = async ({ authorId, genre }) => { + // some expensive database lookup + console.log('Finished looking up'); + return { countOfBooks: n }; +}; + +const countOfBooksPublishedByAuthorInGenreInLibraryA = libraryA.memoize( + expensiveDatabaseLookup, + { key: 'genre-author-count', ttl: 60 * 1000 } +); + +const countOfBooksPublishedByAuthorInGenreInLibraryB = libraryA.memoize( + expensiveDatabaseLookup, + { key: 'genre-author-count', ttl: 60 * 1000 } +); + +await countOfBooksPublishedByAuthorInGenreInLibraryA({ + authorId: 4, + genre: 'fiction' +}); // goes to the database + +await countOfBooksPublishedByAuthorInGenreInLibraryB({ + authorId: 4, + genre: 'fiction' +}); // goes to the database +``` + +## Locking + +This library uses `redis-lock` under the hood to prevent two calls to the same function +at the same time, even when the cache is cold. + +```typescript +const expensiveDatabaseLookup = async ({ authorId, genre }) => { + // some expensive database lookup + console.log('Finished looking up'); + return { countOfBooks: n }; +}; + +const countOfBooksPublishedByAuthorInGenre = memoizer.memoize( + expensiveDatabaseLookup, + { key: 'genre-author-count', ttl: 60 * 1000 } +); + +const args = { authorId: 4, genre: 'fiction' }; +await Promise.all([ + countOfBooksPublishedByAuthorInGenre(args), + countOfBooksPublishedByAuthorInGenre(args) +]); +// only logs 'Finished looking up' once +```