Sequelize Samples

Sequelize Node.js ORM with model definitions, associations, migrations, queries, and database operations

Key Facts

Category
Database
Items
4
Format Families
sql, text

Sample Overview

Sequelize Node.js ORM with model definitions, associations, migrations, queries, and database operations This sample set belongs to Database and can be used to test related workflows inside Elysia Tools.

💻 Sequelize Model Definition javascript

🟢 simple

Database models, relationships, and schema definitions with Sequelize

const { Sequelize, DataTypes, Model, Op } = require('sequelize')

// Initialize Sequelize connection
const sequelize = new Sequelize({
  dialect: 'postgres',
  host: 'localhost',
  port: 5432,
  database: 'myapp',
  username: 'postgres',
  password: 'password',
  logging: console.log,
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
})

// User Model
class User extends Model {}
User.init({
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  email: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true,
    validate: {
      isEmail: true
    }
  },
  username: {
    type: DataTypes.STRING,
    allowNull: true,
    unique: true,
    validate: {
      len: [3, 30]
    }
  },
  password: {
    type: DataTypes.STRING,
    allowNull: false,
    validate: {
      len: [6, 100]
    }
  },
  firstName: {
    type: DataTypes.STRING,
    allowNull: true
  },
  lastName: {
    type: DataTypes.STRING,
    allowNull: true
  },
  isActive: {
    type: DataTypes.BOOLEAN,
    defaultValue: true
  },
  role: {
    type: DataTypes.ENUM('USER', 'ADMIN', 'MODERATOR', 'AUTHOR'),
    defaultValue: 'USER'
  },
  lastLoginAt: {
    type: DataTypes.DATE,
    allowNull: true
  },
  profilePicture: {
    type: DataTypes.STRING,
    allowNull: true
  }
}, {
  sequelize,
  modelName: 'User',
  tableName: 'users',
  timestamps: true,
  indexes: [
    {
      unique: true,
      fields: ['email']
    },
    {
      fields: ['username']
    },
    {
      fields: ['isActive']
    }
  ]
})

// Profile Model
class Profile extends Model {}
Profile.init({
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  userId: {
    type: DataTypes.INTEGER,
    allowNull: false,
    unique: true,
    references: {
      model: User,
      key: 'id'
    }
  },
  bio: {
    type: DataTypes.TEXT,
    allowNull: true
  },
  avatar: {
    type: DataTypes.STRING,
    allowNull: true
  },
  website: {
    type: DataTypes.STRING,
    allowNull: true,
    validate: {
      isUrl: true
    }
  },
  birthDate: {
    type: DataTypes.DATEONLY,
    allowNull: true
  },
  phone: {
    type: DataTypes.STRING,
    allowNull: true
  },
  address: {
    type: DataTypes.JSON,
    allowNull: true
  }
}, {
  sequelize,
  modelName: 'Profile',
  tableName: 'profiles'
})

// Post Model
class Post extends Model {}
Post.init({
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  title: {
    type: DataTypes.STRING,
    allowNull: false,
    validate: {
      len: [1, 200]
    }
  },
  slug: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true
  },
  content: {
    type: DataTypes.TEXT,
    allowNull: false
  },
  excerpt: {
    type: DataTypes.STRING,
    allowNull: true
  },
  publishedAt: {
    type: DataTypes.DATE,
    allowNull: true
  },
  status: {
    type: DataTypes.ENUM('DRAFT', 'PUBLISHED', 'ARCHIVED'),
    defaultValue: 'DRAFT'
  },
  featuredImage: {
    type: DataTypes.STRING,
    allowNull: true
  },
  tags: {
    type: DataTypes.JSON,
    allowNull: true,
    defaultValue: []
  },
  viewCount: {
    type: DataTypes.INTEGER,
    defaultValue: 0
  },
  metadata: {
    type: DataTypes.JSON,
    allowNull: true
  }
}, {
  sequelize,
  modelName: 'Post',
  tableName: 'posts',
  indexes: [
    {
      fields: ['authorId']
    },
    {
      fields: ['status']
    },
    {
      fields: ['publishedAt']
    },
    {
      fields: ['slug']
    }
  ]
})

