@nestjsx/crud
import { CrudValidationGroups } from '@nestjsx/crud';
const { CREATE, UPDATE } = CrudValidationGroups;
@Entity('users')
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString()
@Column({ length: 50 })
name: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString()
@Column({ length: 100, select: false })
password: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString()
@Column({ length: 100 })
email: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString({ each: true })
@Column('simple-array')
roles: string[];
}
Le décorateur Crud
@Crud({
model: {
type: User,
},
params: {
id: {
field: 'id',
type: 'uuid',
primary: true,
},
},
routes: {
only: [
'getOneBase',
'getManyBase',
'deleteOneBase',
'createOneBase',
'updateOneBase'
],
getOneBase: {
decorators: [Roles('admin')]
},
getManyBase: {
decorators: [Roles('admin')]
},
deleteOneBase: {
decorators: [Roles('admin')]
}
},
query: {
exclude: ['password']
}
})
Les routes surchargées
@Controller('users')
@UseGuards(AuthGuard('jwt'), RolesGuard)
export class UserController implements CrudController<User> {
constructor(
public readonly service: UserService,
) {}
@Override()
createOne(@Body() user: User) {
return this.service.createUser(user);
}
@Roles('admin')
@Override('updateOneBase')
anotherName(@Param('id') id: string, @Body() user: User) {
return this.service.updateUser(id, user);
}
}
@Injectable()
export class UserService extends TypeOrmCrudService<User> {
constructor(@InjectRepository(User) private readonly userRepository: Repository<User>) {
super(userRepository);
}
createUser = async (user: User) => {
const plainPassword = user.password;
const encryptedPassword = await hash(plainPassword, SALT_ROUNDS);
const createdUser = await this.userRepository.save({ ...user, password: encryptedPassword });
const { password, ...createdUserDto } = createdUser;
return createdUserDto;
};
updateUser = async (id: string, user: User) => {
let newUser = user;
const plainPassword = user.password;
if (Boolean(plainPassword)) {
const encryptedPassword = await hash(plainPassword, SALT_ROUNDS);
newUser = { ...newUser, password: encryptedPassword };
}
await this.userRepository.update({ id }, newUser);
return await this.userRepository.findOne({ id });
};
}
import { CrudValidationGroups } from '@nestjsx/crud';
const { CREATE, UPDATE } = CrudValidationGroups;
@Entity('users')
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString()
@Column({ length: 50 })
name: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString()
@Column({ length: 100, select: false })
password: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString()
@Column({ length: 100 })
email: string;
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString({ each: true })
@Column('simple-array')
roles: string[];
}
@Crud({
model: {
type: Article,
},
params: {
id: {
field: 'id',
type: 'uuid',
primary: true,
},
},
query: {
join: {
user: { eager: true, exclude: ['password'] },
},
alwaysPaginate: true,
},
})
// user.entity.ts
import { Exclude } from 'class-transformer';
...
@Entity('users')
export class User {
...
@Exclude()
@IsOptional({ groups: [UPDATE] })
@IsNotEmpty({ groups: [CREATE] })
@IsString()
@Column({ length: 100, select: false })
password: string;
...
}
// article.controller.ts
import { UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common';
...
@UseInterceptors(ClassSerializerInterceptor)
@Controller('articles')
...
function getCandidates(options: IPaginationOptions): Promise<CustomPagination<Candidate>> {
const queryBuilder = this.candidateRepository
.createQueryBuilder('candidate')
.leftJoinAndSelect('candidate.headhunter', 'headhunter')
.leftJoinAndSelect('candidate.school', 'school');
return customPaginate<Candidate>(queryBuilder, options);
}
interface IPaginationOptions {
limit: number;
page: number;
route?: string;
}