JJONG`sFACTORY
반응형

old - prisma schema 분리

서론

글을 작성 하던 도중, prisma 에서 드디어 스키마 분리를 지원해 준다는 이슈가 작성 되었다.

 

Support for splitting Prisma schema into multiple files · Issue #2377 · prisma/prisma

Problem Prisma currently only supports one single Prisma Schema file. Developers want more flexibility for managing their Prisma Schema files. Motivations: breaking up large schema files to make th...

github.com

 

Hey, we just released support for multiple-file Prisma Schema setups! It is behind the prismaSchemaFolder preview feature:

Release Notes: https://github.com/prisma/prisma/releases/tag/5.15.0
Documentation: https://prisma.io/docs/orm/prisma-schema/overview/location#multi-file-prisma-schema
Announcement blog post: https://www.prisma.io/blog/organize-your-prisma-schema-with-multi-file-support

Please try it out and leave feedback in this discussion: #24413

 

이에 따라 기존에 스키마를 분리하는 방식은 굳이 필요 없게 되었지만, 위 내용에 따른 추가 내용은 추후 기재 하도록 하고 기존 방식에 대해서 서술을 먼저 작성 해보아야 겠다.

 

기존 방식은 심플하게, 각 `model/[table-schema].prisma` 파일들을 병합하여 `schema.prisma`에 out 하는 형태로 작업하였다.

 

스키마 파일을 합치기 위한 코드 작성

prisma-model-merge.mjs
javascript
import { exec } from 'child_process'; import { promisify } from 'util'; import chalk from 'chalk'; import os from 'os'; import fs from 'fs'; // promisify를 사용하여 exec 함수를 Promise 기반으로 변환 const execAsync = promisify(exec); const prismaPath = './prisma' const schemaPath = `${prismaPath}/schema.prisma` const tempSchemaPrismaFile = `${prismaPath}/temp_schema.prisma` const defaultSchemaPrismaFile = `${prismaPath}/default_schema.prisma` // TODO :: window 환경에서도 돌아갈 수 있도록 처리 const checkOs = () => { if(os.platform() !== 'linux') { console.error(chalk.red('You can run this script only on Linux operating systems.')) process.exit(1); } } const getCurrentDateTime = () => { const now = new Date(); const year = now.getFullYear().toString().slice(-2); const month = (now.getMonth() + 1).toString().padStart(2, '0'); const date = now.getDate().toString().padStart(2, '0'); const hours = now.getHours().toString().padStart(2, '0'); const minutes = now.getMinutes().toString().padStart(2, '0'); const seconds = now.getSeconds().toString().padStart(2, '0'); return `${year}${month}${date}${hours}${minutes}${seconds}`; } async function checkFolderExists(folderPath) { try { const stats = await fs.promises.stat(folderPath); return stats.isDirectory(); } catch (err) { if (err.code === 'ENOENT') { return false; } console.log(chalk.red('folder check fail.')) process.exit(1); throw err; } } const createFolder = async (folderPath) => { try { await fs.promises.mkdir(folderPath); } catch (e) { console.log(chalk.red('An error occurred while creating the backup folder.')) process.exit(1); } } const rollbackSchema = async (message) => { console.error(message) await execAsync('rm ./prisma/temp_schema.prisma'); process.exit(1); } const removeFile = async (filePath) => { return await execAsync(`rm ${filePath}`); } const getPrismaModelFileList = async () => { const { stdout, stderr } = await execAsync('find ./prisma/model -type f -name "*.prisma"'); if (stderr) { await rollbackSchema(`모델 파일을 읽어 오는 도중 오류가 발생하였습니다.: ${stderr}`) } return stdout } const newLineTempFile = async() => { return await execAsync(`echo >> ${tempSchemaPrismaFile}`); } const convertModelFile = async (fileList) => { // prisma/model 디렉토리에 있는 모든 .prisma 파일을 temp_schema.prisma 파일에 추가 // await execAsync('find ./prisma/model -type f -name "*.prisma" -exec cat {} \\; -exec echo \\; >> ./prisma/temp_schema.prisma'); for (const fileName of fileList) { console.log(chalk.yellow(`READ ${fileName}`)) try { await execAsync(`cat ${fileName} >> ${tempSchemaPrismaFile}`) await newLineTempFile() await newLineTempFile() } catch (e) { console.error(chalk.red(e)) await rollbackSchema(`${fileName} MERGE FAILED. ROLLBACK THIS JOB.`) } console.log(chalk.green(`MERGE ${fileName} SUCCEED.`)) } console.log(chalk.green('ALL MODEL FILE CONVERT SUCCEED.')) } async function updateSchema() { checkOs() try { // 백업 폴더 없으면 생성 if(!await checkFolderExists(`${prismaPath}/backup`)) { await createFolder(`${prismaPath}/backup`) } // 현재 스키마 정보 백업 await execAsync(`cat ${schemaPath} >> ${prismaPath}/backup/${getCurrentDateTime()}_schema.prisma`) // default_schema.prisma 파일을 temp_schema.prisma 파일에 추가 await execAsync(`cat ${defaultSchemaPrismaFile} >> ${tempSchemaPrismaFile}`); // DB 접속정보와 model을 구분하기 위하여 개행 두번 처리 await newLineTempFile() await newLineTempFile() // 현재 동기화된 상태를 확인하기 위하여, 각 파일에 따로 접근하도록 처리 const getSchemaFileStdout = await getPrismaModelFileList() const fileNames = getSchemaFileStdout.trim().split('\n'); await convertModelFile(fileNames) // temp_schema.prisma 파일을 schema.prisma 파일로 복사 await execAsync(`cat ${tempSchemaPrismaFile} > ${schemaPath}`); await removeFile(tempSchemaPrismaFile) } catch (error) { await rollbackSchema(`ERROR: ${error.message}`) } } // 함수 호출 updateSchema().then(() => { console.log(chalk.green('😊PRISMA SCHEMA FILE MERGE SUCCEED!😊')) });

 

 

호출 명령어 추가

package.json
json
"scripts": { "prisma:model": "node prisma-model-merge.mjs", //... }

 

pakage.json 파일에 명령어를 추가하여 위에서 작성한 실행 코드를 해당 명령어로 쉽게 호출 하기 위함이다.

 

 

 

default-schema.json 파일 작성

위에서 작성한 코드로 schema 파일을 산출하게 되면, schema.prisma 파일에 계속 되어 동일 코드가 추가되는 문제가 발생한다.

 

따라서, 기본 스키마를 작성하고 해당 파일을 토대로 schems.prisma 파일을 산출 할 수 있도록 추가해 준다.

prisma/default_schema.prisma
prisma
generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") }

 

 

sample model file 작성

 

prisma/model/test.prisma
prisma
model Test { creator String creator_program_id String creator_ip String updator String? updator_program_id String? updator_ip String? created_at DateTime @default(now()) updated_at DateTime @default(now()) deleted_at DateTime? }

 

테스트를 위하여, sample model 파일을 작성한다.

 

병합 실행

bash
npm run prisma:model

 

병합 명령어를 실행한다.

다만 위 코드는 linux 기반에서만 동작하게 되어 있기 때문에 window 환경으로는 wsl을 이용하여 구동시켜보자.

 

아래와 같이 정상적으로 구동 된다면 모든 스키마 파일이 병합되어 schema.prisma 파일이 생성된다.

 

NEW - 새로운 방식의 schema 분리 방법 (^5.15.0)

서론

위에서 언급 하였듯 드디어 prisma 에서 schema를 분리 작성 할 수 있게 지원 해 준다.

기존에 위에 언급한 방식으로 작업 하셨던 분들은 크게 추가적으로 작업을 해 줄 필요는 없이 일부만 수정하면 바로 적용이 가능하였다.

 

지금부터 prisma 5.15.0에서 추가된 schema 분리 작성 방법에 대해 알아보자.

필수 필요 항목

 

필요 항목

  • VS Code
  • prisma : ^5.15.0
  • @prisma/client: ^5.15.0

 

 

INFO

현재 prisma의 schema 분리 방식을 지원해 주는 plugin을 제공해주는 에디터가 VSCode 뿐이다. Intellij 쪽 계열은 아직 지원해 주지 않으니, 작성시에 문법 오류라고 판단 할 수 있다.

기존에 primsa로 작업하고 있던 분들은 package.json 에서 prisma, @prisma/client의 버전을 올려서 작업해야 한다.

 

구현

Schema.prisma 파일 변경

먼저 `schema.prisma` 파일에 generator client 부분을 다음과 같이 수정한다.

schema.prisma
prisma
generator client { provider = "prisma-client-js" previewFeatures = ["prismaSchemaFolder"] // 추가 }

 

디렉토리 구조 변경

디렉토리 구조를 아래와 같이 변경한다.

각 schemaFolder 안에는 모델을 정의한 .prisma 파일이 존재한다.

 

기존 문서 에서 작성한 model을 기준으로 보면 다음과 같은 디렉토리 구조를 가지고 있을 것이다.

bash
prisma └── schema ├── post │   └── post.prisma ├── schema.prisma └── user └── user.prisma

 

각 모델 파일들의 코드는 다음과 같다.

user.prisma
prisma
model User { id Int @default(autoincrement()) @id email String @unique name String? posts Post[] }
post.prisma
prisma
model Post { id Int @default(autoincrement()) @id title String content String? published Boolean? @default(false) author User? @relation(fields: [authorId], references: [id]) authorId Int? }

TIP

schema 폴더 명은 반드시 schema일 필요는 없다.

다만, schema.prisma 파일은 해당 폴더 하위에 반드시 존재 하여야 한다.

 

db push 실행

다음 명령어로 db push 를 실행한다.

bash
npx prisma db push --schema prisma/schema

 

일반적으로 아래와 비슷한 내용을 확인할 수 있다.

실제 DB 스키마에 접근해 보면, 테이블들이 생성 되었음을 확인 할 수 있다.

bash
PS C:\workspace> npx prisma db push --schema prisma/schema Environment variables loaded from .env Prisma schema loaded from prisma\schema Datasource "db": PostgreSQL database "DB", schema "SCHEMA" at "localhost:5432" Your database is now in sync with your Prisma schema. Done in 117ms ✔ Generated Prisma Client (v5.15.0) to .\node_modules\@prisma\client in 146ms

 

참조링크

 

관련 포스트

 

반응형

'JAVASCRIPT > nest.js' 카테고리의 다른 글

[NestJS] NestJS + prisma CRUD  (0) 2024.06.11
[nest.js] nest.js + prisma - setting  (0) 2024.05.10
[nest.js] module reference  (2) 2023.10.02
[Nest.js] Circular dependency  (0) 2023.10.02