README.md
<div align="center">
<h1 align="center"><a aria-label="soluble/cache-interop" href="https://github.com/soluble-io/cache-interop">cache-interop</a></h1>
<p align="center">Interoperable cache adapters for node and browsers.</p>
</div>
<p align="center">
<a aria-label="Build" href="https://github.com/soluble-io/cache-interop/actions?query=workflow%3ACI">
<img alt="GitHub branch checks state" src="https://img.shields.io/github/checks-status/soluble-io/cache-interop/main?label=CI&logo=github&style=for-the-badge">
</a>
<a aria-label="Codecov" href="https://codecov.io/gh/soluble-io/cache-interop">
<img alt="Codecov" src="https://img.shields.io/codecov/c/github/soluble-io/cache-interop?logo=codecov&style=for-the-badge&labelColor=000000" />
</a>
<a aria-label="Codefactor grade" href="https://www.codefactor.io/repository/github/soluble-io/cache-interop">
<img alt="Codefactor" src="https://img.shields.io/codefactor/grade/github/soluble-io/cache-interop?label=Codefactor&logo=codefactor&style=for-the-badge&labelColor=000000" />
</a>
<a aria-label="CodeClimate maintainability" href="https://codeclimate.com/github/soluble-io/cache-interop">
<img alt="Maintainability" src="https://img.shields.io/codeclimate/maintainability/soluble-io/cache-interop?label=Maintainability&logo=code-climate&style=for-the-badge&labelColor=000000" />
</a>
<a aria-label="CodeClimate technical debt" href="https://codeclimate.com/github/soluble-io/cache-interop">
<img alt="Techdebt" src="https://img.shields.io/codeclimate/tech-debt/soluble-io/cache-interop?label=TechDebt&logo=code-climate&style=for-the-badge&labelColor=000000" />
</a>
<a aria-label="Downloads" href="https://npm.im/@soluble/cache-interop">
<img alt="Downloads" src="https://img.shields.io/npm/dt/@soluble/cache-interop?style=for-the-badge&labelColor=000000" />
</a>
<a aria-label="Ts LoC" href="https://github.com/soluble-io/cache-interop/search?l=typescript">
<img alt="TS LoC" src="https://img.shields.io/tokei/lines/github/soluble-io/cache-interop?logo=typescript&style=for-the-badge&labelColor=000000" />
</a>
<a aria-label="Licence" href="https://github.com/soluble-io/cache-interop/blob/main/LICENSE">
<img alt="Licence" src="https://img.shields.io/npm/l/@soluble/cache-ioredis?style=for-the-badge&labelColor=000000" />
</a>
</p>
# About | [Documentation](https://github.com/soluble-io/cache-interop/)
> **Warning** Before v1 is released expect breaking changes in API
## Features
- [x] Simple but powerful [API](./packages/cache-interop/src/cache.interface.ts).
- [x] Native promises /`async`/`await`.
- [x] Don't throw errors.
- [x] Typescript friendly.
- [x] High quality & covergae, see [e2e](packages/cache-e2e-tests/test/suites) tests.
- [x] Multiple adapters: node-redis, ioredis.
## Roadmap
- [ ] Finalize v1 API
- [ ] injectable LoggerInterface
- [ ] SerializerInterface (json, msgpack, gzip, marshaller, superjson)
- [ ] Chainable serializer (json -> gzip...)
- [ ] Cache manager
- [ ] Chainable cache adapter (allows lru as L1, redis as L2)
- [ ] Adapters
- [ ] lru-cache
- [ ] Documentation
## Contracts
| package | targets | description | Info |
| -------------------------------------------------- | ---------------- | --------------------------------------- | ---------------------------------------------------------------------------- |
| [@soluble/cache-interop](./packages/cache-interop) | `node`,`browser` | Interoperability interfaces & contracts | ![npm](https://img.shields.io/npm/dm/@soluble/cache-interop?label=%E2%87%A9) |
## Adapters
| package | targets | description | Info |
| -------------------------------------------------- | ------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| [@soluble/cache-ioredis](./packages/cache-ioredis) | `node` | Adapter for [ioredis](https://github.com/luin/ioredis) driver | ![npm](https://img.shields.io/npm/dm/@soluble/cache-ioredis?label=%E2%87%A9) |
| [@soluble/cache-redis](./packages/cache-redis) | `node` | Adapter for [node-redis](https://github.com/NodeRedis/node-redis) driver | ![npm](https://img.shields.io/npm/dm/@soluble/cache-redis?label=%E2%87%A9) |
## Utils
| package | targets | description | Info |
| -------------------------------------------- | ---------------- | --------------------------- | ------------------------------------------------------------------------- |
| [@soluble/dsn-parser](./packages/dsn-parser) | `node`,`browser` | Tiny and relaxed DSN parser | ![npm](https://img.shields.io/npm/dm/@soluble/dsn-parser?label=%E2%87%A9) |
### At a glance
```typescript
import { IoRedisCacheAdapter } from "@soluble/cache-ioredis";
const cache = new IoRedisCacheAdapter({
connection: "redis://localhost:6375",
});
const getSomething = async () => JSON.stringify({ success: true });
const { data, error } = await cache.getOrSet(
// Cache key
"cacke-key-v-1",
// Async function
getSomething,
// GetOrSetOptions
{ ttl: 3600 }
);
if (error instanceof Error) {
throw error;
}
let parsed;
try {
parsed = JSON.parse(data);
} catch (e) {
throw new SerializerException(e.message);
}
```
## Diagram
```mermaid
classDiagram
CacheInterface <|-- AbstractCacheAdapter
CacheInterface: +getOrSet(key, valueOrFn, options) CacheItemInterface
CacheInterface: +get(key, options) CacheItemInterface
CacheInterface: +set(key, valueOrFn, options) boolean|CacheException
CacheInterface: +has(key, options) boolean|undefined
CacheInterface: +delete(key, options) boolean|CacheException
CacheInterface: +getMultiple(keys, options) Map
CacheInterface: +setMultiple(keyVals, options) Map
CacheInterface: +deleteMultiple(keys, options) Map
CacheInterface: +clear() true|CacheException
class AbstractCacheAdapter {
+string adapterName
+getOrSet() CacheItemInterface
+getMultiple(keyVals, options) Map
+setMultiple(keyVals, options) Map
+deleteMultiple(keys, options) Map
}
ConnectedCacheInterface <|-- RedisCacheAdapter
ConnectedCacheInterface <|-- IoRedisCacheAdapter
class ConnectedCacheInterface {
+getConnection() ConnectionInterface
}
AbstractCacheAdapter <|-- IoRedisCacheAdapter
class IoRedisCacheAdapter {
+IoRedisConnection conn
+string adapterName
}
AbstractCacheAdapter <|-- MapCacheAdapter
class MapCacheAdapter {
+string adapterName
}
AbstractCacheAdapter <|-- RedisCacheAdapter
class RedisCacheAdapter {
+RedisConnection conn
+string adapterName
}
class ConnectionInterface {
+getNativeConnection()
+quit()
}
ConnectionInterface <|-- IoRedisConnection
class IoRedisConnection {
+quit()
}
ConnectionInterface <|-- RedisConnection
class RedisConnection {
+quit()
}
```
## Options
| GetOrSetOptions | target | default | description |
| --------------- | ------------------------------------------- | ------- | ------------------------------------------------------------- |
| `ttl` | `number` | 0 | Time-To-Live in seconds since Epoch time. If zero, no expiry. |
| `disableCache` | `boolean`/`{read: boolean, write: boolean}` | false | Disable cache |
## Structure
This monorepo holds the various adapters, the contracts for interoperability and the e2e tests.
```
./packages
├── dsn-parser
│ └── # @soluble/dsn-parser: utility for parsing connection dsn #
├── cache-interop
│ └── # @soluble/cache-interop: cache interoperability contracts #
├── cache-ioredis
│ └── # @soluble/cache-ioredis: ioredis adapter implementation #
├── cache-redis
│ └── # @soluble/cache-redis: node redis adapter implementation #
└── cache-e2e-tests
└── # e2e test suite for all adapters #
```
### Inspiration
- [PSR-6](https://www.php-fig.org/psr/psr-6/) - PHP Cache interface standard recommendation.
- [PSR-16](https://www.php-fig.org/psr/psr-6/) - PHP SimpleCache interface standard recommendation.
- [Symfony cache](https://github.com/symfony/cache) - Symfony cache component.
- [Node-cache-manager](https://github.com/BryanDonovan/node-cache-manager) - Flexible NodeJS cache module.
- [C# getOrSet](https://csharp.hotexamples.com/examples/Microsoft.Framework.Caching.Memory/MemoryCache/GetOrSet/php-memorycache-getorset-method-examples.html) - C# Memory::getOrSet() method.
- [SWR](https://swr.vercel.app/) - React Hooks library for data fetching
### Acknowledgements
- [microbundle](https://github.com/developit/microbundle) - Zero-configuration bundler for tiny modules.
- [node-testcontainers](https://github.com/testcontainers/testcontainers-node) - Ephemeral docker instances to facilitate e2e on various services (redis...)
- [atlassian/changesets](https://github.com/atlassian/changesets) - To ease pain with monorepo versioning.
### Special thanks to
<table>
<tr>
<td>
<a href="https://www.jetbrains.com/?ref=belgattitude" target="_blank">
<img width="65" src="https://asset.brandfetch.io/idarKiKkI-/id53SttZhi.jpeg" alt="Jetbrains logo" />
</a>
</td>
<td>
<a href="https://www.embie.be/?ref=belgattitude" target="_blank">
<img width="65" src="https://avatars.githubusercontent.com/u/98402122?s=200&v=4" alt="Jetbrains logo" />
</a>
</td>
</tr>
<tr>
<td>
<a href="https://www.jetbrains.com/?ref=belgattitude" target="_blank">JetBrains</a>
</td>
<td>
<a href="https://www.embie.be/?ref=belgattitude" target="_blank">Embie.be</a>
</td>
</tr>
</table>