Add Department module for relationship
This commit is contained in:
parent
9ea2801f8f
commit
7fc284c2c0
@ -14,6 +14,7 @@ import { AllExceptionsFilter } from './logger/any-exception.filter';
|
||||
import loggerMiddleware from './logger/logger.middleware';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { StaffsModule } from './staffs/staffs.module';
|
||||
import { DepartmentModule } from './department/department.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -30,11 +31,13 @@ import { StaffsModule } from './staffs/staffs.module';
|
||||
// entities: ['dist/modules/**/*.mysql.entity{.ts,.js}'],
|
||||
autoLoadEntities: true,
|
||||
// IMPORTANT: disable sync
|
||||
// synchronize: false,
|
||||
synchronize: true,
|
||||
synchronize: false,
|
||||
// synchronize: true,
|
||||
logging: true,
|
||||
}),
|
||||
UsersModule,
|
||||
StaffsModule,
|
||||
DepartmentModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
10
src/department/README.md
Normal file
10
src/department/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Department Module
|
||||
|
||||
- This module demonstrates using:
|
||||
- CRUD
|
||||
- TypeORM: MySQL
|
||||
- TypeORM Repository
|
||||
- No QueryBuilder
|
||||
- TypeOrmModule.forFeature & TypeOrmModule.forRoot{ autoLoadEntities: true }
|
||||
- The Entities
|
||||
- DB and Web-API entities are shared
|
78
src/department/department.controller.ts
Normal file
78
src/department/department.controller.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
NotFoundException,
|
||||
HttpCode,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { ApiResponse } from '@nestjs/swagger';
|
||||
import { DepartmentService } from './department.service';
|
||||
import { Department } from './entities/department.entity';
|
||||
import { DepartmentCreateDto } from './dto/department-create.dto';
|
||||
import { DepartmentUpdateDto } from './dto/department-update.dto';
|
||||
import { EntityNotFoundError } from 'typeorm';
|
||||
|
||||
@Controller('department')
|
||||
export class DepartmentController {
|
||||
constructor(private readonly departmentService: DepartmentService) {}
|
||||
|
||||
private handleEntityNotFoundError(id: number, e: Error) {
|
||||
if (e instanceof EntityNotFoundError) {
|
||||
throw new NotFoundException(`Not found: id=${id}`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiResponse({ type: [Department] })
|
||||
findAll(): Promise<Department[]> {
|
||||
return this.departmentService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiResponse({ type: Department })
|
||||
async findOne(@Param('id') id: number): Promise<Department | null> {
|
||||
// NOTE: the + operator returns the numeric representation of the object.
|
||||
return this.departmentService.findOne(+id).catch((err) => {
|
||||
this.handleEntityNotFoundError(id, err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiResponse({ type: [Department] })
|
||||
create(@Body() departmentCreateDto: DepartmentCreateDto) {
|
||||
return this.departmentService.create(departmentCreateDto);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
// Status 204 because no content will be returned
|
||||
@HttpCode(204)
|
||||
async update(
|
||||
@Param('id') id: number,
|
||||
@Body() departmentUpdateDto: DepartmentUpdateDto,
|
||||
): Promise<void> {
|
||||
if (Object.keys(departmentUpdateDto).length === 0) {
|
||||
throw new BadRequestException('Request body is empty');
|
||||
}
|
||||
await this.departmentService
|
||||
.update(+id, departmentUpdateDto)
|
||||
.catch((err) => {
|
||||
this.handleEntityNotFoundError(id, err);
|
||||
});
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@HttpCode(204)
|
||||
async remove(@Param('id') id: number): Promise<void> {
|
||||
await this.departmentService.remove(+id).catch((err) => {
|
||||
this.handleEntityNotFoundError(id, err);
|
||||
});
|
||||
}
|
||||
}
|
15
src/department/department.module.ts
Normal file
15
src/department/department.module.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Logger, Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { DepartmentService } from './department.service';
|
||||
import { DepartmentController } from './department.controller';
|
||||
import { Department } from './entities/department.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Department])],
|
||||
controllers: [DepartmentController],
|
||||
providers: [Logger, DepartmentService],
|
||||
// If you want to use the repository outside of the module
|
||||
// which imports TypeOrmModule.forFeature, you'll need to re-export the providers generated by it.
|
||||
// exports: [TypeOrmModule],
|
||||
})
|
||||
export class DepartmentModule {}
|
55
src/department/department.service.ts
Normal file
55
src/department/department.service.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { EntityNotFoundError, Repository } from 'typeorm';
|
||||
import { Department } from './entities/department.entity';
|
||||
import { DepartmentCreateDto } from './dto/department-create.dto';
|
||||
import { DepartmentUpdateDto } from './dto/department-update.dto';
|
||||
|
||||
@Injectable()
|
||||
export class DepartmentService {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
@InjectRepository(Department)
|
||||
private departmentRepository: Repository<Department>,
|
||||
) {}
|
||||
|
||||
create(departmentCreateDto: DepartmentCreateDto): Promise<Department> {
|
||||
// Use Repository.create() will copy the values to destination object.
|
||||
const department = this.departmentRepository.create(departmentCreateDto);
|
||||
return this.departmentRepository.save(department);
|
||||
}
|
||||
|
||||
findAll(): Promise<Department[]> {
|
||||
return this.departmentRepository.find();
|
||||
}
|
||||
|
||||
findOne(id: number): Promise<Department> {
|
||||
return this.departmentRepository.findOneOrFail({ where: { id } });
|
||||
}
|
||||
|
||||
async update(
|
||||
id: number,
|
||||
departmentUpdateDto: DepartmentUpdateDto,
|
||||
): Promise<void> {
|
||||
await this.isExist(id);
|
||||
await this.departmentRepository.update({ id }, departmentUpdateDto);
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<void> {
|
||||
await this.isExist(id);
|
||||
await this.departmentRepository.delete(id);
|
||||
}
|
||||
|
||||
// Helper function: Check if the entity exist.
|
||||
// If entity does not exsit, return the Promise.reject()
|
||||
private async isExist(id: number): Promise<void> {
|
||||
const cnt = await this.departmentRepository.countBy({ id });
|
||||
if (cnt > 0) {
|
||||
return;
|
||||
} else {
|
||||
return Promise.reject(
|
||||
new EntityNotFoundError(Department, { where: { id } }),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
16
src/department/dto/department-create.dto.ts
Normal file
16
src/department/dto/department-create.dto.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
export class DepartmentCreateDto {
|
||||
// NOTE: Since the id is auto-inc, so no id for the creation
|
||||
// id: number;
|
||||
|
||||
@ApiProperty({
|
||||
type: String,
|
||||
name: 'name',
|
||||
description: 'Department name',
|
||||
required: true,
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
}
|
4
src/department/dto/department-update.dto.ts
Normal file
4
src/department/dto/department-update.dto.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { DepartmentCreateDto } from './department-create.dto';
|
||||
|
||||
export class DepartmentUpdateDto extends PartialType(DepartmentCreateDto) {}
|
30
src/department/entities/department.entity.ts
Normal file
30
src/department/entities/department.entity.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Staff } from 'src/staffs/entities/staff.entity';
|
||||
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
// @Entity('departments')
|
||||
@Entity()
|
||||
export class Department {
|
||||
@ApiProperty({
|
||||
type: Number,
|
||||
name: 'id',
|
||||
description: 'id of department, auto-incremented',
|
||||
required: true,
|
||||
})
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@ApiProperty({
|
||||
type: String,
|
||||
name: 'name',
|
||||
description: 'Department name',
|
||||
required: true,
|
||||
})
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
})
|
||||
name: string;
|
||||
|
||||
// @OneToMany((type) => Staff, (staff) => staff.departmentId)
|
||||
// staffs: Staff[];
|
||||
}
|
@ -1,11 +1,19 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { Department } from 'src/department/entities/department.entity';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
// @Entity('staffs')
|
||||
@Entity()
|
||||
export class Staff {
|
||||
@ApiProperty({
|
||||
type: 'number',
|
||||
type: Number,
|
||||
name: 'id',
|
||||
description: 'id of staff, auto-incremented',
|
||||
required: true,
|
||||
@ -53,5 +61,7 @@ export class Staff {
|
||||
})
|
||||
departmentId: number;
|
||||
|
||||
// TODO: JOIN TABLE CASE
|
||||
@ManyToOne(() => Department)
|
||||
@JoinColumn({ name: 'department_id' })
|
||||
department: Department;
|
||||
}
|
||||
|
@ -20,7 +20,21 @@ export class StaffsService {
|
||||
}
|
||||
|
||||
findAll(): Promise<Staff[]> {
|
||||
return this.staffsRepository.find();
|
||||
return this.staffsRepository.find({
|
||||
relations: {
|
||||
department: true,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
|
||||
departmentId: false,
|
||||
department: {
|
||||
id: false,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
findOne(id: number): Promise<Staff> {
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
export class CreateUserDto {
|
||||
// NOTE: Since the id is autoinc, so no id for user creation
|
||||
// @ApiProperty({
|
||||
// type: 'number',
|
||||
// type: Number,
|
||||
// name: 'id',
|
||||
// description: 'id of user',
|
||||
// required: false,
|
||||
|
@ -11,7 +11,7 @@ import { UpdateUserDto } from '../dto/update-user.dto';
|
||||
// export class User implements IUser {
|
||||
export class User {
|
||||
@ApiProperty({
|
||||
type: 'number',
|
||||
type: Number,
|
||||
name: 'id',
|
||||
description: 'id of user',
|
||||
required: false,
|
||||
@ -19,7 +19,7 @@ export class User {
|
||||
id: number;
|
||||
|
||||
@ApiProperty({
|
||||
type: 'string',
|
||||
type: String,
|
||||
name: 'name',
|
||||
description: 'name of user',
|
||||
required: false,
|
||||
|
Loading…
Reference in New Issue
Block a user