Add nestjs-paginate and more relationship
This commit is contained in:
parent
7be9dd3e89
commit
2d492f3263
@ -30,6 +30,7 @@
|
||||
"class-validator": "^0.14.0",
|
||||
"mysql2": "^3.2.1",
|
||||
"nest-winston": "^1.9.1",
|
||||
"nestjs-paginate": "^8.1.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.2.0",
|
||||
"typeorm": "^0.3.15",
|
||||
|
@ -14,7 +14,7 @@ import { AllExceptionsFilter } from './logger/any-exception.filter';
|
||||
import loggerMiddleware from './logger/logger.middleware';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { MySqlCompanyModule } from './mysqlcompany/mysqlcompany.module';
|
||||
import { OrmMongoCompanyModule } from './ormmongocompany/ormmongocompany.module';
|
||||
// import { OrmMongoCompanyModule } from './ormmongocompany/ormmongocompany.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -27,12 +27,12 @@ import { OrmMongoCompanyModule } from './ormmongocompany/ormmongocompany.module'
|
||||
port: 23306,
|
||||
username: 'root',
|
||||
password: 'example',
|
||||
database: 'example_nodejs_nest_crud_company',
|
||||
database: 'boilerplate_nestjs_api_crud_company',
|
||||
// entities: ['dist/modules/**/*.mysql.entity{.ts,.js}'],
|
||||
autoLoadEntities: true,
|
||||
// IMPORTANT: disable sync
|
||||
synchronize: false,
|
||||
// synchronize: true,
|
||||
// synchronize: false,
|
||||
synchronize: true,
|
||||
logging: true,
|
||||
}),
|
||||
// Router resigration for module (2nd level) will be declared inside the module
|
||||
@ -40,7 +40,7 @@ import { OrmMongoCompanyModule } from './ormmongocompany/ormmongocompany.module'
|
||||
// ]),
|
||||
UsersModule,
|
||||
MySqlCompanyModule,
|
||||
OrmMongoCompanyModule,
|
||||
// OrmMongoCompanyModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
@ -30,7 +30,8 @@ export class AllExceptionsFilter implements ExceptionFilter {
|
||||
message = exception.message;
|
||||
// trim the stack lines
|
||||
if (exception.stack) {
|
||||
stack = exception.stack.split('\n').slice(1, 3).join('\n');
|
||||
// stack = exception.stack.split('\n').slice(1, 3).join('\n');
|
||||
stack = exception.stack;
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,15 +56,19 @@ export class AllExceptionsFilter implements ExceptionFilter {
|
||||
this.logger.error(logMsg, stack, AllExceptionsFilter.name);
|
||||
} else {
|
||||
const requstBody =
|
||||
Object.keys(body).length > 0 ? ` Body=${JSON.stringify(body)}` : '';
|
||||
Object.keys(body).length > 0 ? `Body=${JSON.stringify(body)}` : '';
|
||||
|
||||
const rawHeadersStr =
|
||||
Object.keys(rawHeaders).length > 0
|
||||
? ` RawHeaders=${JSON.stringify(rawHeaders)}`
|
||||
? `RawHeaders=${JSON.stringify(rawHeaders)}`
|
||||
: '';
|
||||
|
||||
logMsg = `${message}\n${method.toLocaleUpperCase()} ${url}${requstBody}${rawHeadersStr}`;
|
||||
this.logger.error(logMsg, stack, AllExceptionsFilter.name);
|
||||
// this.logger.error(logMsg, stack, AllExceptionsFilter.name);
|
||||
this.logger.error(message);
|
||||
this.logger.debug(
|
||||
`Request: ${method.toLocaleUpperCase()} ${url}\n${requstBody}\n${rawHeadersStr}\n${stack}`,
|
||||
);
|
||||
}
|
||||
|
||||
response.header('Content-Type', 'application/json; charset=utf-8');
|
||||
|
10
src/mysqlcompany/contract/README.md
Normal file
10
src/mysqlcompany/contract/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Contract 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
|
77
src/mysqlcompany/contract/contracts.controller.ts
Normal file
77
src/mysqlcompany/contract/contracts.controller.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
NotFoundException,
|
||||
HttpCode,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { ApiResponse } from '@nestjs/swagger';
|
||||
import { ContractsService } from './contracts.service';
|
||||
import { Contract } from './entities/contract.entity';
|
||||
import { ContractCreateDto } from './dto/contract-create.dto';
|
||||
import { ContractUpdateDto } from './dto/contract-update.dto';
|
||||
import { EntityNotFoundError } from 'typeorm';
|
||||
import { Paginate, PaginateQuery, Paginated } from 'nestjs-paginate';
|
||||
|
||||
@Controller()
|
||||
export class ContractsController {
|
||||
constructor(private readonly contractsService: ContractsService) {}
|
||||
|
||||
private handleEntityNotFoundError(id: number, e: Error) {
|
||||
if (e instanceof EntityNotFoundError) {
|
||||
throw new NotFoundException(`Not found: id=${id}`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiResponse({ type: [Contract] })
|
||||
findAll(@Paginate() query: PaginateQuery): Promise<Paginated<Contract>> {
|
||||
return this.contractsService.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiResponse({ type: Contract })
|
||||
async findOne(@Param('id') id: number): Promise<Contract | null> {
|
||||
// NOTE: the + operator returns the numeric representation of the object.
|
||||
return this.contractsService.findOne(+id).catch((err) => {
|
||||
this.handleEntityNotFoundError(id, err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Post()
|
||||
@ApiResponse({ type: [Contract] })
|
||||
create(@Body() contractCreateDto: ContractCreateDto) {
|
||||
return this.contractsService.create(contractCreateDto);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
// Status 204 because no content will be returned
|
||||
@HttpCode(204)
|
||||
async update(
|
||||
@Param('id') id: number,
|
||||
@Body() contractUpdateDto: ContractUpdateDto,
|
||||
): Promise<void> {
|
||||
if (Object.keys(contractUpdateDto).length === 0) {
|
||||
throw new BadRequestException('Request body is empty');
|
||||
}
|
||||
await this.contractsService.update(+id, contractUpdateDto).catch((err) => {
|
||||
this.handleEntityNotFoundError(id, err);
|
||||
});
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@HttpCode(204)
|
||||
async remove(@Param('id') id: number): Promise<void> {
|
||||
await this.contractsService.remove(+id).catch((err) => {
|
||||
this.handleEntityNotFoundError(id, err);
|
||||
});
|
||||
}
|
||||
}
|
15
src/mysqlcompany/contract/contracts.module.ts
Normal file
15
src/mysqlcompany/contract/contracts.module.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Logger, Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ContractsService } from './contracts.service';
|
||||
import { ContractsController } from './contracts.controller';
|
||||
import { Contract } from './entities/contract.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Contract])],
|
||||
controllers: [ContractsController],
|
||||
providers: [Logger, ContractsService],
|
||||
// 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 ContractsModule {}
|
70
src/mysqlcompany/contract/contracts.service.ts
Normal file
70
src/mysqlcompany/contract/contracts.service.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { EntityNotFoundError, Repository } from 'typeorm';
|
||||
import { Contract } from './entities/contract.entity';
|
||||
import { ContractCreateDto } from './dto/contract-create.dto';
|
||||
import { ContractUpdateDto } from './dto/contract-update.dto';
|
||||
import {
|
||||
FilterOperator,
|
||||
FilterSuffix,
|
||||
PaginateQuery,
|
||||
Paginated,
|
||||
paginate,
|
||||
} from 'nestjs-paginate';
|
||||
|
||||
@Injectable()
|
||||
export class ContractsService {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
@InjectRepository(Contract)
|
||||
private contractsRepository: Repository<Contract>,
|
||||
) {}
|
||||
|
||||
create(contractCreateDto: ContractCreateDto): Promise<Contract> {
|
||||
// Use Repository.create() will copy the values to destination object.
|
||||
const contract = this.contractsRepository.create(contractCreateDto);
|
||||
return this.contractsRepository.save(contract);
|
||||
}
|
||||
|
||||
findAll(query: PaginateQuery): Promise<Paginated<Contract>> {
|
||||
return paginate(query, this.contractsRepository, {
|
||||
relations: { staff: true },
|
||||
sortableColumns: ['id', 'title', 'details', 'staff.name'],
|
||||
select: ['id', 'title', 'details', 'staff.name'],
|
||||
filterableColumns: {
|
||||
title: [FilterOperator.EQ, FilterOperator.ILIKE, FilterSuffix.NOT],
|
||||
// staff.name: [FilterOperator.EQ, FilterOperator.ILIKE, FilterSuffix.NOT],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
findOne(id: number): Promise<Contract> {
|
||||
return this.contractsRepository.findOneOrFail({ where: { id } });
|
||||
}
|
||||
|
||||
async update(
|
||||
id: number,
|
||||
contractUpdateDto: ContractUpdateDto,
|
||||
): Promise<void> {
|
||||
await this.isExist(id);
|
||||
await this.contractsRepository.update({ id }, contractUpdateDto);
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<void> {
|
||||
await this.isExist(id);
|
||||
await this.contractsRepository.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.contractsRepository.countBy({ id });
|
||||
if (cnt > 0) {
|
||||
return;
|
||||
} else {
|
||||
return Promise.reject(
|
||||
new EntityNotFoundError(Contract, { where: { id } }),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
30
src/mysqlcompany/contract/dto/contract-create.dto.ts
Normal file
30
src/mysqlcompany/contract/dto/contract-create.dto.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsString, IsNumber, IsOptional } from 'class-validator';
|
||||
import { Staff } from 'src/mysqlcompany/staffs/entities/staff.entity';
|
||||
export class ContractCreateDto {
|
||||
// NOTE: Since the id is auto-inc, so no id for the creation
|
||||
// id: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Contract name',
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
title: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Contract details',
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
details: string;
|
||||
|
||||
@ApiProperty({
|
||||
type: Staff,
|
||||
name: 'departmentId',
|
||||
description: 'Department ID',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
staff: Staff;
|
||||
}
|
4
src/mysqlcompany/contract/dto/contract-update.dto.ts
Normal file
4
src/mysqlcompany/contract/dto/contract-update.dto.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { ContractCreateDto } from './contract-create.dto';
|
||||
|
||||
export class ContractUpdateDto extends PartialType(ContractCreateDto) {}
|
52
src/mysqlcompany/contract/entities/contract.entity.ts
Normal file
52
src/mysqlcompany/contract/entities/contract.entity.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Staff } from 'src/mysqlcompany/staffs/entities/staff.entity';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('contracts')
|
||||
export class Contract {
|
||||
@ApiProperty({
|
||||
type: Number,
|
||||
name: '_id',
|
||||
description: 'id of contract, auto-incremented',
|
||||
})
|
||||
// https://github.com/ppetzold/nestjs-paginate/issues/518
|
||||
// when use 'id', will cause duplicated column issue
|
||||
@PrimaryGeneratedColumn('increment', { name: '_id' })
|
||||
id: number;
|
||||
|
||||
@ApiProperty({
|
||||
type: String,
|
||||
description: 'Contract title',
|
||||
})
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
length: 255,
|
||||
})
|
||||
title: string;
|
||||
|
||||
@ApiProperty({
|
||||
type: String,
|
||||
name: 'details',
|
||||
description: 'Contract details',
|
||||
required: false,
|
||||
})
|
||||
@Column({
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
})
|
||||
details: string;
|
||||
|
||||
@ApiProperty({
|
||||
name: 'staff',
|
||||
description: 'The staff of this contract',
|
||||
type: () => Staff,
|
||||
})
|
||||
@OneToOne(() => Staff)
|
||||
staff: Staff;
|
||||
}
|
@ -16,6 +16,7 @@ import { Department } from './entities/department.entity';
|
||||
import { DepartmentCreateDto } from './dto/department-create.dto';
|
||||
import { DepartmentUpdateDto } from './dto/department-update.dto';
|
||||
import { EntityNotFoundError } from 'typeorm';
|
||||
import { Paginate, PaginateQuery, Paginated } from 'nestjs-paginate';
|
||||
|
||||
@Controller()
|
||||
export class DepartmentController {
|
||||
@ -31,8 +32,8 @@ export class DepartmentController {
|
||||
|
||||
@Get()
|
||||
@ApiResponse({ type: [Department] })
|
||||
findAll(): Promise<Department[]> {
|
||||
return this.departmentService.findAll();
|
||||
findAll(@Paginate() query: PaginateQuery): Promise<Paginated<Department>> {
|
||||
return this.departmentService.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
|
@ -4,27 +4,38 @@ 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';
|
||||
import { PaginateQuery, Paginated, paginate } from 'nestjs-paginate';
|
||||
|
||||
@Injectable()
|
||||
export class DepartmentService {
|
||||
constructor(
|
||||
private readonly logger: Logger,
|
||||
@InjectRepository(Department)
|
||||
private departmentRepository: Repository<Department>,
|
||||
private departmentsRepository: 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);
|
||||
const department = this.departmentsRepository.create(departmentCreateDto);
|
||||
return this.departmentsRepository.save(department);
|
||||
}
|
||||
|
||||
findAll(): Promise<Department[]> {
|
||||
return this.departmentRepository.find();
|
||||
findAll(query: PaginateQuery): Promise<Paginated<Department>> {
|
||||
return paginate(query, this.departmentsRepository, {
|
||||
relations: { staffs: true },
|
||||
sortableColumns: ['id', 'name'],
|
||||
// select: ['id', 'name', 'staffs.name'],
|
||||
// searchableColumns: ['name', 'department.name'],
|
||||
// filterableColumns: {
|
||||
// 'home.pillows.color': [FilterOperator.EQ],
|
||||
// },
|
||||
});
|
||||
|
||||
// return this.departmentsRepository.find();
|
||||
}
|
||||
|
||||
findOne(id: number): Promise<Department> {
|
||||
return this.departmentRepository.findOneOrFail({ where: { id } });
|
||||
return this.departmentsRepository.findOneOrFail({ where: { id } });
|
||||
}
|
||||
|
||||
async update(
|
||||
@ -32,18 +43,18 @@ export class DepartmentService {
|
||||
departmentUpdateDto: DepartmentUpdateDto,
|
||||
): Promise<void> {
|
||||
await this.isExist(id);
|
||||
await this.departmentRepository.update({ id }, departmentUpdateDto);
|
||||
await this.departmentsRepository.update({ id }, departmentUpdateDto);
|
||||
}
|
||||
|
||||
async remove(id: number): Promise<void> {
|
||||
await this.isExist(id);
|
||||
await this.departmentRepository.delete(id);
|
||||
await this.departmentsRepository.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 });
|
||||
const cnt = await this.departmentsRepository.countBy({ id });
|
||||
if (cnt > 0) {
|
||||
return;
|
||||
} else {
|
||||
|
@ -1,17 +1,23 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { Staff } from 'src/mysqlcompany/staffs/entities/staff.entity';
|
||||
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
JoinColumn,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
// @Entity('departments')
|
||||
@Entity('departments')
|
||||
export class Department {
|
||||
@ApiProperty({
|
||||
type: Number,
|
||||
name: 'id',
|
||||
name: '_id',
|
||||
description: 'id of department, auto-incremented',
|
||||
required: true,
|
||||
})
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
@PrimaryGeneratedColumn('increment', { name: '_id' })
|
||||
id: number;
|
||||
|
||||
@ApiProperty({
|
||||
@ -25,6 +31,13 @@ export class Department {
|
||||
})
|
||||
name: string;
|
||||
|
||||
// @OneToMany((type) => Staff, (staff) => staff.departmentId)
|
||||
// staffs: Staff[];
|
||||
@OneToMany(() => Staff, (staff) => staff.department)
|
||||
@ApiProperty({
|
||||
name: 'staffs',
|
||||
description: 'The staffs under this department',
|
||||
type: [Staff],
|
||||
})
|
||||
@ApiPropertyOptional()
|
||||
// @JoinColumn({ name: 'id', referencedColumnName: 'department_id' })
|
||||
staffs: Staff[];
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { MySqlCompanyController } from './mysqlcompany.controller';
|
||||
import { DepartmentModule } from './department/department.module';
|
||||
import { StaffsModule } from './staffs/staffs.module';
|
||||
import { RouterModule } from '@nestjs/core';
|
||||
import { ContractsModule } from './contract/contracts.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -23,11 +24,16 @@ import { RouterModule } from '@nestjs/core';
|
||||
path: 'staffs',
|
||||
module: StaffsModule,
|
||||
},
|
||||
{
|
||||
path: 'contracts',
|
||||
module: ContractsModule,
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
DepartmentModule,
|
||||
StaffsModule,
|
||||
ContractsModule,
|
||||
],
|
||||
controllers: [MySqlCompanyController],
|
||||
providers: [Logger, MySqlCompanyService],
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Contract } from 'src/mysqlcompany/contract/entities/contract.entity';
|
||||
import { Department } from 'src/mysqlcompany/department/entities/department.entity';
|
||||
import {
|
||||
Column,
|
||||
@ -6,11 +7,11 @@ import {
|
||||
JoinColumn,
|
||||
JoinTable,
|
||||
ManyToOne,
|
||||
OneToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('staffs')
|
||||
@Entity()
|
||||
export class Staff {
|
||||
@ApiProperty({
|
||||
type: Number,
|
||||
@ -41,27 +42,35 @@ export class Staff {
|
||||
@Column({
|
||||
name: 'staff_code',
|
||||
type: 'varchar',
|
||||
length: 10,
|
||||
length: 4,
|
||||
nullable: true,
|
||||
})
|
||||
staffCode: number;
|
||||
|
||||
@ApiProperty({
|
||||
type: Number,
|
||||
name: 'departmentId',
|
||||
description: 'Department ID',
|
||||
name: 'department',
|
||||
description: 'The Department that the staff is undered',
|
||||
type: () => Department,
|
||||
required: false,
|
||||
})
|
||||
@Column({
|
||||
// Match existing column naming convention
|
||||
name: 'department_id',
|
||||
type: 'tinyint',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
@ManyToOne(() => Department, (department) => department.staffs, {
|
||||
nullable: false,
|
||||
eager: true,
|
||||
})
|
||||
departmentId: number;
|
||||
|
||||
@ManyToOne(() => Department)
|
||||
// @JoinColumn({ name: 'department_id', referencedColumnName: 'id' })
|
||||
@JoinColumn({ name: 'department_id' })
|
||||
department: Department;
|
||||
|
||||
@ApiProperty({
|
||||
name: 'contract',
|
||||
description: 'The staff contract',
|
||||
type: () => Contract,
|
||||
})
|
||||
@OneToOne(() => Contract, (contract) => contract.staff, {
|
||||
nullable: false,
|
||||
eager: true,
|
||||
cascade: true,
|
||||
})
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract: Contract;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import { Staff } from './entities/staff.entity';
|
||||
import { StaffCreateDto } from './dto/staff-create.dto';
|
||||
import { StaffUpdateDto } from './dto/staff-update.dto';
|
||||
import { EntityNotFoundError } from 'typeorm';
|
||||
import { Paginate, PaginateQuery, Paginated } from 'nestjs-paginate';
|
||||
|
||||
@Controller()
|
||||
export class StaffsController {
|
||||
@ -31,8 +32,8 @@ export class StaffsController {
|
||||
|
||||
@Get()
|
||||
@ApiResponse({ type: [Staff] })
|
||||
findAll(): Promise<Staff[]> {
|
||||
return this.staffsService.findAll();
|
||||
findAll(@Paginate() query: PaginateQuery): Promise<Paginated<Staff>> {
|
||||
return this.staffsService.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
|
@ -1,9 +1,16 @@
|
||||
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { EntityNotFoundError, Repository } from 'typeorm';
|
||||
import { Staff } from './entities/staff.entity';
|
||||
import { StaffCreateDto } from './dto/staff-create.dto';
|
||||
import { StaffUpdateDto } from './dto/staff-update.dto';
|
||||
import {
|
||||
FilterOperator,
|
||||
FilterSuffix,
|
||||
PaginateQuery,
|
||||
Paginated,
|
||||
paginate,
|
||||
} from 'nestjs-paginate';
|
||||
|
||||
@Injectable()
|
||||
export class StaffsService {
|
||||
@ -19,22 +26,47 @@ export class StaffsService {
|
||||
return this.staffsRepository.save(staff);
|
||||
}
|
||||
|
||||
findAll(): Promise<Staff[]> {
|
||||
return this.staffsRepository.find({
|
||||
relations: {
|
||||
department: true,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
|
||||
departmentId: false,
|
||||
department: {
|
||||
id: false,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
findAll(query: PaginateQuery): Promise<Paginated<Staff>> {
|
||||
return paginate(query, this.staffsRepository, {
|
||||
// loadEagerRelations: true,
|
||||
// relations: { department: true, contract: true },
|
||||
relations: ['contract', 'department'],
|
||||
// sortableColumns: ['id', 'name', 'staffCode', 'department.name'],
|
||||
sortableColumns: ['id', 'name', 'department.name'],
|
||||
select: [
|
||||
'id',
|
||||
'name',
|
||||
'staffCode',
|
||||
'department.id',
|
||||
'department.name',
|
||||
'contract.id',
|
||||
'contract.title',
|
||||
'contract.details',
|
||||
],
|
||||
// searchableColumns: ['name', 'department.name'],
|
||||
// filterableColumns: {
|
||||
// 'department.name': [
|
||||
// FilterOperator.EQ,
|
||||
// FilterOperator.ILIKE,
|
||||
// FilterSuffix.NOT,
|
||||
// ],
|
||||
// },
|
||||
});
|
||||
// return this.staffsRepository.find({
|
||||
// relations: {
|
||||
// department: true,
|
||||
// },
|
||||
// select: {
|
||||
// id: true,
|
||||
// name: true,
|
||||
|
||||
// departmentId: false,
|
||||
// department: {
|
||||
// id: false,
|
||||
// name: true,
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
}
|
||||
|
||||
findOne(id: number): Promise<Staff> {
|
||||
|
@ -37,13 +37,42 @@
|
||||
"colId": "8a14d631-7522-4fcd-a3b8-9a68166e5496",
|
||||
"containerId": "",
|
||||
"name": "Get MySQL Comany Staffs",
|
||||
"url": "http://localhost:3000/mysql-company/staffs/",
|
||||
"url": "http://localhost:3000/mysql-company/staffs/?limit=1&select=id,name,staffCode,department.name,contract.title",
|
||||
"method": "GET",
|
||||
"sortNum": 15000,
|
||||
"created": "2023-04-20T13:01:50.431Z",
|
||||
"modified": "2023-04-20T13:17:36.471Z",
|
||||
"modified": "2023-04-22T14:09:13.798Z",
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"params": [
|
||||
{
|
||||
"name": "limit",
|
||||
"value": "1",
|
||||
"isPath": false
|
||||
},
|
||||
{
|
||||
"name": "select",
|
||||
"value": "id,name,staffCode,department.name,contract.title",
|
||||
"isPath": false
|
||||
},
|
||||
{
|
||||
"name": "sortBy",
|
||||
"value": "department.name:DESC",
|
||||
"isDisabled": true,
|
||||
"isPath": false
|
||||
},
|
||||
{
|
||||
"name": "sortBy",
|
||||
"value": "name:ASC",
|
||||
"isDisabled": true,
|
||||
"isPath": false
|
||||
},
|
||||
{
|
||||
"name": "filter.department.name",
|
||||
"value": "$ilike:Brown",
|
||||
"isDisabled": true,
|
||||
"isPath": false
|
||||
}
|
||||
],
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
@ -51,13 +80,61 @@
|
||||
"colId": "8a14d631-7522-4fcd-a3b8-9a68166e5496",
|
||||
"containerId": "",
|
||||
"name": "Get MySQL Comany Departments",
|
||||
"url": "http://localhost:3000/ormmongo-company/staffs",
|
||||
"url": "http://localhost:3000/mysql-company/departments/",
|
||||
"method": "GET",
|
||||
"sortNum": 17500,
|
||||
"created": "2023-04-20T13:17:46.507Z",
|
||||
"modified": "2023-04-20T15:00:49.647Z",
|
||||
"modified": "2023-04-22T08:37:35.984Z",
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "e4920ab9-8552-46d1-9431-a3aaaa187cce",
|
||||
"colId": "8a14d631-7522-4fcd-a3b8-9a68166e5496",
|
||||
"containerId": "",
|
||||
"name": "Create MySQL Comany Staff",
|
||||
"url": "http://localhost:3000/mysql-company/staffs/",
|
||||
"method": "POST",
|
||||
"sortNum": 16250,
|
||||
"created": "2023-04-22T04:22:32.924Z",
|
||||
"modified": "2023-04-22T13:45:24.200Z",
|
||||
"headers": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"params": [],
|
||||
"body": {
|
||||
"type": "json",
|
||||
"raw": "{\n \"name\":\"{{#name}}\",\n \"department\":{ \"id\":2 },\n \"contract\": { \"title\":\"ZYX\" }\n}",
|
||||
"form": []
|
||||
},
|
||||
"tests": []
|
||||
},
|
||||
{
|
||||
"_id": "97997fc9-e49a-4a96-871b-6292c92c7567",
|
||||
"colId": "8a14d631-7522-4fcd-a3b8-9a68166e5496",
|
||||
"containerId": "",
|
||||
"name": "Create MySQL Comany Department",
|
||||
"url": "http://localhost:3000/mysql-company/departments/",
|
||||
"method": "POST",
|
||||
"sortNum": 16875,
|
||||
"created": "2023-04-22T07:37:29.132Z",
|
||||
"modified": "2023-04-22T07:38:11.328Z",
|
||||
"headers": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"params": [],
|
||||
"body": {
|
||||
"type": "json",
|
||||
"raw": "{\n \"name\": \"Dept: {{#name}}\"\n}",
|
||||
"form": []
|
||||
},
|
||||
"tests": []
|
||||
}
|
||||
]
|
@ -3863,6 +3863,13 @@ nest-winston@^1.9.1:
|
||||
dependencies:
|
||||
fast-safe-stringify "^2.1.1"
|
||||
|
||||
nestjs-paginate@^8.1.3:
|
||||
version "8.1.3"
|
||||
resolved "https://registry.yarnpkg.com/nestjs-paginate/-/nestjs-paginate-8.1.3.tgz#89c6a4fe88e3b2c885c0ca1daa115e889981d4d0"
|
||||
integrity sha512-dQ7VKfssee/FkIf4aI409x1LBkFV2KdKoVDVv6HIwQmVmSeF4n8mkOVLWNh2QSFjqe9IN15ezrrFGzuWvVooTQ==
|
||||
dependencies:
|
||||
lodash "^4.17.21"
|
||||
|
||||
node-abort-controller@^3.0.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz"
|
||||
|
Loading…
Reference in New Issue
Block a user