- user
- commands ( DB 에 수정을 가하는 Logic )
- create-user
- update-user
- database ( DB 모델 및 처리 담당 Repository Logic )
- user.repository.ts
- user.repository.port.ts ( DDD 위한 파일 , 불필요 )
- domain ( Business Logic들 포함한 폴더 )
- user.entity.ts ( Business 를 포함한 파일
- user.error.ts ( Logic 내 발생하는 Error 모은 파일 )
- user.types.ts ( Logic 에 필요한 Type 모은 파일 )
- queris ( DB 에 조회를 가하는 Logic )
- user-di.token.ts
- user.module.ts
create-user-command.ts
import { Command, CommandProps } from '@src/libs/ddd/command-base';
export class CreateUserCommand extends Command {
readonly email: string;
readonly password: string;
readonly nickname: string;
constructor(props: CommandProps<CreateUserCommand>) {
super(props);
this.email = props.email;
this.password = props.password;
this.nickname = props.nickname;
}
}
create-post.controller.ts
import { CommandBus } from '@nestjs/cqrs';
import { Result, match } from 'oxide.ts';
async create(@Body() createUserProps: CreateUserProps): Promise<ResponseBase<{id:string}>> {
const command = new CreateUserCommand(createUserProps);
const result: Result<string, UserAlreadyExistsError> =
await this.commandBus.execute(command);
return match(result, {
Ok: (id: string) => new ResponseBase({id}),
Err: (error: UserAlreadyExistsError) => {
throw error;
},
});
}
create-post.service.ts
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { Err, Ok, Result } from 'oxide.ts';
@CommandHandler(CreatePostCommand)
export class CreatePostCommandHandler implements ICommandHandler {
constructor(
@Inject(POST_REPOSITORY)
private readonly postRepository: PostRepositoryPort,
) {}
async execute(command: CreatePostCommand): Promise<Result<string, Error>> {
const { content, title, userId, imageUrl } = command;
const post = PostEntity.create({ title, content, userId, imageUrl });
try {
await this.postRepository.createPost(post);
return Ok(post.id);
} catch (error: any) {
throw Err(new DBInsertError(error));
}
}
}
read-post.service.ts
import { Inject } from '@nestjs/common';
import { IQueryHandler, QueryHandler } from '@nestjs/cqrs';
import { Err, Ok, Result } from 'oxide.ts';
import { JwtProvider } from '@src/providers/jwt.provider';
import { POST_REPOSITORY } from '../../post.di-token';
import PostRepositoryPort from '../../database/post.repository.port';
import { ReadPostQuery } from './read-post-query';
import { PostNotExistsError } from '../../post.errors';
import { PostProps } from '../../domain/post.types';
@QueryHandler(ReadPostQuery)
export class ReadPostQueryHandler implements IQueryHandler {
constructor(
@Inject(POST_REPOSITORY)
private readonly postRepository: PostRepositoryPort,
private readonly jwtProvider: JwtProvider,
) {}
async execute(query: ReadPostQuery): Promise<Result<PostProps, Error>> {
try {
const record = await this.postRepository.readPost(query.postId);
if (!record) return Err(new PostNotExistsError());
return Ok(record);
} catch (err) {
throw err;
}
}
}
사실 , DataSource 와 크게 연관이 X!
핵심은 , 비즈니스 로직에 존재하는 도메인 모델에 Query 침투 방지가 핵심!