// Comment Model
class Comment extends Model {}
Comment.init({
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  content: {
    type: DataTypes.TEXT,
    allowNull: false,
    validate: {
      len: [1, 1000]
    }
  },
  postId: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: Post,
      key: 'id'
    }
  },
  authorId: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: User,
      key: 'id'
    }
  },
  parentId: {
    type: DataTypes.INTEGER,
    allowNull: true,
    references: {
      model: 'comments',
      key: 'id'
    }
  },
  isApproved: {
    type: DataTypes.BOOLEAN,
    defaultValue: false
  }
}, {
  sequelize,
  modelName: 'Comment',
  tableName: 'comments',
  indexes: [
    {
      fields: ['postId']
    },
    {
      fields: ['authorId']
    },
    {
      fields: ['parentId']
    }
  ]
})

// Category Model
class Category extends Model {}
Category.init({
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  name: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true
  },
  description: {
    type: DataTypes.TEXT,
    allowNull: true
  },
  slug: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true
  },
  color: {
    type: DataTypes.STRING,
    allowNull: true
  },
  icon: {
    type: DataTypes.STRING,
    allowNull: true
  }
}, {
  sequelize,
  modelName: 'Category',
  tableName: 'categories'
})

// Define Associations (Relationships)
User.hasOne(Profile, {
  foreignKey: 'userId',
  as: 'profile'
})
Profile.belongsTo(User, {
  foreignKey: 'userId',
  as: 'user'
})

User.hasMany(Post, {
  foreignKey: 'authorId',
  as: 'posts'
})
Post.belongsTo(User, {
  foreignKey: 'authorId',
  as: 'author'
})

User.hasMany(Comment, {
  foreignKey: 'authorId',
  as: 'comments'
})
Comment.belongsTo(User, {
  foreignKey: 'authorId',
  as: 'author'
})

Post.hasMany(Comment, {
  foreignKey: 'postId',
  as: 'comments'
})
Comment.belongsTo(Post, {
  foreignKey: 'postId',
  as: 'post'
})

// Self-referencing relationship for nested comments
Comment.hasMany(Comment, {
  foreignKey: 'parentId',
  as: 'replies'
})
Comment.belongsTo(Comment, {
  foreignKey: 'parentId',
  as: 'parent'
})

// Many-to-Many: Posts and Categories
const PostCategory = sequelize.define('PostCategory', {
  postId: {
    type: DataTypes.INTEGER,
    references: {
      model: Post,
      key: 'id'
    }
  },
  categoryId: {
    type: DataTypes.INTEGER,
    references: {
      model: Category,
      key: 'id'
    }
  }
}, {
  tableName: 'post_categories',
  timestamps: false
})

Post.belongsToMany(Category, {
  through: PostCategory,
  foreignKey: 'postId',
  otherKey: 'categoryId',
  as: 'categories'
})

Category.belongsToMany(Post, {
  through: PostCategory,
  foreignKey: 'categoryId',
  otherKey: 'postId',
  as: 'posts'
})

// Hooks and Instance Methods
User.beforeCreate(async (user) => {
  // Hash password before creating user
  const bcrypt = require('bcrypt')
  user.password = await bcrypt.hash(user.password, 10)
})

User.prototype.comparePassword = async function(password) {
  const bcrypt = require('bcrypt')
  return await bcrypt.compare(password, this.password)
}

User.prototype.toJSON = function() {
  const values = Object.assign({}, this.get())
  delete values.password
  return values
}

Post.beforeSave(async (post) => {
  // Generate excerpt if not provided
  if (!post.excerpt && post.content) {
    post.excerpt = post.content.substring(0, 150) + '...'
  }

  // Generate slug if not provided
  if (!post.slug && post.title) {
    post.slug = post.title.toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/(^-|-$)/g, '')
  }
})

module.exports = {
  sequelize,
  User,
  Profile,
  Post,
  Comment,
  Category,
  PostCategory
}

💻 CRUD Operations javascript

🟢 simple

Complete CRUD operations, queries, and data manipulation with Sequelize

const { User, Profile, Post, Comment } = require('./models')

// CREATE Operations
async function createUser(userData) {
  try {
    const user = await User.create({
      email: userData.email,
      username: userData.username,
      password: userData.password,
      firstName: userData.firstName,
      lastName: userData.lastName,
      role: userData.role || 'USER'
    })

    return user
  } catch (error) {
    console.error('Error creating user:', error)
    throw error
  }
}

