Skip to content

paulwer/prisma-extension-cache-manager

 
 

Repository files navigation

@paulwer/prisma-extension-cache-manager

A caching extension for Prisma, fully compatible with cache-manager, predefined uncaching strategies and custom handlers for key generation and uncaching.

Features

  • full 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:

npm i @paulwer/prisma-extension-cache-manager

Usage

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 exspected.
  2. Automatic Uncaching only works when using @prisma/client. Custom generated client which are loaded from another origin/package are not supported yet.
  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 @knaus94

Learn more

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 100.0%