Prisma, Drizzle ORM & Kysely
How to seamlessly integrate Cachemate with modern Node.js ORMs and query builders.
1. Drizzle ORM Integration
Drizzle ORM uses TypeScript schema definitions that map directly to database tables.
src/db/cache.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { eq, and } from 'drizzle-orm';
import { Client, type TableRegistry } from 'cachemate';
import { users, posts, comments } from './schema';
const registry: TableRegistry = {
entries: {
users: { tag: 'u', versionKey: 'cm:ver:users' },
posts: { tag: 'p', versionKey: 'cm:ver:posts' },
comments: { tag: 'c', versionKey: 'cm:ver:comments' },
},
};
export const client = new Client({
memoryMaxMb: 128,
redisUrls: [process.env.REDIS_URL!],
registry,
});
// Caching Drizzle Relational Queries
export async function getPostWithAuthor(postId: string) {
return await client.cache({
tables: ['posts', 'users', 'comments'],
filters: { postId },
ttlSeconds: 300,
loader: async () => {
return await db.query.posts.findFirst({
where: eq(posts.id, postId),
with: {
author: true,
comments: {
with: { author: true },
},
},
});
},
});
}
2. Prisma Client Extension Pattern
You can extend Prisma Client using $extends to auto-cache model queries:
src/db/prisma.ts
import { PrismaClient } from '@prisma/client';
import { Client } from 'cachemate';
const cachemate = new Client({
memoryMaxMb: 128,
redisUrls: [process.env.REDIS_URL!],
registry: {
entries: {
User: { tag: 'u', versionKey: 'cm:ver:users' },
Post: { tag: 'p', versionKey: 'cm:ver:posts' },
},
},
});
export const prisma = new PrismaClient().$extends({
model: {
user: {
async findCachedUnique(args: any) {
return await cachemate.cache({
tables: ['User'],
filters: args,
loader: async () => {
return await (prisma as any).user.findUnique(args);
},
});
},
},
},
});
3. Kysely Type-Safe SQL Query Builder
src/db/kysely.ts
import { Kysely, PostgresDialect } from 'kysely';
import { client } from './cache';
import type { Database } from './types';
export const db = new Kysely<Database>({
dialect: new PostgresDialect({ /* ... */ }),
});
export async function getActiveUsers() {
return await client.cache({
tables: ['users', 'roles'],
filters: { status: 'active' },
loader: async () => {
return await db
.selectFrom('users')
.innerJoin('roles', 'roles.id', 'users.role_id')
.select(['users.id', 'users.name', 'roles.name as roleName'])
.where('users.status', '=', 'active')
.execute();
},
});
}