Project using Nest.js/E-commerce App
nestJS entity
Cog Factory
2021. 9. 2. 12:33
common.entity.ts
import { Field, ObjectType } from '@nestjs/graphql';
import {
CreateDateColumn,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
@ObjectType()
export class CoreEntity {
@PrimaryGeneratedColumn()
@Field((type) => Number)
id: number;
@CreateDateColumn()
@Field((type) => Date)
createdAt: Date;
@UpdateDateColumn()
@Field((type) => Date)
updatedAt: Date;
}
user.entity.ts
import {
Field,
InputType,
ObjectType,
registerEnumType,
} from '@nestjs/graphql';
import { IsBoolean, IsEmail, IsEnum, IsString } from 'class-validator';
import { BeforeInsert, Column, Entity } from 'typeorm';
import * as bcrypt from 'bcrypt';
import { CoreEntity } from 'src/common/entities/common.entity';
import { InternalServerErrorException } from '@nestjs/common';
export enum UserRole {
Consumer = 'Consumer',
Provider = 'Provider',
}
enum Language {
Korean = 'Korean',
English = 'English',
}
registerEnumType(UserRole, { name: 'UserRole' });
registerEnumType(Language, { name: 'Language' });
@InputType('UserInputType', { isAbstract: true })
@ObjectType()
@Entity()
export class User extends CoreEntity {
@Column({ unique: true })
@Field((type) => String)
@IsEmail()
email: string;
@Column()
@Field((type) => String)
@IsString()
password: string;
@Column({ type: 'enum', enum: UserRole, default: UserRole.Consumer })
@Field((type) => UserRole)
@IsEnum(UserRole)
role: UserRole;
@Column({ default: false })
@Field((type) => Boolean)
@IsBoolean()
verified: boolean;
@Column({ default: Language.Korean })
@Field((type) => Language)
@IsEnum(Language)
language: Language;
@Column({ nullable: true })
@Field((type) => String, { nullable: true })
@IsString()
bio?: string;
@BeforeInsert()
async hashPassword(): Promise<void> {
if (this.password) {
try {
this.password = await bcrypt.hash(this.password, 10);
} catch (e) {
console.error(e);
throw new InternalServerErrorException();
}
}
}
async checkPassowrd(password: string): Promise<boolean> {
try {
const ok = await bcrypt.compare(password, this.password);
return ok;
} catch (error) {
console.error(error);
throw new InternalServerErrorException();
}
}
}
- @Entity() decorator는 entity를 정의할 수 있게 해준다. 그 안에 email, password 등의 필드들을 정의할 수 있다. TypeORM을 위한 코드다.
ref : https://docs.nestjs.com/techniques/database#repository-pattern - @ObjectType() decorator는 Graphql을 위한 코드다.
ref : https://docs.nestjs.com/graphql/resolvers#object-types - @InputType()는 DTOs를 위한 코드다. mapped types를 위해서 @InputType()을 해줘야 한다. 그리고 InputType에 'UserInputType'이라고 이름을 지정해줘야 한다. 그렇지 않으면 나중에 reloation field가 있을 때 @ObjectType가 충돌하여 error가 발생한다. 그리고 InputType은 DB에 등록되는 것이 아니므로 isAbstract를 설정한다.
ref : https://docs.nestjs.com/graphql/mapped-types#partial
- @Column()은 TypeORM의 Schema로 정의하는 decorator다. @Column()을 하고 밑에 field를 정의하면 db field에 등록된다.
- @Field()는 graphql의 type을 정의한다.
- @IsEmail(), @IsString() 등은 class-validator로 유효성 검사를 한다.
- enum type은 registerEnumType(UserRole, { name: 'UserRole' });를 사용하여서 등록해서 쓸 수 있다.
- entity 안에 method를 선언할 수 있다. ex) checkPassword
- @BeforeInsert() decorator를 이용해서 데이터가 db에 저장되기 이전에 process 할 수 있다.
- await bcrypt.hash() function이 있는데, password는 저장되기 전에 무조건 해시를 한 후 저장해야 한다.
- Installation : $ npm i bcrypt
Validation
Entity에서 @IsEmail()같이 validate를 하는 decorator가 있다.
$ npm i class-transformer class-validator
두 개 모듈을 설치함으로써 사용할 수 있다. 그리고 app.useGlobalPipes(new ValidationPipe());를 추가한다.
참고 자료
- 노마드 코더의 우버 이츠 클론 강의
- @Entity() : https://docs.nestjs.com/techniques/database#repository-pattern
- @ObjectType() : https://docs.nestjs.com/graphql/resolvers#object-types
- @InputType() : https://docs.nestjs.com/graphql/mapped-types#partial