Drizzle CRUD/Advanced
Lifecycle Hooks
Add custom business logic with lifecycle hooks in Drizzle CRUD
Lifecycle Hooks
Lifecycle hooks allow you to inject custom business logic at specific points in the CRUD operations lifecycle. This is perfect for adding timestamps, validation, transformations, and other business rules.
Available Hooks
Data Transformation Hooks
beforeCreate
- Transform data before creatingbeforeUpdate
- Transform data before updating
Validation Hooks
validate
- Custom validation logic
Operation Hooks
beforeOperation
- Run before any operationafterOperation
- Run after any operation
Basic Usage
const userCrud = createCrud(users, {
hooks: {
beforeCreate: (data) => ({
...data,
email: data.email.toLowerCase(),
createdAt: new Date(),
}),
beforeUpdate: (data) => ({
...data,
updatedAt: new Date(),
}),
validate: ({ data, context, operation }) => {
// Custom validation logic
return !context?.skipValidation
},
},
})
Data Transformation Hooks
Before Create
Transform data before insertion:
const userCrud = createCrud(users, {
hooks: {
beforeCreate: (data) => ({
...data,
// Normalize email
email: data.email.toLowerCase().trim(),
// Generate slug from name
slug: data.name.toLowerCase().replace(/\s+/g, '-'),
// Set default values
isActive: data.isActive ?? true,
createdAt: new Date(),
}),
},
})
Before Update
Transform data before updating:
const postCrud = createCrud(posts, {
hooks: {
beforeUpdate: (data) => ({
...data,
// Update slug if title changed
slug: data.title
? data.title.toLowerCase().replace(/\s+/g, '-')
: undefined,
// Always update timestamp
updatedAt: new Date(),
}),
},
})
Validation Hooks
Custom validation beyond schema validation:
const userCrud = createCrud(users, {
hooks: {
validate: ({ data, context, operation }) => {
// Skip validation for trusted sources
if (context?.skipValidation) {
return true
}
// Custom business rules
if (operation === 'create' && data.email) {
const isValidDomain = data.email.endsWith('@company.com')
if (!isValidDomain) {
throw new Error('Only company email addresses are allowed')
}
}
// Age validation
if (data.age && data.age < 13) {
throw new Error('Users must be at least 13 years old')
}
return true
},
},
})
Hook Context
Hooks receive context information:
interface HookContext {
operation: 'create' | 'update' | 'delete' | 'list' | 'findById'
data?: any // The data being operated on
result?: any // The result (for after hooks)
originalData?: any // Original data (for update operations)
context?: OperationContext // The operation context
}
Using Hook Context
const smartCrud = createCrud(articles, {
hooks: {
beforeCreate: (data, { context }) => {
// Set author from actor
if (context?.actor?.type === 'user') {
data.authorId = context.actor.properties.userId
}
return data
},
validate: ({ data, context, operation }) => {
return context?.skipValidation ?? true
},
},
})
Next Steps
- Validation - Custom validation schemas
- Transactions - Database transactions
- Soft Deletes - Soft delete configuration