طراحی ساختار دیتابیس (ER-Diagram)
در ادامه یک مثال از بخش طراحی دیتابیس آورده شده است

-
طراحی ساختار دیتابیس (ER-Diagram)
- مشخص کردن موجودیتها (Entities):User
،Request
وRequestStatus
- تعریف روابط: هرUser
میتواند چندRequest
داشته باشد؛ هرRequest
چندRequestStatus
- تعیین کلیدهای اصلی (PK) و خارجی (FK) در هر جدول -
تنظیم کانفیگ Sequelize برای PostgreSQL
- نصب پکیجها:
- ایجاد فایل کانفیگnpm install sequelize pg pg-hstore
src/configs/database.js
:import { Sequelize } from 'sequelize'; const sequelize = new Sequelize( process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, { host: process.env.DB_HOST, dialect: 'postgres', logging: false, } );
export default sequelize;
-
ایجاد مدل
User
- تعریف فیلدهای پایه مثلuserId
،name
،email
وrole
import { DataTypes } from 'sequelize'; import sequelize from '../configs/database.js';
const User = sequelize.define('User', { userId: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true, }, name: { type: DataTypes.STRING(100), allowNull: false, }, email: { type: DataTypes.STRING(150), allowNull: false, unique: true, }, role: { type: DataTypes.ENUM('user', 'expert', 'admin'), defaultValue: 'user', }, }, { tableName: 'users', timestamps: true, });
export default User;
-
ایجاد مدل
Request
- فیلدهایrequestId
،userId
،expertId
،text
وtrackingCode
import { DataTypes } from 'sequelize'; import sequelize from '../configs/database.js'; import User from './user.js'; import { v4 as uuidv4 } from 'uuid';
const Request = sequelize.define('Request', { requestId: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true, }, userId: { type: DataTypes.INTEGER, references: { model: User, key: 'userId' }, allowNull: true, }, expertId: { type: DataTypes.INTEGER, references: { model: User, key: 'userId' }, allowNull: true, }, text: { type: DataTypes.TEXT, allowNull: false, }, trackingCode: { type: DataTypes.STRING(20), allowNull: false, unique: true, defaultValue: () => uuidv4().slice(0, 20), }, }, { tableName: 'requests', timestamps: true, });
export default Request;
-
ایجاد مدل
RequestStatus
- ENUM وضعیتها، ارجاع بهrequestId
و نگهداریprevious_state
import { DataTypes } from 'sequelize'; import sequelize from '../configs/database.js'; import Request from './request.js';
const RequestStatus = sequelize.define('RequestStatus', { statusId: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true, }, requestId: { type: DataTypes.INTEGER, references: { model: Request, key: 'requestId' }, allowNull: false, }, statusType: { type: DataTypes.ENUM('started','pending','accepted','rejected','done'), defaultValue: 'started', }, expertComment: { type: DataTypes.TEXT, defaultValue: '', }, userComment: { type: DataTypes.TEXT, defaultValue: '', }, files: { type: DataTypes.JSONB, allowNull: true, }, previous_state: { type: DataTypes.INTEGER, references: { model: 'request_statuses', key: 'statusId' }, allowNull: true, }, }, { tableName: 'request_statuses', timestamps: true, hooks: { beforeCreate: async (status) => { const last = await RequestStatus.findOne({ where: { requestId: status.requestId }, order: [['statusId','DESC']], }); if (last) status.previous_state = last.statusId; } } }); export default RequestStatus;
-
تنظیم ارتباطات (Associations)
- در فایلsrc/models/index.js
یا انتهای هر مدل:
import User from './user.js'; import Request from './request.js'; import RequestStatus from './requestStatus.js'; // User ↔ Request User.hasMany(Request, { foreignKey: 'userId', as: 'Requests' }); Request.belongsTo(User, { foreignKey: 'userId', as: 'Customer' }); User.hasMany(Request, { foreignKey: 'expertId', as: 'ExpertRequests' }); Request.belongsTo(User, { foreignKey: 'expertId', as: 'Expert' }); // Request ↔ RequestStatus Request.hasMany(RequestStatus, { foreignKey: 'requestId', as: 'Statuses' }); RequestStatus.belongsTo(Request, { foreignKey: 'requestId', as: 'Request' }); export { User, Request, RequestStatus };
-
پیادهسازی الگوی وضعیت (State Pattern)
- ساخت پوشهsrc/models/state/
و ایجاد کلاسهای وضعیت:
- در سرویس Request فراخوانی وضعیت:import { handleReqRejected } from '../../utils/status.utils.js'; class AcceptedState { constructor(context) { this.context = context; } async transitionTo(statusType) { if (!statusType) throw new Error('Invalid statusType'); if (statusType === 'rejected') { return await handleReqRejected(this.context); } throw new Error(`Cannot transition from accepted to ${statusType}`); } }
export default AcceptedState;
import AcceptedState from './state/acceptedState.js'; import PendingState from './state/pendingState.js'; // … class RequestService { constructor(request) { this.request = request; this.state = this._getStateInstance(request.currentStatus); } _getStateInstance(type) { switch(type) { case 'accepted': return new AcceptedState(this.request); // … } } async changeStatus(toType) { return this.state.transitionTo(toType); } }
No Comments