Database Query Caching
Cache expensive database queries using the @cached decorator.
Basic Pattern
import { cached } from '@humanspeak/memory-cache'
class UserRepository {
@cached<User | null>({ ttl: 60000 }) // 1 minute
async findById(id: string): Promise<User | null> {
return await prisma.user.findUnique({
where: { id },
include: { profile: true, posts: true }
})
}
@cached<User[]>({ ttl: 30000, maxSize: 50 }) // 30 seconds
async findByOrganization(orgId: string): Promise<User[]> {
return await prisma.user.findMany({
where: { organizationId: orgId },
orderBy: { createdAt: 'desc' }
})
}
}
const repo = new UserRepository()
// First call hits database
const user = await repo.findById('user-123')
// Second call returns cached result
const cachedUser = await repo.findById('user-123')import { cached } from '@humanspeak/memory-cache'
class UserRepository {
@cached<User | null>({ ttl: 60000 }) // 1 minute
async findById(id: string): Promise<User | null> {
return await prisma.user.findUnique({
where: { id },
include: { profile: true, posts: true }
})
}
@cached<User[]>({ ttl: 30000, maxSize: 50 }) // 30 seconds
async findByOrganization(orgId: string): Promise<User[]> {
return await prisma.user.findMany({
where: { organizationId: orgId },
orderBy: { createdAt: 'desc' }
})
}
}
const repo = new UserRepository()
// First call hits database
const user = await repo.findById('user-123')
// Second call returns cached result
const cachedUser = await repo.findById('user-123')With Hooks for Query Monitoring
import { cached } from '@humanspeak/memory-cache'
class UserRepository {
@cached<User | null>({
ttl: 60000,
hooks: {
onHit: ({ key }) => {
metrics.increment('db.cache.hit', { query: 'findById' })
},
onMiss: ({ key }) => {
metrics.increment('db.cache.miss', { query: 'findById' })
}
}
})
async findById(id: string): Promise<User | null> {
const start = Date.now()
const result = await prisma.user.findUnique({ where: { id } })
metrics.timing('db.query.duration', Date.now() - start)
return result
}
}import { cached } from '@humanspeak/memory-cache'
class UserRepository {
@cached<User | null>({
ttl: 60000,
hooks: {
onHit: ({ key }) => {
metrics.increment('db.cache.hit', { query: 'findById' })
},
onMiss: ({ key }) => {
metrics.increment('db.cache.miss', { query: 'findById' })
}
}
})
async findById(id: string): Promise<User | null> {
const start = Date.now()
const result = await prisma.user.findUnique({ where: { id } })
metrics.timing('db.query.duration', Date.now() - start)
return result
}
}Key Considerations
- TTL: Short TTLs (30s-2min) for frequently changing data
- Invalidation: Clear cache after writes to the same data
- Key Generation: The decorator uses
JSON.stringify(args)for keys