Hooks & Lifecycle Events

Use hooks and events to run custom logic at key points in the data lifecycle

Available Hooks

Stabilize supports these lifecycle hooks:

hooks/types.ts
// Available hook types:
// - beforeCreate - Before a record is created
// - afterCreate - After a record is created
// - beforeUpdate - Before a record is updated
// - afterUpdate - After a record is updated
// - beforeDelete - Before a record is deleted
// - afterDelete - After a record is deleted
// - beforeSave - Before create OR update
// - afterSave - After create OR update

Event Listeners

Listen to ORM events for logging and monitoring:

examples/events.ts
import { Stabilize, StabilizeEmitter } from "stabilize-orm";
// connection:open fires from the constructor, before a handler registered on
// orm.events afterwards could exist. Build the emitter, subscribe, then pass it
// as the fifth argument.
const events = new StabilizeEmitter();
events.on("connection:open", (dbType) => {
console.log(`Connected to ${dbType}`);
});
const orm = new Stabilize(
dbConfig,
{ enabled: false, ttl: 60 },
{},
undefined, // no shared client
events,
);
orm.events.on("connection:close", () => {
console.log("Database connection closed");
});
// Every other event can be subscribed to normally, in any order.
orm.events.on("query", ({ dbType, query, params, executionTime }) => {
console.log(`${dbType} ${query} in ${executionTime}ms`, params);
});
// "phase" says which of the three sources raised it: "query", "transaction"
// or "migration".
orm.events.on("error", ({ phase, error }) => {
console.error(`Database error during ${phase}:`, error);
});
orm.events.on("transaction:start", ({ dbType }) => {
console.log(`Transaction started on ${dbType}`);
});
orm.events.on("transaction:complete", ({ dbType }) => {
console.log(`Transaction committed on ${dbType}`);
});
orm.events.on("transaction:error", ({ dbType, error }) => {
console.error(`Transaction rolled back on ${dbType}:`, error);
});
orm.events.on("migration:start", ({ name, index, total }) => {
console.log(`Migration ${index}/${total} started: ${name}`);
});
orm.events.on("migration:complete", ({ name, index, total }) => {
console.log(`Migration ${index}/${total} complete: ${name}`);
});

Practical Hook Patterns

examples/hook-patterns.ts
// Logging pattern - log all create operations
const userRepo = orm.getRepository(User);
const originalCreate = userRepo.create.bind(userRepo);
userRepo.create = async (entity, options) => {
console.log("Creating user:", entity.email);
const result = await originalCreate(entity, options);
console.log("Created user with ID:", result.id);
return result;
};
// Validation pattern - extra validation before save
const orderRepo = orm.getRepository(Order);
const originalUpdate = orderRepo.update.bind(orderRepo);
orderRepo.update = async (id, entity) => {
if (entity.status === "shipped" && !entity.trackingNumber) {
throw new Error("Tracking number required for shipped orders");
}
return originalUpdate(id, entity);
};
// Audit pattern - track who made changes
const postRepo = orm.getRepository(Post);
orm.events.on("query", (entry) => {
if (entry.query.includes("UPDATE") || entry.query.includes("INSERT")) {
console.log("Audit:", {
query: entry.query,
timestamp: new Date().toISOString(),
duration: entry.durationMs,
});
}
});

Middleware Pattern

examples/middleware.ts
// Create a middleware wrapper for repositories
function withLogging<T>(repo: any, tableName: string) {
const wrap = (method: string) => {
const original = repo[method].bind(repo);
repo[method] = async (...args: any[]) => {
const start = performance.now();
const result = await original(...args);
const ms = (performance.now() - start).toFixed(1);
console.log(`[${tableName}] ${method} completed in ${ms}ms`);
return result;
};
};
["create", "update", "delete", "findOne"].forEach(wrap);
return repo;
}
// Usage
const userRepo = withLogging(orm.getRepository(User), "users");
const postRepo = withLogging(orm.getRepository(Post), "posts");
// Now all operations are automatically logged
await userRepo.create({ id: "1", name: "Test" });
// [users] create completed in 2.3ms