Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support sync cache creation #598

Merged
merged 4 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

strategy:
matrix:
node-version: ['16', '18', '20']
node-version: ['18', '20']

steps:
- uses: actions/checkout@v3
Expand Down
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,32 @@ You can use your own custom store by creating one with the same API as the built
- [Example Custom Store redis](https://github.com/node-cache-manager/node-cache-manager-redis-yet)
- [Example Custom Store ioredis](https://github.com/node-cache-manager/node-cache-manager-ioredis-yet)

#### Create single cache store synchronously

As `caching()` requires async functionality to resolve some stores, this is not well-suited to use for default function/constructor parameters etc.

If you need to create a cache store synchronously, you can instead use `createCache()`:

```typescript
import { createCache, memoryStore } from 'node-cache-manager';

// Create memory cache synchronously
const memoryCache = createCache(memoryStore(), {
max: 100,
ttl: 10 * 1000 /*milliseconds*/,
});

// Default parameter in function
function myService(cache = createCache(memoryStore())) {}

// Default parameter in class constructor
const DEFAULT_CACHE = createCache(memoryStore(), { ttl: 60 * 1000 });
// ...
class MyService {
constructor(private cache = DEFAULT_CACHE) {}
}
```

### Multi-Store

```typescript
Expand Down
35 changes: 28 additions & 7 deletions src/caching.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { coalesceAsync } from 'promise-coalesce';
import { MemoryCache, MemoryConfig, memoryStore } from './stores';
import { MemoryCache, MemoryConfig, MemoryStore, memoryStore } from './stores';

export type Config = {
ttl?: Milliseconds;
Expand Down Expand Up @@ -63,13 +63,34 @@ export async function caching<S extends Store, T extends object = never>(
export async function caching<S extends Store, T extends object = never>(
factory: Stores<S, T>,
args?: CachingConfig<T>,
): Promise<Cache<S> | MemoryCache> {
let store: Store;
if (factory === 'memory') store = memoryStore(args as MemoryConfig);
else if (typeof factory === 'function')
store = await factory(args as FactoryConfig<T>);
else store = factory;
): Promise<Cache<S> | Cache<Store> | MemoryCache> {
if (factory === 'memory') {
const store = memoryStore(args as MemoryConfig);
return createCache(store, args as MemoryConfig);
}
if (typeof factory === 'function') {
const store = await factory(args as FactoryConfig<T>);
return createCache(store, args);
}

const store = factory;
return createCache(store, args);
}

export function createCache(
store: MemoryStore,
args?: MemoryConfig,
): MemoryCache;

export function createCache(store: Store, args?: Config): Cache<Store>;

/**
* Create cache instance by store (non-async).
*/
export function createCache<S extends Store, C extends Config>(
store: S,
args?: C,
): Cache<S> {
return {
/**
* Wraps a function in cache. I.e., the first time the function is run,
Expand Down
14 changes: 13 additions & 1 deletion test/caching.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { faker } from '@faker-js/faker';
import promiseCoalesce from 'promise-coalesce';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { Cache, MemoryConfig, caching, memoryStore } from '../src';
import { caching, Cache, MemoryConfig, memoryStore, createCache } from '../src';
import { sleep } from './utils';

// Allow the module to be mocked so we can assert
Expand Down Expand Up @@ -389,3 +389,15 @@ describe('caching', () => {
});
});
});

describe('createCache', () => {
it('should create cache instance by store', async () => {
const store = memoryStore();
const cache1 = await caching(store);
const cache2 = createCache(store);
expect(cache1.store).toBe(cache2.store);
Object.entries(cache1).forEach(([key, value]) => {
expect(cache2[key as keyof Cache].toString()).toBe(value.toString());
});
});
});