CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sequelize

Promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Amazon Redshift and Snowflake's Data Cloud with solid transaction support, relations, eager and lazy loading, read replication and more

Pending
Overview
Eval results
Files

hooks.mddocs/

Hooks

Lifecycle event system for extending model and query behavior with customizable hooks that execute at specific points during database operations.

Capabilities

Instance Lifecycle Hooks

Hooks that execute during individual model instance operations.

/**
 * Validation hooks
 */
interface ValidationHooks {
  /** Before instance validation */
  beforeValidate: (instance: Model, options: ValidationOptions) => Promise<void> | void;
  /** After successful validation */
  afterValidate: (instance: Model, options: ValidationOptions) => Promise<void> | void;
  /** When validation fails */
  validationFailed: (instance: Model, options: ValidationOptions, error: ValidationError) => Promise<void> | void;
}

/**
 * Create/Update/Save hooks
 */
interface CRUDHooks {
  /** Before creating new instance */
  beforeCreate: (instance: Model, options: CreateOptions) => Promise<void> | void;
  /** After creating new instance */
  afterCreate: (instance: Model, options: CreateOptions) => Promise<void> | void;
  
  /** Before updating instance */
  beforeUpdate: (instance: Model, options: UpdateOptions) => Promise<void> | void;
  /** After updating instance */
  afterUpdate: (instance: Model, options: UpdateOptions) => Promise<void> | void;
  
  /** Before saving (create or update) */
  beforeSave: (instance: Model, options: SaveOptions) => Promise<void> | void;
  /** After saving (create or update) */
  afterSave: (instance: Model, options: SaveOptions) => Promise<void> | void;
  
  /** Before destroying instance */
  beforeDestroy: (instance: Model, options: InstanceDestroyOptions) => Promise<void> | void;
  /** After destroying instance */
  afterDestroy: (instance: Model, options: InstanceDestroyOptions) => Promise<void> | void;
  
  /** Before restoring soft-deleted instance */
  beforeRestore: (instance: Model, options: RestoreOptions) => Promise<void> | void;
  /** After restoring soft-deleted instance */
  afterRestore: (instance: Model, options: RestoreOptions) => Promise<void> | void;
  
  /** Before upserting */
  beforeUpsert: (values: any, options: UpsertOptions) => Promise<void> | void;
  /** After upserting */
  afterUpsert: (result: [Model, boolean], options: UpsertOptions) => Promise<void> | void;
}

Usage Examples:

// Define hooks in model definition
class User extends Model {}
User.init({
  firstName: DataTypes.STRING,
  lastName: DataTypes.STRING,
  email: DataTypes.STRING,
  hashedPassword: DataTypes.STRING,
  lastLoginAt: DataTypes.DATE
}, {
  sequelize,
  modelName: 'user',
  hooks: {
    // Hash password before creating user
    beforeCreate: async (user, options) => {
      if (user.password) {
        user.hashedPassword = await bcrypt.hash(user.password, 10);
        delete user.password;
      }
    },
    
    // Update login timestamp after creation
    afterCreate: async (user, options) => {
      console.log(`User ${user.email} created at ${new Date()}`);
    },
    
    // Hash password before updates too
    beforeUpdate: async (user, options) => {
      if (user.changed('password')) {
        user.hashedPassword = await bcrypt.hash(user.password, 10);
        delete user.password;
      }
    },
    
    // Log validation failures
    validationFailed: (user, options, error) => {
      console.log(`Validation failed for user: ${error.message}`);
    }
  }
});

// Add hooks after model definition
User.addHook('beforeSave', async (user, options) => {
  user.email = user.email.toLowerCase();
});

User.addHook('afterDestroy', (user, options) => {
  console.log(`User ${user.email} was deleted`);
});

Bulk Operation Hooks

Hooks that execute during bulk database operations.

/**
 * Bulk operation hooks
 */
interface BulkHooks {
  /** Before bulk create operation */
  beforeBulkCreate: (instances: Model[], options: BulkCreateOptions) => Promise<void> | void;
  /** After bulk create operation */
  afterBulkCreate: (instances: Model[], options: BulkCreateOptions) => Promise<void> | void;
  