// Create user with profile
async function createUserWithProfile(userData) {
  const user = await User.create(userData, {
    include: [{
      association: User.Profile,
      as: 'profile'
    }]
  })
  return user
}

// Create multiple users
async function createMultipleUsers(usersData) {
  const users = await User.bulkCreate(usersData, {
    validate: true,
    individualHooks: true
  })
  return users
}

// READ Operations
async function getUserById(id) {
  const user = await User.findByPk(id, {
    include: [
      {
        model: Profile,
        as: 'profile'
      },
      {
        model: Post,
        as: 'posts',
        include: [
          {
            model: Comment,
            as: 'comments'
          }
        ]
      }
    ]
  })
  return user
}

async function getUserByEmail(email) {
  const user = await User.findOne({
    where: { email },
    attributes: ['id', 'email', 'username', 'firstName', 'lastName', 'role', 'createdAt']
  })
  return user
}

async function getAllUsers(options = {}) {
  const {
    page = 1,
    limit = 10,
    search,
    role,
    sortBy = 'createdAt',
    sortOrder = 'DESC'
  } = options

  const offset = (page - 1) * limit

  const where = {
    [Op.and]: []
  }

  if (search) {
    where[Op.and].push({
      [Op.or]: [
        { username: { [Op.like]: `%${search}%` } },
        { email: { [Op.like]: `%${search}%` } },
        { firstName: { [Op.like]: `%${search}%` } },
        { lastName: { [Op.like]: `%${search}%` } }
      ]
    })
  }

  if (role) {
    where[Op.and].push({ role })
  }

  where[Op.and].push({ isActive: true })

  const { count, rows } = await User.findAndCountAll({
    where,
    offset,
    limit,
    include: [
      {
        model: Profile,
        as: 'profile',
        attributes: ['bio', 'avatar', 'website']
      }
    ],
    order: [[sortBy, sortOrder.toUpperCase()]]
  })

  return {
    users: rows,
    pagination: {
      page,
      limit,
      total: count,
      pages: Math.ceil(count / limit)
    }
  }
}

// UPDATE Operations
async function updateUser(id, updateData) {
  const user = await User.update(updateData, {
    where: { id },
    returning: true,
    include: [{
      model: Profile,
      as: 'profile'
    }]
  })

  return user[1][0] // Return the updated user
}

async function updateOrCreateProfile(userId, profileData) {
  const [profile, created] = await Profile.findOrCreate({
    where: { userId },
    defaults: {
      userId,
      ...profileData
    }
  })

  if (!created) {
    await profile.update(profileData)
  }

  return profile
}

// DELETE Operations
async function deleteUser(id) {
  // Soft delete
  const user = await User.update(
    { isActive: false },
    { where: { id } }
  )
  return user
}

async function hardDeleteUser(id) {
  const user = await User.destroy({
    where: { id }
  })
  return user
}

// Complex Queries
async function getUserWithPostStats(userId) {
  const user = await User.findByPk(userId, {
    attributes: [
      'id', 'email', 'username', 'firstName', 'lastName', 'role'
    ],
    include: [
      {
        model: Post,
        as: 'posts',
        attributes: [
          'id', 'title', 'publishedAt', 'viewCount', 'status'
        ],
        include: [
          {
            model: Comment,
            as: 'comments',
            attributes: ['id'],
            required: false
          }
        ]
      }
    ]
  })

  // Add post counts
  const userWithStats = user.toJSON()
  userWithStats.stats = {
    totalPosts: user.posts.length,
    publishedPosts: user.posts.filter(p => p.status === 'PUBLISHED').length,
    totalComments: user.posts.reduce((sum, post) => sum + post.comments.length, 0),
    totalViews: user.posts.reduce((sum, post) => sum + post.viewCount, 0)
  }

  return userWithStats
}

// Advanced Search
async function searchPosts(query) {
  const posts = await Post.findAll({
    where: {
      [Op.and]: [
        {
          [Op.or]: [
            { title: { [Op.like]: `%${query}%` } },
            { content: { [Op.like]: `%${query}%` } },
            { excerpt: { [Op.like]: `%${query}%` } }
          ]
        },
        { status: 'PUBLISHED' },
        { publishedAt: { [Op.not]: null } }
      ]
    },
    include: [
      {
        model: User,
        as: 'author',
        attributes: ['id', 'username', 'firstName', 'lastName']
      },
      {
        model: Comment,
        as: 'comments',
        attributes: ['id'],
        required: false
      }
    ],
    order: [['publishedAt', 'DESC']],
    limit: 20
  })

  return posts
}

