1. TypeORM 설치 npm install typeorm @nestjs/typeorm mysql
  2. 프로젝트 루트에 ormconfig.json 파일을 만들어서 데이터베이스 연결 정보를 설정
{
  "type": "mysql",
  "host": "localhost",
  "port": 3306,
  "username": "your_username",
  "password": "your_password",
  "database": "your_database_name",
  "entities": ["dist/**/*.entity{.ts,.js}"],
  "synchronize": true
}
  1. 엔티티 생성
// user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  username: string;

  @Column()
  email: string;
}
  1. 컨트롤러/서비스 계층에서 사용
// user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  async findAll(): Promise<User[]> {
    return this.userRepository.find();
  }

  async create(user: User): Promise<User> {
    return this.userRepository.save(user);
  }
}
// user.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { User } from './user.entity';
import { UserService } from './user.service';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  async findAll(): Promise<User[]> {
    return this.userService.findAll();
  }

  @Post()
  async create(@Body() user: User): Promise<User> {
    return this.userService.create(user);
  }
}

※ 복잡한 조회 쿼리도 가능하고, SQL 쿼리문 자체를 사용하는 것도 가능하다고 함

/* 
복잡한 조건 조회
user 엔티티에서 나이가 18 이상이며 이메일이 '[email protected]'인 사용자를 조회하는 예시
createQueryBuilder를 사용하여 복합적인 where 조건을 설정할 수 있음
*/
const users = await userRepository
  .createQueryBuilder('user')
  .where('user.age > :age', { age: 18 })
  .andWhere('user.email = :email', { email: '[email protected]' })
  .getMany();

/* 
정렬 및 페이징
user 엔티티를 나이 순으로 정렬하고, 11번째부터 20번째 사용자를 가져오는 예시
orderBy로 정렬을 설정하고 skip(10)으로 11번째 결과부터 시작하며, take(10)으로 10개의 결과를 가져옴
*/
const users = await userRepository
  .createQueryBuilder('user')
  .orderBy('user.age', 'ASC')
  .skip(10)
  .take(10)
  .getMany();

/* 
관계로 연결된 데이터 조회
findOne() 메서드를 사용하여 ID가 1인 사용자를 조회하고, 이 사용자의 posts 관계를 가져오는 예시
relations 옵션을 사용하여 관련 엔티티를 조회
결과적으로 user.posts를 통해 이 사용자와 관련된 모든 게시물에 액세스할 수 있게 됨
*/
const user = await userRepository.findOne(1, { relations: ['posts'] });

/*
서브쿼리
subQuery() 메서드를 사용하여 서브쿼리를 정의하고, 이를 메인 쿼리에 포함시킴
이 예시에서는 'TypeORM Example'라는 제목을 가진 Post 엔티티의 사용자를 조회
*/
const users = await userRepository
  .createQueryBuilder('user')
  .where(qb => {
    const subQuery = qb
      .subQuery()
      .select('post.userId')
      .from(Post, 'post')
      .where('post.title = :title', { title: 'TypeORM Example' })
      .getQuery();
    return 'user.id IN ' + subQuery;
  })
  .getMany();

/*
이너 조인
위의 서브쿼리를 사용한 것과 동일한 결과
innerJoinAndSelect 메서드를 사용하여 user와 post 엔티티를 조인하고, post.title이 "TypeORM Example"인 게시물만을 선택하는 이너 조인을 수행
*/
const users = await userRepository
  .createQueryBuilder('user')
  .innerJoinAndSelect('user.posts', 'post', 'post.title = :title', { title: 'TypeORM Example' })
  .getMany();

// 원시 SQL문 사용
const result = await connection.query('SELECT * FROM users WHERE age > ? AND email = ?', [18, '[email protected]']);