2023. 11. 30. 20:01ใBack-End ์์ ์ค/๋ฌธ์ ์ ๋ฆฌ
NestJS๋ก ๋ฐฐ์ฐ๋ ๋ฐฑ์๋ ํ๋ก๊ทธ๋๋ฐ:ํ์ ์คํฌ๋ฆฝํธ ํ๊ฒฝ์ ์ฐจ์ธ๋ ์๋ฒ ํ๋ ์์ํฌ๋ฅผ ๋ง๋๋ค
COUPANG
www.coupang.com
"์ด ํฌ์คํ ์ ์ฟ ํก ํํธ๋์ค ํ๋์ ์ผํ์ผ๋ก, ์ด์ ๋ฐ๋ฅธ ์ผ์ ์ก์ ์์๋ฃ๋ฅผ ์ ๊ณต๋ฐ์ต๋๋ค."
GitHub - junyharang-coding-study/GraphQL-Study: GraphQL์ ๊ณต๋ถํ๊ณ , ์ค์ตํ ์ฝ๋์์ ๐
GraphQL์ ๊ณต๋ถํ๊ณ , ์ค์ตํ ์ฝ๋์์ ๐. Contribute to junyharang-coding-study/GraphQL-Study development by creating an account on GitHub.
github.com
๐ทโ๏ธ ์์ ์ค์ธ ๋ด์ฉ
์ด ๊ธ์ Nest.JS๋ฅผ ์ด์ฉํด GraphQL ์ค์ต ํ๊ฒฝ ๊ตฌ์ฑ ์ค Mock Data๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํด TypeORM Extension์ Seeding์ ํ๋ฉด์ ๋ฐ์ํ ๋ฌธ์ ์ ๋ํด ์ ๋ฆฌํ๋ ๊ธ์ด์์.
Seeding์ ํด์ ์๋ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋ฉด Enbedded SQLite์ ์์ ๊ฐ์ด Mock Data๊ฐ Table์ ๋ง์ถฐ ์
๋ ฅ๋๊ฑธ ํ์ธํ ์ ์์ด์.
โ ๏ธ ๋ฌธ์ ๋ฐ์!
ํ์ง๋ง ๋ฌธ์ ๋ ์์ ๊ฐ์ด ๊ด๊ณ๊ฐ ๋งบ์ด์ ธ ์๋ Table์์ ํด๋น Table์ FK ๊ฐ์ด ๋ค์ด๊ฐ์ง ์๋๋ค๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ด์.
๐ค ์์ธ ๋ถ์
์ด๋ ์์ ๊ฐ์ด Supply๋ Team๊ณผ ๊ด๊ณ๋ฅผ ๋งบ๊ณ ์๊ณ , FK๋ก team_id๋ฅผ ๊ฐ์ง๊ณ ์์ด์.
Supply Entity์ 10 ~ 11๋ฒ์งธ ์ค์ ๋ณด๋ฉด Team๊ณผ ์ฐ๊ด ๊ด๊ณ๋ฅผ ๋งบ์๊ณ , ํ๋์ Supply๋ ์ฌ๋ฌ Team๊ณผ ๊ด๊ณ๋ฅผ ๋งบ๊ธฐ ๋๋ฌธ์ Many To One์ผ๋ก ๊ด๊ณ๋ฅผ ๋งบ์ด ์ฃผ์์ผ๋ฉฐ, ์ด ๋, N + 1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์ดํ๊ณ ์ Entity Type์ Promise๋ก ์ค์ ํด ์ฃผ์์ด์.
์ด๊ฒ์ ํด๋น ๊ด๊ณ๋ฅผ Lazy Relations๋ก ์ค์ ํ๊ฒ ๋ค๋ ์๋ฏธ์์.
Lay Relations(์ง์ฐ ๊ด๊ณ)๋ฅผ ๋งบ๊ฒ ๋๋ฉด ํด๋น Entity์ ์ ๊ทผ ํ ๋๋ง ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋๊ฒ ๋ผ์.
์์ SupplyEntity์ 11๋ฒ์งธ ์ค team ๊ฐ์ฒดํ ๋ณ์๋ Pramise<TeamEntity>๋ก ๋ฐ์์ผ ํ๋๋ฐ,
Seeder๋ฅผ ๋ณด๋ฉด Team Table์ ๊ฐ์ด ๋ค์ด๊ฐ๊ณ ๋์ ํด๋น Table์ teamId๋ก ํ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์
๊ฐ๊ฐ์ ์์ํ ๋ณ์์ ๋ฃ์ด์ฃผ๋ ๊ฑธ ๋ณผ ์ ์์ด์.
๊ทธ๋ฆฌ๊ณ ๋์ Supply Table์ insert๋ฅผ ํ ๋, ์์ ๊ฐ์ด team Field์ ํด๋น ๊ฐ์ฒด๋ฅผ ๋ฃ์ด์ฃผ๋ ค๊ณ ํ๋
๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฑธ ์ ์ ์์ด์.
๐ป ๋ฌธ์ ํด๊ฒฐ!
์ต์ด ์ด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์๋ ์์กด์ฑ์ ์ค์นํด ์ฃผ์ด์ผ ํด์.
์ ๋ช
๋ น์ด๋ฅผ ํตํด TypeScript ํ์ผ ์คํ ์ ๋์์ ๋ฐ์ ์ ์๋ ํจํค์ง๋ฅผ ์ค์นํ ์ ์๋๋ฐ,
-D Options(์ต์
)์ ์ด ํจํค์ง๋ค์ด devDependencies์ ์ค์น ๋๋๋ก ํ๋ ์ต์
์ด์์.
์ด๊ฒ์ ๊ฐ๋ฐ ํ๊ฒฝ์์๋งํ์ํ๊ณ , ์ด์ํ๊ฒฝ์์๋ ์ฐ์ง ์๊ฒ ๋ค๋ ์๋ฏธ์์.
์ด๋ ๊ฒ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋ฉด TypeScript ์ฝ๋๋ฅผ ์ง์ Node.js ํ๊ฒฝ์์ ์คํํ ์ ์๋ ๋๊ตฌ ts-node๊ฐ ์ค์น๋๊ณ , ์ด๊ฒ์ Node.js๋ JavaScript ์ฝ๋๋ง ์คํํ ์ ์๋๋ฐ,
์ด๋ฅผ ํตํด TypeScript ํ์ผ์ ์ง์ ์คํํ ์ ์๋๋ก ๋์์ฃผ๋ ํจํค์ง์์.
๊ทธ๋ฆฌ๊ณ , TypeScript ํ๋ก์ ํธ์์ ์ค์ ๋ tsconfig.json ํ์ผ์ paths ์ค์ ์ ํ์ฉํ์ฌ Module ๊ฒฝ๋ก๋ฅผ ํด์ํ ์
์๋๋ก ๋์์ฃผ๋ ํจํค์ง๊ฐ ๋ฐ๋ก tsconfig-paths์์. ์ด๊ฒ์ ํตํด TypeScript๋ก ์์ฑ๋ ์ฝ๋์์ Import ๊ตฌ๋ฌธ์
์ฌ์ฉํ ๋, ๊ฒฝ๋ก๋ฅผ ์ค์ ํ๋ฉด ํด๋น ๊ฒฝ๋ก๋ฅผ ํด์ํ ์ ์๊ฒ ๋์์ค๋ต๋๋ค.
์์ ๊ฐ์ด Project(ํ๋ก์ ํธ) Root(๋ฃจํธ) Directory(๋๋ ํฐ๋ฆฌ)์ ์ ๋ด์ฉ์ ์
๋ ฅํด ์ฃผ์ด์ผ ํด์.
์ด์ ๋ํ ์์ธํ ๋ด์ฉ์ ์ด ๊ณณ์ ์์ฑํด ์ฃผ์์ด์.
๊ทธ๋ฆฌ๊ณ ์์ ๊ฐ์ด package.json script{}์ TypeORM migraion ๊ด๋ จ Script๋ฅผ ๋ฃ์ด์ฃผ์์ด์.
์ด๋ ๊ณต์ ๋ฌธ์์ ์ข ๋ค๋ฅด๊ฒ ์ค์ ํด ์ฃผ์๋๋ฐ,
์ด์ ๋ TypeORM CLI๊ฐ ์ ๋ ๊ฒฝ๋ก๋ฅผ ์ดํดํ์ง ๋ชปํด ๊ณต์ ๋ฌธ์๋๋ก ํ๊ฒ ๋๋ฉด
can not found module Error๋ฅผ ๋ด๋ฑ๊ธฐ ๋๋ฌธ์ด์์.
๊ทธ๋์ ์์๋ก ์ ๋ ๊ฒฝ๋ก๋ฅผ ์ดํด์ํค๊ธฐ ์ํด ์์์ ts-node์ tsconfig-paths ํจํค์ง๋ฅผ ์ค์นํ ๊ฑฐ๊ณ ,
Script ๋ฌธ์ ts-node -r tsconfig-paths/register๋ฅผ ๋ฃ์ด์ค ๊ฑฐ์์.
npm ๋ช ๋ น์ด(์ต์ ) | ์ ์ธ ๋ด ์ฉ |
npm run migration:run | ๊ฐ๊ฐ์ Migration File์ up()์์ ์์ฑํ ๋ด์ฉ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ Query ์ ๋ฌ ๋ฐ ๋ฐ์. |
npm run migration:revert | ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ ์ ์ฉ๋ ๊ฐ๊ฐ์ Migration File์ down()์์ ์์ฑํ ๋ด์ฉ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ Query ์ ๋ฌ ๋ฐ ๋ฐ์. ๋จ, ๊ฐ์ฅ ์ต๊ทผ์ Migration File์ up()์ ํตํด ์ ๋ฌํ ๋ด์ฉ๋ง ๋จ, ํ๋ฒ ๋๋๋ฆผ. |
npm run migration:create | ์๋ก์ด Migration File ์์ฑ. |
npm run migration:grnerate | Migration ์๋ ์์ฑ. |
npm run schema:drop | ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ชจ๋ ์คํค๋ง ์ญ์ ๋ฅผ ์ํ Query ์ ๋ฌ ๋ฐ ๋ฐ์. |
npm run schema: sync | ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง๋ฅผ Update(์ต์ ํ)ํ์ฌ ํ์ฌ ์์ค ์ฝ๋์ Entity์ ์ผ์นํ๋๋ก ์์ . |
์ฌ๊ธฐ๊น์ง ํ ๋ค Entity๋ฅผ ๋ง๋ค์ด ์ค๋๋ค. Entity ์ญ์ ์ด ๊ณณ์ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
์ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋ฉด
import { MigrationInterface, QueryRunner } from "typeorm";
export class Migration1701333148773 implements MigrationInterface {
name = 'Migration1701333148773'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "software" ("software_id" varchar(255) PRIMARY KEY NOT NULL, "used_by" varchar(255) NOT NULL, "developed_by" varchar NOT NULL, "description" varchar NOT NULL, CONSTRAINT "UQ_4ef15228013fdc93b76c9339283" UNIQUE ("software_id"))`);
await queryRunner.query(`CREATE TABLE "team" ("team_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "manager" varchar(255) NOT NULL, "office" varchar(5) NOT NULL, "extension_number" varchar(5) NOT NULL, "mascot" varchar(10), "cleaning_duty" varchar(10) NOT NULL, "project" varchar(10) NOT NULL, CONSTRAINT "UQ_a35a345d4436b82adf6bb76f3ce" UNIQUE ("team_id"))`);
await queryRunner.query(`CREATE TABLE "people" ("people_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "last_name" varchar(255) NOT NULL, "first_name" varchar(255) NOT NULL, "sex" varchar(6) NOT NULL, "blood_type" varchar(2) NOT NULL, "serveYears" integer NOT NULL, "role" varchar(100) NOT NULL, "hometown" varchar NOT NULL, "team_id" integer, CONSTRAINT "UQ_017abdefead91b361b5e7ac108f" UNIQUE ("people_id"))`);
await queryRunner.query(`CREATE TABLE "role" ("role_id" varchar(255) PRIMARY KEY NOT NULL, "job" varchar(255) NOT NULL, "requirement" varchar NOT NULL, CONSTRAINT "UQ_df46160e6aa79943b83c81e496e" UNIQUE ("role_id"))`);
await queryRunner.query(`CREATE TABLE "equipment" ("equipment_id" varchar(255) PRIMARY KEY NOT NULL, "used_by" varchar(255) NOT NULL, "count" integer NOT NULL, "new_or_used" varchar(10) NOT NULL, CONSTRAINT "UQ_88b371a2f0b8ae33b1060f00189" UNIQUE ("equipment_id"))`);
await queryRunner.query(`CREATE TABLE "supply" ("supply_id" varchar(255) PRIMARY KEY NOT NULL, "teamTeamId" integer, CONSTRAINT "UQ_ea803c518d575c82cd33f5668df" UNIQUE ("supply_id"))`);
await queryRunner.query(`CREATE TABLE "temporary_people" ("people_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "last_name" varchar(255) NOT NULL, "first_name" varchar(255) NOT NULL, "sex" varchar(6) NOT NULL, "blood_type" varchar(2) NOT NULL, "serveYears" integer NOT NULL, "role" varchar(100) NOT NULL, "hometown" varchar NOT NULL, "team_id" integer, CONSTRAINT "UQ_017abdefead91b361b5e7ac108f" UNIQUE ("people_id"), CONSTRAINT "FK_6b7b841de9de9db18199f718ee9" FOREIGN KEY ("team_id") REFERENCES "team" ("team_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_people"("people_id", "last_name", "first_name", "sex", "blood_type", "serveYears", "role", "hometown", "team_id") SELECT "people_id", "last_name", "first_name", "sex", "blood_type", "serveYears", "role", "hometown", "team_id" FROM "people"`);
await queryRunner.query(`DROP TABLE "people"`);
await queryRunner.query(`ALTER TABLE "temporary_people" RENAME TO "people"`);
await queryRunner.query(`CREATE TABLE "temporary_supply" ("supply_id" varchar(255) PRIMARY KEY NOT NULL, "teamTeamId" integer, CONSTRAINT "UQ_ea803c518d575c82cd33f5668df" UNIQUE ("supply_id"), CONSTRAINT "FK_cd14bd0c792703a7fce50828bb0" FOREIGN KEY ("teamTeamId") REFERENCES "team" ("team_id") ON DELETE NO ACTION ON UPDATE NO ACTION)`);
await queryRunner.query(`INSERT INTO "temporary_supply"("supply_id", "teamTeamId") SELECT "supply_id", "teamTeamId" FROM "supply"`);
await queryRunner.query(`DROP TABLE "supply"`);
await queryRunner.query(`ALTER TABLE "temporary_supply" RENAME TO "supply"`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "supply" RENAME TO "temporary_supply"`);
await queryRunner.query(`CREATE TABLE "supply" ("supply_id" varchar(255) PRIMARY KEY NOT NULL, "teamTeamId" integer, CONSTRAINT "UQ_ea803c518d575c82cd33f5668df" UNIQUE ("supply_id"))`);
await queryRunner.query(`INSERT INTO "supply"("supply_id", "teamTeamId") SELECT "supply_id", "teamTeamId" FROM "temporary_supply"`);
await queryRunner.query(`DROP TABLE "temporary_supply"`);
await queryRunner.query(`ALTER TABLE "people" RENAME TO "temporary_people"`);
await queryRunner.query(`CREATE TABLE "people" ("people_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "last_name" varchar(255) NOT NULL, "first_name" varchar(255) NOT NULL, "sex" varchar(6) NOT NULL, "blood_type" varchar(2) NOT NULL, "serveYears" integer NOT NULL, "role" varchar(100) NOT NULL, "hometown" varchar NOT NULL, "team_id" integer, CONSTRAINT "UQ_017abdefead91b361b5e7ac108f" UNIQUE ("people_id"))`);
await queryRunner.query(`INSERT INTO "people"("people_id", "last_name", "first_name", "sex", "blood_type", "serveYears", "role", "hometown", "team_id") SELECT "people_id", "last_name", "first_name", "sex", "blood_type", "serveYears", "role", "hometown", "team_id" FROM "temporary_people"`);
await queryRunner.query(`DROP TABLE "temporary_people"`);
await queryRunner.query(`DROP TABLE "supply"`);
await queryRunner.query(`DROP TABLE "equipment"`);
await queryRunner.query(`DROP TABLE "role"`);
await queryRunner.query(`DROP TABLE "people"`);
await queryRunner.query(`DROP TABLE "team"`);
await queryRunner.query(`DROP TABLE "software"`);
}
}
๊ทธ๋ผ ์์ ๊ฐ์ด ํ์ผ์ด ์๋์ผ๋ก ์์ฑ๋ ๊ฑฐ์์.
์ด ํ์ผ์ ๋ณด๋ฉด DML Query๊ฐ ์์ฑ ๋์ด ์๋๋ฐ, ์ด๋ Entity๋ฅผ ๊ธฐ๋ฐ์ผ๋ก TypeORM์ด ๋ง๋ค์ด ์ค๊ฑฐ์์.
์ด๋ฒ์๋ Team๊ณผ Supply์ ๋ํ Migraion์ ๋ง๋ค์ด ๋ณผ๊ฒ์.
์ด ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋ฉด ์์ ๊ฐ์ด Project Root Directory์ ์์ ๊ฐ์ด
TypeScript ํ์ฅ์๋ฅผ ๊ฐ์ ํ์ผ์ด ์์ฑ๋๋๊ฑธ ํ์ธํ ์ ์์ด์.
์ฃผ๋๋ ์์ ๊ฐ์ด Directory๋ฅผ ๋ณ๊ฒฝํด์ ์ฌ์ฉํด ๋ณด๋ ค๊ณ ํด์.
up()์ ๋ํด ๋ถ์์ ํด๋ณผ๊ฒ์. ์ด Method(๋ฉ์๋)๋ Database(๋ฐ์ดํฐ๋ฒ ์ด์ค)
Scheam(์คํค๋ง)๋ฅผ ๋ณ๊ฒฝํ๊ณ , ํน์ Table(ํ
์ด๋ธ)์ ์์ฑํ๋ ์ญํ ์ ํ๋ ์น๊ตฌ์์.
up()์ queryRunner.createTable()์ ํ์ฉํ์ฌ team์ด๋ผ๋ ํ
์ด๋ธ์ ๋ง๋ค๊ฒ ํด์ฃผ๋๋ฐ,
์ด ๋, team_id๋ bigint Type์ ์ปฌ๋ผ์ ๋ง๋ค๊ณ , ๊ธฐ๋ณธ ํค์ด๋ฉฐ,
์๋์ผ๋ก ์์ฑ๋๋ increment ์ ๋ต์ ์ฌ์ฉํ๊ฒ ๋ค๊ณ ๋ช
์ํด ์ค ๊ฒ์ด์์.
name์ varchart Type์ผ๋ก Null์ ํ์ฉํ์ง ์๊ฒ ๋ค๊ณ ๋ช
์ํด ์ค ๋ถ๋ถ์ด์์.
isPrimary๋ ํด๋น ์ปฌ๋ผ์ด ๊ธฐ๋ณธ ํค์ธ์ง ์ฌ๋ถ๋ฅผ ๋ช
์ํด์ฃผ๊ธฐ ์ํด ์ฌ์ฉํ ๊ฒ์ด๊ณ ,
isGenerated๋ ํด๋น ์ปฌ๋ผ์ด ์๋์ผ๋ก ์์ฑ๋๋์ง ์ฌ๋ถ๋ฅผ ๋ช
์ํด ์ฃผ๊ธฐ ์ํด ์ฌ์ฉํ ๊ฒ์ด๊ณ ,
generationStrategy๋ ์๋ ์์ฑ๋๋ ์ปฌ๋ผ ์ ๋ต์ ์ง์ ํ๊ธฐ ์ํด ๋ช
์ํ ๊ฒ์ธ๋ฐ,
์ ์ฝ๋๋ Increament ์ ๋ต์ ์ฌ์ฉํ๊ฒ ๋ค๊ณ ๋ช
์ํ ๋ถ๋ถ์ด์์.
์ด๋ ๊ฒ ํด์ team Table์ ์์ฑํ๋ Migration์ ๋ง๋ค์๊ณ , up()์ ํตํด Table์ ์์ฑํ๊ณ ,
down()์ ํตํด ํด๋น Table์ด ์ญ์ ๋ ์ ์๋๋ก Logic์ ๊ตฌํํ์์ด์.
๊ทธ๋ฆฌ๊ณ ์์ ๊ฐ์ด team Table์ ๋ค์ด๊ฐ Mock Data๋ฅผ ๋ช
์ํด ์ฃผ์์ด์.
ํ์ง๋ง, TypeORM์ ์ฌ์ฉํ๊ณ ์๊ณ , Entity๋ฅผ ๊ตฌ์ฑํด์ค ๋ค
์์ ๊ฐ์ด synchronize๋ฅผ true๋ก ํด์ฃผ๋ฉด TypeORM์ด ์์์ Entity๋ฅผ ๋ถ์ํด์ Table๊ณผ Column์ ๋ง๋ค์ด ์ฃผ์ด์.
ํ์ง๋ง, ์ํ๋ ์์ ์ ์ ์๋ ์คํค๋ง(Entity)๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ํด์ผ ํ๋๋ฐ, ์์ ๊ฐ์ด ํ๊ฒ ๋๋ฉด ์๋ฒ๊ฐ ๊ธฐ๋๋ ๋๋ง๋ค ์คํค๋ง์ ๋ฐ๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ๊ฐ ๋ณ๊ฒฝ๋ ์ ์๊ธฐ ๋๋ฌธ์ ๋งค์ฐ ์ ์คํด์ผ ํด์.
๊ทธ๋์ ๋ง์ด ์ด์ฉํ๋ ๊ฒ์ด Migration์ด์์.
๊ทธ๋์ ์์ ๊ฐ์ด ๋ณ๊ฒฝํด ์ฃผ์์ด์.
์ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋ฉด
์ด๋ ๊ฒ ๋ง๋ค์ด์ง๋ค๊ณ ํ๋๋ฐ,
๋ณด์๋ค์ํผ DDL ๋ฌธ์ด ๋ค์ด๊ฐ ์๊ณ , TABLE์ ๋ง๋๋ SQL์ด ๋ค์ด๊ฐ ์๋๊ฑธ ๋ณผ ์ ์์ด์.
์ด ๊ตฌ๋ฌธ๋ค๋ก ์ธํด synchronize๋ฅผ False๋ก ํด๋ Table์ด ์์์ ๋ง๋ค์ด์ ธ์.
์ต์ด ์์ ๊ฐ์ด team Table์ ๋ง๋ค์ด ์ฃผ์์ด์.
๊ทธ๋ฆฌ๊ณ team Table๊ณผ ๊ด๊ณ๋ฅผ ๋งบ๊ธฐ ์ํด team_id๋ฅผ FK๋ก ์ค์ ํด ์ฃผ์์ด์.
๊ทธ๋ฆฌ๊ณ DML Native Query๋ฅผ ์ด์ฉํด์ Mock Data๋ฅผ ๋ฃ์ ์ ์๋๋ก ์ฒ๋ฆฌํด ์ฃผ์์ด์.
import { MigrationInterface, QueryRunner, Table } from "typeorm";
export class SeedTeam1701325303468 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
const teamTableExist = await queryRunner.hasTable("team");
if (!teamTableExist) {
await queryRunner.createTable(
new Table({
name: "team",
columns: [
{ name: "team_id", type: "integer", isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "manager", type: "varchar", isNullable: false },
{ name: "office", type: "varchar", isNullable: false },
{ name: "extension_number", type: "varchar", isNullable: false },
{ name: "mascot", type: "varchar", isNullable: false },
{ name: "cleaning_duty", type: "varchar", isNullable: false },
{ name: "project", type: "varchar", isNullable: false },
],
}),
true,
);
}
//Seeding Data ์ฝ์
await queryRunner.query(
`INSERT INTO \`team\` (\`manager\`, \`office\`, \`extension_number\`, \`mascot\`, \`cleaning_duty\`, \`project\`) VALUES ('Mandy Warren', '101A', '#5709', 'Panda','Monday','Hyperion')`,
);
await queryRunner.query(
`INSERT INTO \`team\` (\`manager\`, \`office\`, \`extension_number\`, \`mascot\`, \`cleaning_duty\`, \`project\`) VALUES ('Stewart Grant', '101B', '#4012', 'Tadpole','Tuesday','Zen')`,
);
await queryRunner.query(
`INSERT INTO \`team\` (\`manager\`, \`office\`, \`extension_number\`, \`mascot\`, \`cleaning_duty\`, \`project\`) VALUES ('Smantha Wheatly', '102A', '#3852', 'Falcon','Wednesday','Duranno')`,
);
await queryRunner.query(
`INSERT INTO \`team\` (\`manager\`, \`office\`, \`extension_number\`, \`mascot\`, \`cleaning_duty\`, \`project\`) VALUES ('Francis Buckley', '103B', '#1039', 'Beaver','Thursday','Genghis')`,
);
await queryRunner.query(
`INSERT INTO \`team\` (\`manager\`, \`office\`, \`extension_number\`, \`mascot\`, \`cleaning_duty\`, \`project\`) VALUES ('Blake Smith', '104A', '#7750', 'Wildcat','Friday','Acheron')`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable("team");
}
}
TeamSeed๋ ์์ ๊ฐ์ด ๋ง๋ค์ด ์ฃผ์์ด์.
โ JunySS ๐ฐ ๎ฐ ~/Programming/study/graphql-study/type-script-nest-graph-ql-์ค์ต ๎ฐ ๎ master ±โ ๎ฐ npm run migration:run
> type-script-nest-graph-ql-์ค์ต@0.0.1 migration:run
> npm run typeorm migration:run
> type-script-nest-graph-ql-์ค์ต@0.0.1 typeorm
> ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js --dataSource ./data-source.ts migration:run
query: SELECT * FROM "sqlite_master" WHERE "type" = 'table' AND "name" = 'migrations'
query: SELECT * FROM "migrations" "migrations" ORDER BY "id" DESC
0 migrations are already loaded in the database.
2 migrations were found in the source code.
2 migrations are new migrations must be executed.
query: PRAGMA foreign_keys = OFF
query: BEGIN TRANSACTION
query: SELECT * FROM "sqlite_master" WHERE "type" = 'table' AND "name" = 'supply'
query: CREATE TABLE "supply" ("supply_id" varchar NOT NULL, "team_id" integer NOT NULL, CONSTRAINT "FK_88d10c4e569685c8345705b213f" FOREIGN KEY ("team_id") REFERENCES "team" ("team_id") ON DELETE CASCADE)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('ergonomic mouse', 1)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('mug', 1)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('webcam', 2)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('hoodie', 2)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('chair', 3)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('usb hub', 3)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('headphone', 4)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('stempler', 4)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('calculator', 5)
query: INSERT INTO `supply` (`supply_id`, `team_id`) VALUES ('t shirt', 5)
query: INSERT INTO "migrations"("timestamp", "name") VALUES (1701325299045, ?) -- PARAMETERS: ["SeedSupply1701325299045"]
Migration SeedSupply1701325299045 has been executed successfully.
query: SELECT * FROM "sqlite_master" WHERE "type" = 'table' AND "name" = 'team'
query: SELECT * FROM "sqlite_master" WHERE "type" = 'table' AND "name" = 'team'
query: CREATE TABLE "team" ("team_id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "manager" varchar NOT NULL, "office" varchar NOT NULL, "extension_number" varchar NOT NULL, "mascot" varchar NOT NULL, "cleaning_duty" varchar NOT NULL, "project" varchar NOT NULL)
query: INSERT INTO `team` (`manager`, `office`, `extension_number`, `mascot`, `cleaning_duty`, `project`) VALUES ('Mandy Warren', '101A', '#5709', 'Panda','Monday','Hyperion')
query: INSERT INTO `team` (`manager`, `office`, `extension_number`, `mascot`, `cleaning_duty`, `project`) VALUES ('Stewart Grant', '101B', '#4012', 'Tadpole','Tuesday','Zen')
query: INSERT INTO `team` (`manager`, `office`, `extension_number`, `mascot`, `cleaning_duty`, `project`) VALUES ('Smantha Wheatly', '102A', '#3852', 'Falcon','Wednesday','Duranno')
query: INSERT INTO `team` (`manager`, `office`, `extension_number`, `mascot`, `cleaning_duty`, `project`) VALUES ('Francis Buckley', '103B', '#1039', 'Beaver','Thursday','Genghis')
query: INSERT INTO `team` (`manager`, `office`, `extension_number`, `mascot`, `cleaning_duty`, `project`) VALUES ('Blake Smith', '104A', '#7750', 'Wildcat','Friday','Acheron')
query: INSERT INTO "migrations"("timestamp", "name") VALUES (1701325303468, ?) -- PARAMETERS: ["SeedTeam1701325303468"]
Migration SeedTeam1701325303468 has been executed successfully.
query: COMMIT
query: PRAGMA foreign_keys = ON
์์ ๊ฐ์ด Query๊ฐ ๋ ์๊ฐ๋ฉด์ Mock Data๊ฐ ๋ฃ์ด์ง๊ฑธ ํ์ธํ ์ ์์ด์.
๋ง์ฝ ์ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ๋๋ฐ, ์ด๋ฏธ ์ด๋ค Table์ด ๋ง๋ค์ด์ ธ ์๋ค๋ Error๊ฐ ๋์ค๊ฒ ๋๋ฉด
์ด ๋ช
๋ น์ด๋ ์
๋ ฅํ์ง ๋ง๊ณ , ์งํํ๋ฉด ๋๊ณ ,
์ด๋ฏธ ์
๋ ฅํ๋ค๋ฉด ์ด ๋ช
๋ น์ด๋ก ๋ง๋ค์ด์ง TypeScript ํ์ผ์ ์ญ์ ํด ์ฃผ๋ฉด ๋ผ์.
ํด๋น Error๋ generate๋ก Table์ ์ด๋ฏธ ๋ง๋ค์๋๋ฐ, Seed์์ ๋ Table์ ๋ง๋๋ ค๊ณ ํ๋ ๋ฐ์๋๋ ๋ฌธ์ ์ด๊ธฐ ๋๋ฌธ์ด์์.
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ๋ ์ ๋ค์ด๊ฐ ๊ฑธ ํ์ธํ ์ ์์ด์.
NestJS๋ก ๋ฐฐ์ฐ๋ ๋ฐฑ์๋ ํ๋ก๊ทธ๋๋ฐ:ํ์ ์คํฌ๋ฆฝํธ ํ๊ฒฝ์ ์ฐจ์ธ๋ ์๋ฒ ํ๋ ์์ํฌ๋ฅผ ๋ง๋๋ค
COUPANG
www.coupang.com
"์ด ํฌ์คํ ์ ์ฟ ํก ํํธ๋์ค ํ๋์ ์ผํ์ผ๋ก, ์ด์ ๋ฐ๋ฅธ ์ผ์ ์ก์ ์์๋ฃ๋ฅผ ์ ๊ณต๋ฐ์ต๋๋ค."
GitHub - junyharang-coding-study/GraphQL-Study: GraphQL์ ๊ณต๋ถํ๊ณ , ์ค์ตํ ์ฝ๋์์ ๐
GraphQL์ ๊ณต๋ถํ๊ณ , ์ค์ตํ ์ฝ๋์์ ๐. Contribute to junyharang-coding-study/GraphQL-Study development by creating an account on GitHub.
github.com
๐ง ์ฐธ๊ณ ์๋ฃ
How to seed TypeORM
There is no need for any packages. It is very straightforward. I am using it to seed my production server with some initial data like…
sushilkbansal.medium.com
[NestJS] TypeORM ๋ง์ด๊ทธ๋ ์ด์
TypeORM ๋ง์ด๊ทธ๋ ์ด์ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด๊ธฐ
velog.io
'Back-End ์์ ์ค > ๋ฌธ์ ์ ๋ฆฌ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring Boot 3.0] Could not resolve org.springframework.boot:spring-boot-gradle-plugin (0) | 2023.12.12 |
---|