// Aggregation Queries
async function getPostAnalytics() {
  const analytics = await Post.findAll({
    attributes: [
      [sequelize.fn('COUNT', sequelize.col('id')), 'totalPosts'],
      [sequelize.fn('COUNT', sequelize.col('id')), 'publishedPosts'],
      [sequelize.fn('AVG', sequelize.col('viewCount')), 'avgViews'],
      [sequelize.fn('SUM', sequelize.col('viewCount')), 'totalViews']
    ],
    where: {
      [Op.or]: [
        { status: 'PUBLISHED' },
        { status: 'DRAFT' }
      ]
    },
    raw: true
  })

  return analytics[0]
}

// Raw SQL Queries
async function getUsersWithMostPosts() {
  const users = await sequelize.query(`
    SELECT
      u.id,
      u.username,
      u.email,
      COUNT(p.id) as post_count,
      COUNT(c.id) as comment_count
    FROM users u
    LEFT JOIN posts p ON u.id = p.author_id
    LEFT JOIN comments c ON u.id = c.author_id
    WHERE u.is_active = true
    GROUP BY u.id, u.username, u.email
    HAVING COUNT(p.id) > 0
    ORDER BY post_count DESC
    LIMIT 10
  `, {
    type: Sequelize.QueryTypes.SELECT
  })

  return users
}

// Transaction Operations
async function transferPostOwnership(postId, newAuthorId) {
  const result = await sequelize.transaction(async (t) => {
    const post = await Post.findByPk(postId, {
      include: [{
        model: User,
        as: 'author'
      }],
      transaction: t
    })

    if (!post) {
      throw new Error('Post not found')
    }

    const updatedPost = await post.update({
      authorId: newAuthorId
    }, { transaction: t })

    return {
      previousAuthor: post.author,
      updatedPost
    }
  })

  return result
}

// Bulk Operations
async function archiveOldPosts(daysOld = 365) {
  const cutoffDate = new Date()
  cutoffDate.setDate(cutoffDate.getDate() - daysOld)

  const [affectedCount] = await Post.update(
    {
      status: 'ARCHIVED',
      archivedAt: new Date()
    },
    {
      where: {
        publishedAt: {
          [Op.lt]: cutoffDate
        },
        status: 'PUBLISHED'
      }
    }
  )

  return affectedCount
}

module.exports = {
  createUser,
  createUserWithProfile,
  createMultipleUsers,
  getUserById,
  getUserByEmail,
  getAllUsers,
  updateUser,
  updateOrCreateProfile,
  deleteUser,
  hardDeleteUser,
  getUserWithPostStats,
  searchPosts,
  getPostAnalytics,
  getUsersWithMostPosts,
  transferPostOwnership,
  archiveOldPosts
}

💻 Sequelize Migrations text

🟡 intermediate

Database migrations, seeding, and version control for schema changes

// Migration Example: 20231201000001-create-users.js
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('users', {
      id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      email: {
        type: Sequelize.STRING,
        allowNull: false,
        unique: true
      },
      username: {
        type: Sequelize.STRING,
        allowNull: true,
        unique: true
      },
      password: {
        type: Sequelize.STRING,
        allowNull: false
      },
      firstName: {
        type: Sequelize.STRING,
        allowNull: true
      },
      lastName: {
        type: Sequelize.STRING,
        allowNull: true
      },
      isActive: {
        type: Sequelize.BOOLEAN,
        defaultValue: true
      },
      role: {
        type: Sequelize.ENUM('USER', 'ADMIN', 'MODERATOR', 'AUTHOR'),
        defaultValue: 'USER'
      },
      lastLoginAt: {
        type: Sequelize.DATE,
        allowNull: true
      },
      createdAt: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
      },
      updatedAt: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
      }
    })

    // Create indexes
    await queryInterface.addIndex('users', ['email'], { unique: true })
    await queryInterface.addIndex('users', ['username'])
    await queryInterface.addIndex('users', ['isActive'])
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('users')
  }
}

