[英]NestJs using a service from another Module in a Custom Repository
实际学习 NestJs 并面临保存 typeorm OneToMany 关系的问题。 假设我有两个模块 ProjectsModule @ PlansModule
在计划和项目实体之间存在 OneToMany 关系
@Entity()
export class Project extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
...
@OneToMany(type => Plan, plan => plan.project, { eager: true })
plans: Plan[];
}
@Entity()
export class Plan extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
...
@ManyToOne(type => Project, project => project.plans, { eager: false } )
project: Project;
@Column()
projectId: string;
}
在 ProjectsModule 中,我有一个使用此方法的 ProjectsService:
async getProjectById(
id: string,
user: User
): Promise<Project> {
const found = await this.projectRepository.findOne({ where: { id, ownerId: user.id } });
if(!found) {
throw new NotFoundException(`Project with ID "${id}" not found`)
}
return found;
}
我的问题是当我尝试保存新计划时。 我的 PlansService 像这样调用 PlanRepository
async createPlan(
createPlanDto: CreatePlanDto,
user: User
): Promise<Plan> {
return this.planRepository.createPlan(createPlanDto, user);
}
在 PlanRepository 上:
constructor(
@Inject(ProjectsService)
private projectsService: ProjectsService
) {
super();
}
async createPlan(
createPlanDto: CreatePlanDto,
user: User
): Promise<Plan> {
const { title, description, project } = createPlanDto;
const plan = new Plan();
const projectFound = await this.projectsService.getProjectById(project, user)
plan.title = title;
plan.description = description;
plan.status = PlanStatus.ENABLED;
plan.owner = user;
plan.project = project;
try {
await plan.save();
} catch (error) {
this.logger.error(`Failed to create a Plan for user "${user.email}". Data: ${JSON.stringify(createPlanDto)}`, error.stack);
throw new InternalServerErrorException();
}
delete plan.owner;
return plan;
}
在向我的计划 controller 发送 POST 请求时,尝试这样做会引发此错误:
TypeError: this.projectsService.getProjectById is not a function
并尝试
console.log('service', this.projectsService)
给我吗
service EntityManager {
repositories: [],
plainObjectToEntityTransformer: PlainObjectToNewEntityTransformer {},
connection: Connection {
我想我没有正确使用项目服务,但我不明白我可能在哪里犯了错误。
在模块方面,我在他的模块中导出 ProjectsService:
exports: [ProjectsService]
并将完整的 ProjectsModule 导入 PlansModule:
imports: [
TypeOrmModule.forFeature([PlanRepository]),
AuthModule,
ProjectsModule
],
抱歉,这篇文章很长,试图详尽无遗。
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../auth/user.entity';
import { PlanRepository } from './plan.repository';
import { GetPlanFilterDto } from './dto/get-plan-filter.dto';
import { Plan } from './plan.entity';
import { CreatePlanDto } from './dto/create-plan.dto';
@Injectable()
export class PlansService {
constructor(
@InjectRepository(PlanRepository)
private planRepository: PlanRepository,
) {}
async getPlans(filterDto: GetPlanFilterDto, user: User): Promise<Plan[]> {
return this.planRepository.find({ ...filterDto, ownerId: user.id });
}
async getPlanById(id: string, user: User): Promise<Plan> {
return this.planRepository.findOne({
where: { id, ownerId: user.id },
});
}
async createPlan(createPlanDto: CreatePlanDto, user: User): Promise<Plan> {
const { project, ...data } = createPlanDto;
return this.planRepository
.create({
projectId: project,
ownerId: user.id,
...data,
})
.save();
}
}
此 PlanService仅使用存储库的内部方法,如果您在发生错误时登录,则 ExceptionFilter 将是一个合适的选项: https://docs.nestjs.com/exception-filters 。
您可以使用拦截器,而不是检查是否找到了计划:
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
NotFoundException,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class PlanNotFoundInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(plan => {
if (!plan) {
throw new NotFoundException("plan couldn't be found");
}
return plan;
}),
);
}
}
然后在您的getById
(控制器)上使用 @UseInterceptor,这将您的服务、数据访问、日志记录、验证等解耦。
我已经简化了实现(对于拦截器),您可能需要稍微调整它以适应您的确切需要。
yarn run v1.22.4
$ jest
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
PASS src/auth/user.repository.spec.ts
PASS src/projects/projects.service.spec.ts
PASS src/auth/jwt.strategy.spec.ts
PASS src/auth/user.entity.spec.ts
Test Suites: 4 passed, 4 total
Tests: 18 passed, 18 total
Snapshots: 0 total
Time: 3.774s, estimated 4s
Ran all test suites.
Done in 4.58s.
我没有花太多时间审查您的测试,但所做的更改并没有对单元测试造成任何重大更改(对于 e2e 不能这么说,个人不要使用 Cucumber.js)。
这个答案的重点不是为您提供所需的代码,而是您可以用来解决紧密耦合组件的抽象。
您还可以使用拦截器来验证请求,检查project
是否存在,检查它是否存在,如果不存在错误则中止。 再次将您的错误处理与您的控制器/服务/其他内容分离。
您还可以选择在请求中提取/添加内容,例如经过身份验证的.user
或来自 header 的值。 (如果您想通过 Request 对象将 projectId 发送到 Controller 可能会很有用)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.