FullStackProject[0] - Set Up MikroORM

About Project

이 프로젝트는 Ben AwadFullstack React GraphQL TypeScript Tutorial를 따른다.

본 포스트는 동영상의 모든 내용을 다루지 않는다.

Add Typescript

Install

yarn add @type/node typescript ts-node

Add scripts

"watch": "tsc -w", // watch and compile input files
"start": "node dist/index.js"

What is ORM?

무엇이든 새로운 지식을 습득할 때는 용어가 중요하다. ORM에 대해서 알아보자

Object–relational mapping

Open Database Connectivity

간단히 말해서 자신이 사용하는 프로그래밍 언어의 OOP 컨텍스트 내에서 데이터베이스에 접근하고, 저장된 데이터를 객체 형태로 사용할 수 있게해주는 테크닉이다.

예를 들어, 타입스크립트 코드를 통해서 데이터베이스의 쿼리문을 수행하고 그 결과를 자신이 사용하는 프로그래밍 언어의 객체에 담게 해주는 기술이다.

SQL 베이스의 언어의 ORM Sequelize, NoSQL인 mongodb의 mongoose(이 경우, ODM)이 이러한 테크닉을 이용한 라이브러리라 할 수 있다.

Ben Awad의 풀스택 프로젝트에서는 MikroORM을 사용한다.

MikroORM

MikroORM이란?

MikroORM Official

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns.

공식 홈페이지에 나와 있는 설명에 따르면 타입스크립트 전용 ORM이다.

SQL, NoSQL 둘 다 지원한다.

Set Up

어떤 라이브러리 든지, 초반에 셋팅하는 작업을 반드시 이해해야 한다. 시작이 반이다.

Install

yarn add @mikro-orm/cli @mikro-orm/core @mikro-orm/migrations @mikro-orm/postgresql pg
- @mikro-orm/core # MikroORM core package
- @mikro-orm/postgrsql # database driver package for postgresql
- @mikro-orm/cli # for using MikroORM CLI commandline tools 
- pg # Non-blocking PostgreSQL client for Node.js

mikro-orm.config.js

참고 문서 - MikroORM Configuration Reference

MikroORM의 commandline tool을 사용하기 위해 먼저 mikro-orm.config.js을 만든다. 이름에서 알 수 있듯이 ORM의 configuration을 설정하는 파일이다.

// package.json

  "mikro-orm": {
    "useTsNode": true,
    "configPaths": [
      "./src/mikro-orm.config.ts",
      "./dist/mikro-orm.config.js"
    ]
  }

package.json에 해당 내용을 추가한다. configPaths에서 configuration파일의 위치를 명시해준다.

그런 다음 mikro-orm.config.js에 다음 내용을 추가한다.

import { MikroORM } from "@mikro-orm/core";
import { __prod__ } from "./constants";
import { Post } from "./entities/Post";
import path from "path";

const config = {
  migrations: {
    path: path.join(__dirname, "./migrations"), // path to the folder with migrations
    pattern: /^[\w-]+\d+\.[tj]s$/, // regex pattern for the migration files
  },
  dbName: "lireddit",
  user: "leejss",
  password: "1234",
  debug: !__prod__,
  type: "postgresql",
  entities: [Post],
} as Parameters<typeof MikroORM.init>[0];

export default config;

여기서 주목할 것은 database와 connection을 결정할 DriverConnection 부분이다. 해당 부분에 대한 자세한 내용은 공식 홈페이지에 자세히 나와있다.

dbName
user
password
type

내용을 알맞게 설정해야 한다.

그런데 MySQL과 Mongodb는 이미 설치되어 있지만 PostgrSQL은 설치가 안 되어 있다.

PostgreSQL을 설치해보자.

WSL2 and PostgreSQL

Get started with databases on Windows Subsystem for Linux