// Migration Example: 20231201000002-create-profiles.js
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('profiles', {
      id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      userId: {
        type: Sequelize.INTEGER,
        allowNull: false,
        unique: true,
        references: {
          model: 'users',
          key: 'id'
        },
        onUpdate: 'CASCADE',
        onDelete: 'CASCADE'
      },
      bio: {
        type: Sequelize.TEXT,
        allowNull: true
      },
      avatar: {
        type: Sequelize.STRING,
        allowNull: true
      },
      website: {
        type: Sequelize.STRING,
        allowNull: true
      },
      birthDate: {
        type: Sequelize.DATEONLY,
        allowNull: true
      },
      phone: {
        type: Sequelize.STRING,
        allowNull: true
      },
      address: {
        type: Sequelize.JSON,
        allowNull: true
      },
      createdAt: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
      },
      updatedAt: {
        type: Sequelize.DATE,
        allowNull: false,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
      }
    })

    await queryInterface.addIndex('profiles', ['userId'], { unique: true })
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('profiles')
  }
}

// Migration Example: 20231201000003-add-user-profile-field.js
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.addColumn('users', 'profilePicture', {
      type: Sequelize.STRING,
      allowNull: true
    })
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.removeColumn('users', 'profilePicture')
  }
}

// Seeders Example: 20231201000001-users-seeder.js
module.exports = {
  up: async (queryInterface, Sequelize) => {
    const bcrypt = require('bcrypt')

    const users = [
      {
        email: '[email protected]',
        username: 'admin',
        password: await bcrypt.hash('admin123', 10),
        firstName: 'Admin',
        lastName: 'User',
        role: 'ADMIN',
        isActive: true,
        createdAt: new Date(),
        updatedAt: new Date()
      },
      {
        email: '[email protected]',
        username: 'john_doe',
        password: await bcrypt.hash('password123', 10),
        firstName: 'John',
        lastName: 'Doe',
        role: 'USER',
        isActive: true,
        createdAt: new Date(),
        updatedAt: new Date()
      },
      {
        email: '[email protected]',
        username: 'jane_smith',
        password: await bcrypt.hash('password123', 10),
        firstName: 'Jane',
        lastName: 'Smith',
        role: 'AUTHOR',
        isActive: true,
        createdAt: new Date(),
        updatedAt: new Date()
      }
    ]

    await queryInterface.bulkInsert('users', users)
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.bulkDelete('users', {
      email: {
        [Sequelize.Op.in]: [
          '[email protected]',
          '[email protected]',
          '[email protected]'
        ]
      }
    })
  }
}

// Database Configuration
const { Sequelize } = require('sequelize')

const sequelize = new Sequelize({
  dialect: 'postgres',
  host: process.env.DB_HOST || 'localhost',
  port: process.env.DB_PORT || 5432,
  database: process.env.DB_NAME || 'myapp',
  username: process.env.DB_USER || 'postgres',
  password: process.env.DB_PASSWORD || 'password',
  logging: process.env.NODE_ENV === 'development' ? console.log : false,
  pool: {
    max: parseInt(process.env.DB_POOL_MAX) || 5,
    min: parseInt(process.env.DB_POOL_MIN) || 0,
    acquire: parseInt(process.env.DB_POOL_ACQUIRE) || 30000,
    idle: parseInt(process.env.DB_POOL_IDLE) || 10000
  }
})

module.exports = sequelize

💻 Sequelize Advanced Features javascript

🔴 complex

Advanced Sequelize features including transactions, scopes, hooks, and performance optimization

const { Sequelize, DataTypes, Model, Op } = require('sequelize')

// 1. Advanced Scopes
class User extends Model {
  // Instance methods
  getFullName() {
    return `${this.firstName} ${this.lastName}`
  }

  async getRecentPosts(limit = 5) {
    return await this.getPosts({
      where: {
        status: 'PUBLISHED',
        publishedAt: {
          [Op.not]: null
        }
      },
      order: [['publishedAt', 'DESC']],
      limit
    })
  }

  async deactivate() {
    return await this.update({ isActive: false })
  }
}

