Files
sena_db_api_layer/controllers/subjectController.js
2026-01-19 09:33:35 +07:00

344 lines
8.0 KiB
JavaScript

const { Subject, Chapter } = require('../models');
const { cacheUtils } = require('../config/redis');
const { addDatabaseWriteJob } = require('../config/bullmq');
/**
* Subject Controller - Quản lý môn học
*/
class SubjectController {
/**
* Get all subjects with pagination and caching
*/
async getAllSubjects(req, res, next) {
try {
const { page = 1, limit = 50, is_active } = req.query;
const offset = (page - 1) * limit;
// Generate cache key
const cacheKey = `subjects:list:${page}:${limit}:${is_active || 'all'}`;
// Try to get from cache first
const cached = await cacheUtils.get(cacheKey);
if (cached) {
return res.json({
success: true,
data: cached,
cached: true,
});
}
// Build query conditions
const where = {};
if (is_active !== undefined) where.is_active = is_active === 'true';
// Query from database (through ProxySQL)
const { count, rows } = await Subject.findAndCountAll({
where,
limit: parseInt(limit),
offset: parseInt(offset),
order: [['subject_code', 'ASC']],
});
const result = {
subjects: rows,
pagination: {
total: count,
page: parseInt(page),
limit: parseInt(limit),
totalPages: Math.ceil(count / limit),
},
};
// Cache the result
await cacheUtils.set(cacheKey, result, 7200); // Cache for 2 hours
res.json({
success: true,
data: result,
cached: false,
});
} catch (error) {
next(error);
}
}
/**
* Get subject by ID with caching
*/
async getSubjectById(req, res, next) {
try {
const { id } = req.params;
const cacheKey = `subject:${id}`;
// Try cache first
const cached = await cacheUtils.get(cacheKey);
if (cached) {
return res.json({
success: true,
data: cached,
cached: true,
});
}
// Query from database
const subject = await Subject.findByPk(id);
if (!subject) {
return res.status(404).json({
success: false,
message: 'Subject not found',
});
}
// Cache the result
await cacheUtils.set(cacheKey, subject, 7200); // Cache for 2 hours
res.json({
success: true,
data: subject,
cached: false,
});
} catch (error) {
next(error);
}
}
/**
* Get subject by code with caching
*/
async getSubjectByCode(req, res, next) {
try {
const { code } = req.params;
const cacheKey = `subject:code:${code}`;
// Try cache first
const cached = await cacheUtils.get(cacheKey);
if (cached) {
return res.json({
success: true,
data: cached,
cached: true,
});
}
// Query from database
const subject = await Subject.findOne({
where: { subject_code: code },
});
if (!subject) {
return res.status(404).json({
success: false,
message: 'Subject not found',
});
}
// Cache the result
await cacheUtils.set(cacheKey, subject, 7200); // Cache for 2 hours
res.json({
success: true,
data: subject,
cached: false,
});
} catch (error) {
next(error);
}
}
/**
* Create new subject (async via BullMQ)
*/
async createSubject(req, res, next) {
try {
const subjectData = req.body;
// Add to job queue for async processing
const job = await addDatabaseWriteJob('create', 'Subject', subjectData);
// Note: Cache will be invalidated by worker after successful creation
res.status(202).json({
success: true,
message: 'Subject creation job queued',
jobId: job.id,
data: subjectData,
});
} catch (error) {
next(error);
}
}
/**
* Update subject (async via BullMQ)
*/
async updateSubject(req, res, next) {
try {
const { id } = req.params;
const updates = req.body;
// Add to job queue for async processing
const job = await addDatabaseWriteJob('update', 'Subject', {
id,
updates,
});
// Note: Cache will be invalidated by worker after successful update
res.status(202).json({
success: true,
message: 'Subject update job queued',
jobId: job.id,
});
} catch (error) {
next(error);
}
}
/**
* Delete subject (async via BullMQ)
*/
async deleteSubject(req, res, next) {
try {
const { id } = req.params;
// Add to job queue for async processing
const job = await addDatabaseWriteJob('delete', 'Subject', { id });
// Note: Cache will be invalidated by worker after successful deletion
res.status(202).json({
success: true,
message: 'Subject deletion job queued',
jobId: job.id,
});
} catch (error) {
next(error);
}
}
/**
* Get active subjects (frequently used)
*/
async getActiveSubjects(req, res, next) {
try {
const cacheKey = 'subjects:active';
// Try cache first
const cached = await cacheUtils.get(cacheKey);
if (cached) {
return res.json({
success: true,
data: cached,
cached: true,
});
}
// Query from database
const subjects = await Subject.findAll({
where: { is_active: true },
order: [['subject_code', 'ASC']],
});
// Cache for 4 hours (this data changes infrequently)
await cacheUtils.set(cacheKey, subjects, 14400);
res.json({
success: true,
data: subjects,
cached: false,
});
} catch (error) {
next(error);
}
}
/**
* Get subject datatypes
*/
async getSubjectDatatypes(req, res, next) {
try {
const datatypes = Subject.rawAttributes;
res.json({
success: true,
data: datatypes,
});
} catch (error) {
next(error);
}
}
/**
* Get chapters by subject ID
*/
async getChaptersBySubject(req, res, next) {
try {
const { id } = req.params;
const { page = 1, limit = 50, is_published } = req.query;
const offset = (page - 1) * limit;
// Generate cache key
const cacheKey = `subject:${id}:chapters:${page}:${limit}:${is_published || 'all'}`;
// Try cache first
const cached = await cacheUtils.get(cacheKey);
if (cached) {
return res.json({
success: true,
data: cached,
cached: true,
});
}
// Check if subject exists
const subject = await Subject.findByPk(id);
if (!subject) {
return res.status(404).json({
success: false,
message: 'Subject not found',
});
}
// Build query conditions
const where = { subject_id: id };
if (is_published !== undefined) where.is_published = is_published === 'true';
// Query chapters
const { count, rows } = await Chapter.findAndCountAll({
where,
limit: parseInt(limit),
offset: parseInt(offset),
order: [['display_order', 'ASC'], ['chapter_number', 'ASC']],
});
const result = {
subject: {
id: subject.id,
subject_code: subject.subject_code,
subject_name: subject.subject_name,
},
chapters: rows,
pagination: {
total: count,
page: parseInt(page),
limit: parseInt(limit),
totalPages: Math.ceil(count / limit),
},
};
// Cache the result
await cacheUtils.set(cacheKey, result, 3600); // Cache for 1 hour
res.json({
success: true,
data: result,
cached: false,
});
} catch (error) {
next(error);
}
}
}
module.exports = new SubjectController();