  /** Before bulk update operation */
  beforeBulkUpdate: (options: UpdateOptions) => Promise<void> | void;
  /** After bulk update operation */
  afterBulkUpdate: (options: UpdateOptions) => Promise<void> | void;
  
  /** Before bulk destroy operation */
  beforeBulkDestroy: (options: DestroyOptions) => Promise<void> | void;
  /** After bulk destroy operation */
  afterBulkDestroy: (options: DestroyOptions) => Promise<void> | void;
  
  /** Before bulk restore operation */
  beforeBulkRestore: (options: RestoreOptions) => Promise<void> | void;
  /** After bulk restore operation */
  afterBulkRestore: (options: RestoreOptions) => Promise<void> | void;
  
  /** Before bulk sync operation */
  beforeBulkSync: (options: SyncOptions) => Promise<void> | void;
  /** After bulk sync operation */
  afterBulkSync: (options: SyncOptions) => Promise<void> | void;
}

Usage Examples:

// Bulk operation hooks
User.addHook('beforeBulkCreate', (instances, options) => {
  console.log(`About to create ${instances.length} users`);
  
  // Modify all instances before creation
  instances.forEach(user => {
    user.email = user.email.toLowerCase();
    user.createdAt = new Date();
  });
});

User.addHook('afterBulkUpdate', (options) => {
  console.log('Bulk update completed');
  
  // Clear cache after bulk operations
  cache.clear('users');
});

User.addHook('beforeBulkDestroy', (options) => {
  // Log what's about to be deleted
  console.log('About to delete users matching:', options.where);
});

Query Hooks

Hooks that execute around database query operations.

/**
 * Query-related hooks
 */
interface QueryHooks {
  /** Before find operations */
  beforeFind: (options: FindOptions) => Promise<void> | void;
  /** After find operations */
  afterFind: (instances: Model | Model[] | null, options: FindOptions) => Promise<void> | void;
  
  /** Before count operations */
  beforeCount: (options: CountOptions) => Promise<void> | void;
  
  /** Before find, after include expansion */
  beforeFindAfterExpandIncludeAll: (options: FindOptions) => Promise<void> | void;
  /** Before find, after options processing */
  beforeFindAfterOptions: (options: FindOptions) => Promise<void> | void;
  
  /** Before any SQL query execution */
  beforeQuery: (options: QueryOptions, query: string) => Promise<void> | void;
  /** After any SQL query execution */
  afterQuery: (options: QueryOptions, query: string) => Promise<void> | void;
}

Usage Examples:

// Query hooks for caching and logging
User.addHook('beforeFind', (options) => {
  console.log('Finding users with options:', options);
  
  // Add default ordering if not specified
  if (!options.order) {
    options.order = [['createdAt', 'DESC']];
  }
});

User.addHook('afterFind', (result, options) => {
  if (Array.isArray(result)) {
    console.log(`Found ${result.length} users`);
  } else if (result) {
    console.log(`Found user: ${result.email}`);
  } else {
    console.log('No user found');
  }
});

// Global query logging
sequelize.addHook('beforeQuery', (options, query) => {
  console.time('query');
  console.log('Executing query:', query);
});

sequelize.addHook('afterQuery', (options, query) => {
  console.timeEnd('query');
});

Model Definition Hooks

Hooks that execute during model definition and association setup.

/**
 * Model definition hooks
 */
interface ModelDefinitionHooks {
  /** Before model definition */
  beforeDefine: (attributes: ModelAttributes, options: DefineOptions) => Promise<void> | void;
  /** After model definition */
  afterDefine: (model: typeof Model) => Promise<void> | void;
  
  /** Before model initialization */
  beforeInit: (attributes: ModelAttributes, options: InitOptions) => Promise<void> | void;
  /** After model initialization */
  afterInit: (model: typeof Model) => Promise<void> | void;
  
  /** Before association setup */
  beforeAssociate: (model: typeof Model, associations: any) => Promise<void> | void;
  /** After association setup */
  afterAssociate: (model: typeof Model, associations: any) => Promise<void> | void;
}

Usage Examples:

// Model definition hooks
sequelize.addHook('beforeDefine', (attributes, options) => {
  // Automatically add timestamps if not present
  if (!options.timestamps && !attributes.createdAt) {
    attributes.createdAt = DataTypes.DATE;
    attributes.updatedAt = DataTypes.DATE;
    options.timestamps = true;
  }
});

sequelize.addHook('afterDefine', (model) => {
  console.log(`Model ${model.name} defined with attributes:`, Object.keys(model.getAttributes()));
});

Connection and Sync Hooks

Hooks that execute during database connection and synchronization operations.

/**
 * Connection and sync hooks
 */
interface ConnectionSyncHooks {
  /** Before database connection */
  beforeConnect: (config: any) => Promise<void> | void;
  /** After database connection */
  afterConnect: (connection: any, config: any) => Promise<void> | void;
  
  /** Before connection disconnect */
  beforeDisconnect: (connection: any) => Promise<void> | void;
  /** After connection disconnect */
  afterDisconnect: (connection: any) => Promise<void> | void;
  
  /** Before connection pool acquire */
  beforePoolAcquire: (config: any) => Promise<void> | void;
  /** After connection pool acquire */
  afterPoolAcquire: (connection: any, config: any) => Promise<void> | void;
  
  /** Before database sync */
  beforeSync: (options: SyncOptions) => Promise<void> | void;
  /** After database sync */
  afterSync: (options: SyncOptions) => Promise<void> | void;
}

Usage Examples:

// Connection hooks
sequelize.addHook('beforeConnect', (config) => {
  console.log('Attempting to connect to database:', config.database);
});

sequelize.addHook('afterConnect', (connection, config) => {
  console.log('Successfully connected to database');
});

sequelize.addHook('beforeSync', (options) => {
  console.log('Starting database synchronization');
});

sequelize.addHook('afterSync', (options) => {
  console.log('Database synchronization completed');
});

Hook Management

Adding and Removing Hooks

Methods for managing hooks dynamically.

/**
 * Add hook to model or sequelize instance
 * @param hookType - Type of hook
 * @param name - Hook name (optional)
 * @param fn - Hook function
 */
addHook(hookType: string, name: string, fn: Function): void;
addHook(hookType: string, fn: Function): void;

/**
 * Remove hook from model or sequelize instance
 * @param hookType - Type of hook
 * @param name - Hook name
 */
removeHook(hookType: string, name: string): boolean;

/**
 * Check if hook exists
 * @param hookType - Type of hook
 * @param name - Hook name
 */
hasHook(hookType: string, name?: string): boolean;

/**
 * Run hooks manually
 * @param hookType - Type of hook
 * @param args - Arguments to pass to hooks
 */
runHooks(hookType: string, ...args: any[]): Promise<void>;

Usage Examples:

// Named hooks can be removed later
User.addHook('beforeCreate', 'hashPassword', async (user, options) => {
  user.hashedPassword = await bcrypt.hash(user.password, 10);
});

User.addHook('beforeCreate', 'setDefaults', (user, options) => {
  user.isActive = user.isActive !== false;
  user.role = user.role || 'user';
});

// Remove specific hook
User.removeHook('beforeCreate', 'hashPassword');

// Check if hook exists
if (User.hasHook('beforeCreate', 'setDefaults')) {
  console.log('setDefaults hook is active');
}

// Run hooks manually
await User.runHooks('beforeCreate', userInstance, options);

Hook Options and Context

Advanced hook configuration and context access.

/**
 * Hook function signature with context
 */
type HookFunction<T = any> = (
  this: typeof Model | Model,
  ...args: any[]
) => Promise<void> | void;

/**
 * Hook options
 */
interface HookOptions {
  /** Hook priority (higher runs first) */
  priority?: number;
  /** Hook context */
  context?: any;
}

Usage Examples:

// Hook with priority (higher priority runs first)
User.addHook('beforeCreate', 'validation', async function(user, options) {
  // Validation logic
}, { priority: 100 });

User.addHook('beforeCreate', 'defaults', function(user, options) {
  // Set defaults (runs after validation)
}, { priority: 50 });

// Access model context in hook
User.addHook('afterFind', function(result, options) {
  // 'this' refers to the User model
  console.log(`Query executed on ${this.name} model`);
});