User.init({
  // ... fields
}, {
  sequelize,
  modelName: 'User',

  // Scopes for reusable queries
  scopes: {
    active: {
      where: { isActive: true }
    },
    admins: {
      where: { role: 'ADMIN' }
    },
    recent: (days = 30) => ({
      where: {
        createdAt: {
          [Op.gte]: new Date(Date.now() - days * 24 * 60 * 60 * 1000)
        }
      }
    }),
    withProfile: {
      include: [{
        model: Profile,
        as: 'profile'
      }]
    },
    withStats: {
      attributes: {
        include: [
          [
            sequelize.literal(`(
              SELECT COUNT(*)
              FROM posts
              WHERE posts.author_id = User.id
              AND posts.status = 'PUBLISHED'
            )`),
            'publishedPostCount'
          ],
          [
            sequelize.literal(`(
              SELECT COUNT(*)
              FROM comments
              WHERE comments.author_id = User.id
            )`),
            'commentCount'
          ]
        ]
      }
    }
  }
})

// Using scopes
async function getActiveAdminsWithStats() {
  const users = await User.scope([
    'active',
    'admins',
    'withProfile',
    'withStats'
  ]).findAll()

  return users
}

async function getRecentUsers(days = 7) {
  return await User.scope('recent', days).findAll({
    order: [['createdAt', 'DESC']]
  })
}

// 2. Advanced Hooks and Middleware
User.addHook('beforeCreate', async (user) => {
  console.log('Creating user:', user.email)

  // Additional validation
  if (user.email && user.email.endsWith('@spam.com')) {
    throw new Error('Spam emails not allowed')
  }
})

User.addHook('afterCreate', async (user) => {
  // Send welcome email
  await sendWelcomeEmail(user.email, user.getFullName())
})

User.addHook('beforeUpdate', async (user) => {
  if (user.changed('password')) {
    // Rehash password if changed
    const bcrypt = require('bcrypt')
    user.password = await bcrypt.hash(user.password, 10)
  }
})

User.addHook('afterDestroy', async (user) => {
  // Soft delete related data
  await Post.update(
    { authorId: null },
    { where: { authorId: user.id } }
  )
})

// 3. Advanced Transactions
async function complexTransaction() {
  const result = await sequelize.transaction({
    isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
    type: Sequelize.Transaction.TYPES.DEFERRED
  }, async (t) => {

    // Create user
    const user = await User.create({
      email: '[email protected]',
      password: 'password123'
    }, { transaction: t })

    // Create profile
    const profile = await Profile.create({
      userId: user.id,
      bio: 'New user bio'
    }, { transaction: t })

    // Create initial post
    const post = await Post.create({
      title: 'Welcome Post',
      content: 'My first post',
      authorId: user.id,
      status: 'PUBLISHED'
    }, { transaction: t })

    // If any operation fails, all changes are rolled back
    return { user, profile, post }
  })

  return result
}

// Parallel transactions
async function processBatchUsers(userDataArray) {
  const promises = userDataArray.map(userData =>
    sequelize.transaction(async (t) => {
      const user = await User.create(userData, { transaction: t })
      await Profile.create({
        userId: user.id,
        bio: `Bio for ${user.email}`
      }, { transaction: t })
      return user
    })
  )

  const results = await Promise.all(promises)
  return results
}

// 4. Performance Optimization

// Eager loading with nested associations
async function getPostsWithFullDetails(postIds) {
  const posts = await Post.findAll({
    where: {
      id: { [Op.in]: postIds }
    },
    include: [
      {
        model: User,
        as: 'author',
        attributes: ['id', 'username', 'firstName', 'lastName'],
        include: [{
          model: Profile,
          as: 'profile',
          attributes: ['avatar', 'bio']
        }]
      },
      {
        model: Comment,
        as: 'comments',
        include: [{
          model: User,
          as: 'author',
          attributes: ['username', 'firstName']
        }],
        where: { isApproved: true },
        required: false
      },
      {
        model: Category,
        as: 'categories',
        attributes: ['id', 'name', 'slug']
      }
    ],
    order: [
      ['publishedAt', 'DESC'],
      [{ model: Comment, as: 'comments' }, 'createdAt', 'ASC']
    ]
  })

  return posts
}

