@paulwer/prisma-extension-cache-manager
Version:
A caching extension for [Prisma](https://www.prisma.io/), fully compatible with [cache-manager](https://www.npmjs.com/package/cache-manager), predefined uncaching strategies and custom handlers for key generation and uncaching.
156 lines (121 loc) • 5.61 kB
Markdown
# /prisma-extension-cache-manager
A caching extension for [Prisma](https://www.prisma.io/), fully compatible with [cache-manager](https://www.npmjs.com/package/cache-manager), predefined uncaching strategies and custom handlers for key generation and uncaching.
## Features
- full [cache-manager](https://www.npmjs.com/package/cache-manager) compatibility => also supports external storages like redis (see cache-manager)
- Model queries and custom queries are cacheable (additional methods $queryRawCached or $queryRawUnsafeCached)
- Automatic uncaching strategy
- Namespaces for separate caching ttl
- Custom keys for custom caching strategies
- Cache-Keys and Uncache-Keys can be handled with a custom function after data fetching
- Deduplicate concurrent queries
## Installation
Install:
```cmd
npm i /prisma-extension-cache-manager
```
## Usage
```typescript
import { PrismaClient } from "@prisma/client";
import * as cm from "cache-manager";
import cacheExtension from "@paulwer/prisma-extension-cache-manager";
async function main() {
const cache = await cm.caching("memory", {
ttl: 10000,
max: 200,
});
const prisma = new PrismaClient().$extends(
cacheExtension({ cache, useAutoUncaching: true }),
);
await prisma.user.findUniqueOrThrow({
where: {
email: user.email,
},
cache: true, // using cache default settings
});
await prisma.user.findMany({
cache: 5000, // setting ttl in milliseconds
});
await prisma.user.count({
cache: {
ttl: 2000,
key: "user_count", // custom cache key
},
});
await prisma.user.count({
cache: {
ttl: 24 * 60 * 60 * 1000,
namespace: "pricing_tier1", // custom namespace for custom ttls
},
});
await prisma.user.update({
data: {},
cache: {
ttl: 2000,
key: (result) => `user-${result.id}`, // custom cache key by result (There will be no reading from the cache, only a write down)
},
});
await prisma.user.create({
data: {},
uncache: `user_count`, // delete key from cache
});
await prisma.user.create({
data: {},
cache: {
ttl: 2000,
key: (result) => `user-${result.id}`, // custom cache key by result (There will be no reading from the cache, only a write down)
},
uncache: [`user_count`, `users`], // delete keys from cache
});
// Custom Queries
await prisma.$queryRawCached(
Prisma.sql`SELECT * FROM "User" WHERE id = ${1}`,
{
cache: {
namespace: "test",
ttl: 2000,
key: (result) => `user-${result[0].id}`, // custom cache key by result (There will be no reading from the cache, only a write down)
},
uncache: [`user_count`, `users`], // delete keys from cache
},
);
await prisma.$queryRawUnsafeCached(
Prisma.sql`SELECT * FROM "User" WHERE id = 1`,
{
cache: "custom_query1",
uncache: {
namespace: "test", // delete keys from cache
},
},
);
}
main().catch(console.error);
```
## Customize Caching
### Caching Key
By default this extension will create a cache-key in the format of `<namespace?>:<model>:<operation>@<args-hash>`.
You can customize this behavior by providing one or both of the following parameters. Both parameters can also be computed by a function which gets passed the result of the query for even more customization options.
**namespace** By providing a namespace you can prefix the key and handle seperate caching ttls.
**key** By providing a custom key you can define how the caching key is generated. When using a custom key, the cache key will be generated as following: `<key>` or `<namespace>:<key>`.
### Automatic Uncaching
When a write-operation was performed on a model, all cache-data for this model will be removed. We also support nested write operations.
**Important Notice:** This will only work for the default caching keys.
### Deduplication
When using deduplication a map of running promisses is kept on your local server to deduplicate requests with the same cache-key.
**Important Notice:** Deduplication is not supported for custom key functions as they determine the cache-key after the execution.
### TTL
You can customize the ttl of the cache key. The plugin will use the first ttl only when originaly creating the cache entry.
### (De-)Serialization
This plugin serialize/deserialize some classes used by prisma to string with a prefix to deserialize it back when using cache later. You can customize this behavior by passing the prefixes property to the plugin while initialization.
## Planned features
- more granular automatic uncaching
- performance improvements for uncaching
## Limitations & Important Considderations
1. Be carefull when using custom cache-keys and automatic-uncaching. If you produce an overlay it could happen, that more cache entries gets deleted than expected.
2. Automatic Uncaching only works when using /client. For custom clients, you have to provide the current instance in the settings.
3. when using custom key generator functions, you cannot rely on a cache for this function. Those should only be used to generate the cache for other functions.
## Credit
Original Implementation by [](https://github.com/knaus94)
## Learn more
- [Docs — Client extensions](https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions)
- [Docs — Shared extensions](https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions/shared-extensions)
- [Credit: Original Repository](https://github.com/@knaus94/prisma-extension-cache-manager)