// Instance method with hook context
User.addHook('beforeSave', function(user, options) {
  // 'this' refers to the model class
  console.log(`Saving ${this.name} instance`);
});

Common Hook Patterns

Audit Trail Pattern

Automatic tracking of data changes.

// Audit trail implementation
class AuditLog extends Model {}
AuditLog.init({
  tableName: DataTypes.STRING,
  recordId: DataTypes.INTEGER,
  action: DataTypes.ENUM('CREATE', 'UPDATE', 'DELETE'),
  oldValues: DataTypes.JSON,
  newValues: DataTypes.JSON,
  userId: DataTypes.INTEGER,
  timestamp: DataTypes.DATE
}, { sequelize, modelName: 'auditLog' });

// Add audit hooks to User model
User.addHook('afterCreate', async (user, options) => {
  await AuditLog.create({
    tableName: 'users',
    recordId: user.id,
    action: 'CREATE',
    newValues: user.toJSON(),
    userId: options.userId,
    timestamp: new Date()
  });
});

User.addHook('afterUpdate', async (user, options) => {
  await AuditLog.create({
    tableName: 'users',
    recordId: user.id,
    action: 'UPDATE',
    oldValues: user._previousDataValues,
    newValues: user.dataValues,
    userId: options.userId,
    timestamp: new Date()
  });
});

User.addHook('afterDestroy', async (user, options) => {
  await AuditLog.create({
    tableName: 'users',
    recordId: user.id,
    action: 'DELETE',
    oldValues: user.toJSON(),
    userId: options.userId,
    timestamp: new Date()
  });
});

Caching Pattern

Automatic cache invalidation.

// Cache management hooks
const cache = new Map();

User.addHook('afterCreate', (user, options) => {
  // Invalidate user list cache
  cache.delete('users:list');
  cache.delete(`users:${user.id}`);
});

User.addHook('afterUpdate', (user, options) => {
  // Invalidate specific user cache
  cache.delete(`users:${user.id}`);
  cache.delete('users:list');
});

User.addHook('afterDestroy', (user, options) => {
  // Remove from cache
  cache.delete(`users:${user.id}`);
  cache.delete('users:list');
});

User.addHook('afterFind', (result, options) => {
  // Cache found results
  if (Array.isArray(result)) {
    cache.set('users:list', result);
  } else if (result) {
    cache.set(`users:${result.id}`, result);
  }
});

Validation and Sanitization Pattern

Data cleaning and validation.

// Comprehensive validation and sanitization
User.addHook('beforeValidate', (user, options) => {
  // Trim whitespace
  if (user.firstName) user.firstName = user.firstName.trim();
  if (user.lastName) user.lastName = user.lastName.trim();
  if (user.email) user.email = user.email.trim().toLowerCase();
  
  // Remove extra spaces
  if (user.bio) user.bio = user.bio.replace(/\s+/g, ' ').trim();
});

User.addHook('beforeSave', async (user, options) => {
  // Encrypt sensitive data
  if (user.changed('socialSecurityNumber')) {
    user.socialSecurityNumber = await encrypt(user.socialSecurityNumber);
  }
  
  // Generate slugs
  if (user.changed('firstName') || user.changed('lastName')) {
    user.slug = slugify(`${user.firstName}-${user.lastName}`);
  }
});

Notification Pattern

Event-driven notifications.

// Notification system
User.addHook('afterCreate', async (user, options) => {
  // Send welcome email
  await emailService.sendWelcomeEmail(user.email, {
    firstName: user.firstName
  });
  
  // Create notification
  await Notification.create({
    userId: user.id,
    type: 'welcome',
    message: 'Welcome to our platform!',
    isRead: false
  });
});

User.addHook('afterUpdate', async (user, options) => {
  // Notify on important changes
  if (user.changed('email')) {
    await emailService.sendEmailChangeNotification(
      user.previous('email'),
      user.email
    );
  }
  
  if (user.changed('password')) {
    await emailService.sendPasswordChangeNotification(user.email);
  }
});

Install with Tessl CLI

npx tessl i tessl/npm-sequelize

docs

associations.md

data-types.md

database-connection.md

error-handling.md

hooks.md

index.md

model-definition.md

query-operators.md

querying.md

transactions.md

tile.json