// Query optimization with limit and pagination
async function getOptimizedUserList(options = {}) {
  const { page = 1, limit = 20, search, sortBy = 'createdAt' } = options
  const offset = (page - 1) * limit

  const where = {
    isActive: true
  }

  if (search) {
    where[Op.or] = [
      { username: { [Op.iLike]: `%${search}%` } },
      { email: { [Op.iLike]: `%${search}%` } },
      [sequelize.fn('CONCAT', sequelize.col('firstName'), ' ', sequelize.col('lastName')),
       { [Op.iLike]: `%${search}%` }]
    ]
  }

  const { count, rows } = await User.findAndCountAll({
    where,
    offset,
    limit,
    attributes: ['id', 'username', 'email', 'firstName', 'lastName', 'role', 'createdAt'],
    order: [[sortBy, 'DESC']],
    include: [
      {
        model: Profile,
        as: 'profile',
        attributes: ['avatar'],
        required: false
      }
    ]
  })

  return {
    users: rows,
    pagination: {
      page,
      limit,
      total: count,
      pages: Math.ceil(count / limit)
    }
  }
}

// 5. Raw Query Optimization
async function getDashboardStats() {
  const stats = await sequelize.query(`
    SELECT
      (SELECT COUNT(*) FROM users WHERE is_active = true) as total_users,
      (SELECT COUNT(*) FROM posts WHERE status = 'PUBLISHED') as published_posts,
      (SELECT COUNT(*) FROM comments WHERE is_approved = true) as approved_comments,
      (SELECT COUNT(*) FROM categories) as total_categories,
      (SELECT AVG(view_count) FROM posts WHERE status = 'PUBLISHED') as avg_post_views,
      (SELECT
        COUNT(CASE WHEN status = 'PUBLISHED' THEN 1 END) * 100.0 / COUNT(*)
        FROM posts
        WHERE published_at >= NOW() - INTERVAL '30 days'
      ) as recent_publish_rate
  `, {
    type: Sequelize.QueryTypes.SELECT,
    plain: true
  })

  return stats
}

// 6. Caching Layer
class CacheService {
  constructor(ttl = 300) { // 5 minutes default TTL
    this.cache = new Map()
    this.ttl = ttl * 1000
  }

  set(key, value) {
    this.cache.set(key, {
      value,
      timestamp: Date.now()
    })
  }

  get(key) {
    const item = this.cache.get(key)
    if (!item) return null

    if (Date.now() - item.timestamp > this.ttl) {
      this.cache.delete(key)
      return null
    }

    return item.value
  }

  has(key) {
    return this.get(key) !== null
  }

  delete(key) {
    return this.cache.delete(key)
  }
}

const cache = new CacheService()

async function getCachedUserWithPosts(userId) {
  const cacheKey = `user_with_posts_${userId}`

  let cached = cache.get(cacheKey)
  if (cached) return cached

  const user = await User.findByPk(userId, {
    include: [
      {
        model: Post,
        as: 'posts',
        where: { status: 'PUBLISHED' },
        required: false,
        order: [['publishedAt', 'DESC']]
      }
    ]
  })

  cache.set(cacheKey, user)
  return user
}

// 7. Connection Pool Management
async function getConnectionPoolStats() {
  const pool = sequelize.connectionManager.pool

  return {
    total: pool.total,
    all: pool.all,
    waiting: pool.waiting,
    idle: pool.idle,
    used: pool.used,
    max: pool.max,
    min: pool.min
  }
}

// 8. Error Handling and Validation
class ValidationError extends Error {
  constructor(message, field) {
    super(message)
    this.name = 'ValidationError'
    this.field = field
  }
}

async function createUserWithValidation(userData) {
  try {
    // Custom validation
    if (userData.email && userData.email.endsWith('@blocked.com')) {
      throw new ValidationError('Email domain is blocked', 'email')
    }

    if (userData.username && userData.username.length < 3) {
      throw new ValidationError('Username must be at least 3 characters', 'username')
    }

    const user = await User.create(userData)
    return user
  } catch (error) {
    if (error.name === 'SequelizeUniqueConstraintError') {
      const field = error.errors[0]?.path
      throw new ValidationError(`${field} already exists`, field)
    }

    if (error.name === 'SequelizeValidationError') {
      const field = error.errors[0]?.path
      const message = error.errors[0]?.message
      throw new ValidationError(message, field)
    }

    throw error
  }
}

module.exports = {
  User,
  getActiveAdminsWithStats,
  getRecentUsers,
  complexTransaction,
  processBatchUsers,
  getPostsWithFullDetails,
  getOptimizedUserList,
  getDashboardStats,
  getCachedUserWithPosts,
  getConnectionPoolStats,
  createUserWithValidation,
  ValidationError,
  cache
}