WSL2를 사용한다면 간단하게 터미널을 통해서 postgresql을 설치할 수 있다. 설치방법은 위 링크에 나온 순서를 따라한다면 무난하게 설치할 수 있다.

Create User

프로젝트에서 사용할 유저를 생성해준다.

데이터베이스를 시작하고 postgresql shell에 들어간다.

sudo service postgresql start
sudo -u postgres sql

유저를 생성하는 쿼리문을 작성한다.

postgres=#CREATE USER leejss;

현재 유저목록을 확인한다. 생성된 유저를 확인한다.

postgres=# \du

새로 생성한 유저에게 ROLE을 부여한다.

postgres=# ALTER USER leejss SUPERUSER CREATEDB;

유저의 비밀번호를 변경한다.

postgres=# ALTER USER leejss with PASSWORD '1234';

그런 다음 현재 연결된 유저와 데이터베이스를 변경한다.

# \c - leejss;
# \c lireddit;

FATAL: Peer authentication failed for user

유저를 변경하려고 시도한 경우 다음과 같은 에러가 발생할 것이다.

에러를 해결하기 위해서는 postgresql의 conf파일을 수정해야 한다.

$code /etc/postgresql/12/main/pg_hba.conf

데이터베이스 버전은 다를 수 있지만 어쨌든 pg_hba.conf 파일을 수정하기 위해 에디터를 열어준다.

파일 맨 밑에

# "local" is for Unix domain socket connections only
local   all             all                                     peer

에서 peer 부분을 md5로 변경한다.

이제 유저를 변경해도 에러가 발생하지 않는다.

Create Entity

참고문서: Defining Entities

Object Mapping을 위한 Entity를 만들어야 한다. src폴더에 entities폴더를 생성하고 Post.ts 를 생성한다.

MikroORM은 entity를 생성하는 두 가지 방법을 제시한다. 그 중 Decorated classes를 사용할 것이다.

import { Entity, Property, PrimaryKey } from "@mikro-orm/core";

@Entity()
export class Post {
  @PrimaryKey()
  id!: number;

  @Property({ type: "text" })
  title!: string;

  @Property({ type: "date" })
  createdAt = new Date();

  @Property({ type: "date", onUpdate: () => new Date() })
  updatedAt = new Date();
}

클래스 정의 위에 @Entity()를 작성하여 Entity를 정의하고 @Property() 데코레이터를 사용하여 속성을 규정한다.

공식문서에서 Decorators Reference에 관한 내용을 살펴볼 수 있다.

Migration

참고 1: Data migration

참고 2: MikroORM Migrations

간단하게 말해서 migration이란 데이터베이스 플랫폼을 바꾸는 것을 말한다.

postgresql이 아닌 다른 데이터베이스를 사용하더라도 코드가 정상적으로 작동하도록 설정하는 것이다.

mikro-orm.config.js에 다음 내용을 추가하여 migration을 설정한다.

  migrations: {
    path: path.join(__dirname, "./migrations"), // path to the folder with migrations
    pattern: /^[\w-]+\d+\.[tj]s$/, // regex pattern for the migration files
  },
  // ...

Execute migration

migration을 수행하는 방식에는 두 가지가 있다.

Uisng CLI

npx mikro-orm migration:create   # Create new migration with current schema diff

이 외 다른 커맨드는 공식 문서에서 찾아볼 수 있다.

Using Migrator

const main = async () => {
  // ...
  await orm.getMigrator().up(); // // runs migrations up to the latest
  // ...
};

migration을 수행하면 src폴더에 migrations폴더가 생기고 쿼리문을 수행하는 파일이 생기는 것을 볼 수 있다.

import { Migration } from '@mikro-orm/migrations';

export class Migration20210507110852 extends Migration {

  async up(): Promise<void> {
    this.addSql('create table "post" ("id" serial primary key, "title" text not null, "created_at" timestamptz(0) not null, "updated_at" timestamptz(0) not null);');
  }

}