-
Notifications
You must be signed in to change notification settings - Fork 0
feat: course entity and endpoints #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…to many relationships
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a Course entity and establishes a many-to-many relationship between Courses and Faculties. It includes API endpoints for CRUD operations on courses and enhances the faculty endpoints to support course associations.
Key Changes:
- Added Course entity with many-to-many relationship to Faculty
- Created CoursesModule with full CRUD endpoints (controller, service, DTOs)
- Refactored Faculty entity location to entities folder and added courses relationship
- Implemented global EntityNotFoundFilter for standardized error handling
- Updated database seeding to support courses and their associations
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/courses/entities/course.entity.ts | New Course entity with id, name, acronym, and many-to-many relationship to faculties |
| src/courses/courses.service.ts | Service implementing CRUD operations for courses with faculty relationship management |
| src/courses/courses.controller.ts | REST controller exposing course endpoints with authentication guards |
| src/courses/dto/create-course.dto.ts | DTO for course creation with validation and optional faculty IDs |
| src/courses/dto/update-course.dto.ts | DTO extending CreateCourseDto for partial updates |
| src/courses/courses.module.ts | Module configuration importing Course and Faculty repositories |
| src/courses/courses.service.spec.ts | Basic test file for CoursesService |
| src/courses/courses.controller.spec.ts | Basic test file for CoursesController |
| src/faculties/entities/faculty.entity.ts | Faculty entity relocated with added many-to-many courses relationship |
| src/faculties/faculties.service.ts | Updated to handle course associations in create, update, and delete operations |
| src/faculties/faculties.module.ts | Updated to import Course repository |
| src/faculties/dto/create-faculty.dto.ts | Extended with optional courseIds array field |
| src/faculties/faculties.service.spec.ts | Updated import path for Faculty entity |
| src/faculties/faculties.controller.ts | Updated import path for Faculty entity |
| src/faculties/faculties.controller.spec.ts | Updated import path for Faculty entity |
| src/filters/entity-not-found.filter.ts | New global filter to convert TypeORM EntityNotFoundError to NotFoundException |
| src/database/factories/course.factory.ts | Factory for generating realistic course test data |
| src/database/seeds/course.seeder.ts | Seeder to create 20 course records |
| src/database/seeds/faculty.seeder.ts | Updated to associate faculties with random courses |
| src/database/seed.ts | Updated entity list to include Course |
| src/database/factories/faculty.factory.ts | Updated import path for Faculty entity |
| src/app.module.ts | Registered CoursesModule |
| src/main.ts | Registered EntityNotFoundFilter globally |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { Injectable, NotFoundException } from '@nestjs/common'; | ||
| import { CreateCourseDto } from './dto/create-course.dto'; | ||
| import { UpdateCourseDto } from './dto/update-course.dto'; | ||
| import { InjectRepository } from '@nestjs/typeorm'; | ||
| import { Course } from './entities/course.entity'; | ||
| import { In, Repository } from 'typeorm'; | ||
| import { Faculty } from '../faculties/entities/faculty.entity'; | ||
|
|
||
| @Injectable() | ||
| export class CoursesService { | ||
| constructor( | ||
| @InjectRepository(Course) | ||
| private courseRepository: Repository<Course>, | ||
| @InjectRepository(Faculty) | ||
| private facultyRepository: Repository<Faculty>, | ||
| ) {} | ||
|
|
||
| async create(createCourseDto: CreateCourseDto): Promise<Course> { | ||
| const { facultyIds, ...courseData } = createCourseDto; | ||
| const course = this.courseRepository.create(courseData); | ||
|
|
||
| if (facultyIds && facultyIds.length > 0) { | ||
| const faculties = await this.facultyRepository.findBy({ | ||
| id: In(facultyIds), | ||
| }); | ||
| if (faculties.length !== facultyIds.length) { | ||
| throw new NotFoundException(`One or more faculties not found`); | ||
| } | ||
| course.faculties = faculties; | ||
| } else { | ||
| course.faculties = []; | ||
| } | ||
|
|
||
| return this.courseRepository.save(course); | ||
| } | ||
|
|
||
| findAll(): Promise<Course[]> { | ||
| return this.courseRepository.find({ relations: ['faculties'] }); | ||
| } | ||
|
|
||
| findOne(id: number): Promise<Course> { | ||
| return this.courseRepository.findOneOrFail({ | ||
| where: { id }, | ||
| relations: ['faculties'], | ||
| }); | ||
| } | ||
|
|
||
| async update(id: number, updateCourseDto: UpdateCourseDto): Promise<Course> { | ||
| const { facultyIds, ...courseData } = updateCourseDto; | ||
|
|
||
| const course = await this.courseRepository.findOneBy({ id }); | ||
|
|
||
| if (!course) { | ||
| throw new NotFoundException(`Course with id ${id} not found`); | ||
| } | ||
|
|
||
| this.courseRepository.merge(course, courseData); | ||
|
|
||
| if (facultyIds && facultyIds.length > 0) { | ||
| const faculties = await this.facultyRepository.findBy({ | ||
| id: In(facultyIds), | ||
| }); | ||
| if (faculties.length !== facultyIds.length) { | ||
| throw new NotFoundException(`One or more faculties not found`); | ||
| } | ||
| course.faculties = faculties; | ||
| } else { | ||
| course.faculties = []; | ||
| } | ||
|
|
||
| return this.courseRepository.save(course); | ||
| } | ||
|
|
||
| async remove(id: number): Promise<Course> { | ||
| const course = await this.courseRepository.findOneByOrFail({ id }); | ||
| await this.courseRepository.delete(id); | ||
| return course; | ||
| } | ||
| } |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Significant code duplication exists between CoursesService and FacultiesService. The create, update, and remove methods have nearly identical logic for handling many-to-many relationships. Consider extracting the common relationship handling logic into a shared utility function or base service class to improve maintainability and reduce code duplication.
Closes #52