Prisma는 현대적인 데이터베이스 ORM(Object-Relational Mapping) 도구로, 데이터베이스와 애플리케이션 사이의 상호작용을 간소화하고 효율적으로 관리할 수 있도록 도와준다. Prisma는 TypeScript와 JavaScript 환경에서 사용될 수 있으며, 다양한 데이터베이스 시스템과 호환되게 된다.
npm install prisma 로 prisma를 설치한다.

설치 후 위와 같이 npx prisma init 을 실행시키게 되면,
prisma/schema.prisma 폴더와
.env 폴더가 자동 생성되는 것을 확인할 수 있다.
schema.prisma 폴더에서 어떤 데이터베이스를 사용할 건지 정할 수 있게 되어있는데,
sqlite를 사용할 예정이다.
SQLite는 경량화된 관계형 데이터베이스 관리 시스템
SQLite는 서버가 필요 없으며, 데이터베이스 파일을 애플리케이션과 함께 배포하여 사용할 수 있는 특징을 가지고 있다.
가장 큰 특징은. 데이터베이스를 단일 파일로 저장한다.
이 파일에는 모든 데이터와 데이터베이스 구조가 포함되어 있다. 서버 프로세스 없이 파일만으로 데이터베이스를 운영할 수 있게 된다.
DATABASE_URL="file:./database.db" -> 이에 DATABASE_URL의 주소를 file:./database.db로 즉 파일로 저장을 시켜주었다.
테이블을 모델이라고 할 수 있는데, 카테고리처럼 우리 DB안에 있는 객체 같은 것을 의미함.
DB에 있는 모델은 최소한 한개의 고유한 기준을 가져야 한다 --> 기본적으로 고유한 식별자가 필요함
Prisma 모델(Prisma Model)은 데이터베이스 테이블의 구조를 정의하는 Prisma Schema 파일(schema.prisma) 내의 개별 단위이다. 모델은 데이터베이스 테이블의 필드(컬럼)와 그 속성(제약 조건, 기본값 등)을 정의하여 Prisma가 해당 테이블과 상호작용할 수 있도록 한다.
model User {
id Int @id @default(autoincrement())
//default -> autoincrement() -> 첫번째 사용자를 생성할 때 첫번쨰 사용자의 id = 1이 됨
username String @unique
email String? @unique
//사용자가 핸드폰 번호로 로그인 하는 경우가 있어서 필수가 아니기 때문에 ?물음표를 달아줌
password String?
phone String? @unique
github_id String? @unique
avatar String?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
}
user라는 모델을 만들고, 이 모델을 prisma에게 알려주게 된다.
그리고 그걸 우리 DB와 주고 받으면서, 그리고 우릴 위한 Prisma Client를 만들어달라고 할 것이다.
--> 그러려먼 npx prisma migrate dev 명령어를 실행하면 된다.
이렇게 SQLite database database.db created at file:./database.db 하며 데이터베이스가 만들어 졌다는 알림 문구를 확인할 수 있다.
여기서 migration 이란?
마이그레이션(Migration)은 데이터베이스의 구조를 변경하는 과정을 의미한다.
예를 들어, 새로운 테이블을 추가하거나 기존 테이블에 열을 추가하거나, 열의 속성을 변경하는 등의 작업이 포함된다.
Prisma와 같은 도구를 사용할 때, 데이터베이스 스키마(데이터베이스의 구조나 설계) 가 변경되면 이를 반영하기 위해 "마이그레이션"이라는 작업을 수행한다.
이 과정에서 변경 사항을 SQL 스크립트로 기록하고, 이를 데이터베이스에 적용하여 실제로 구조가 바뀌도록 한다.
마이그레이션을 통해 데이터베이스와 애플리케이션 코드 간의 일관성을 유지할 수 있으며, 이전 변경 사항을 추적하고 필요한 경우 되돌릴 수 있다.
add_user 이라는 이름의 migration을 생성했다.
그럼 migrations의 폴더가 생성되게 되는데,
현재 시간과 함께 add_user 폴더를 생성하고, 안에 migration.sql 폴더가 생성되었다.
migration.sql

이 파일에는 Prisma가 생성한 SQL 명령어가 포함되어 있으며, 이 명령어는 데이터베이스에 적용될 스키마 변경 사항을 정의하게 된다.
Your database is now in sync with your schema.
이 메시지는 데이터베이스의 현재 상태가 Prisma Schema 파일(schema.prisma)과 일치함을 의미한다.
Prisma Studio는 Prisma로 관리하는 데이터베이스를 시각적으로 탐색하고 조작할 수 있는 웹 기반 GUI 도구이다. 개발자가 데이터베이스의 데이터를 손쉽게 조회하고 수정할 수 있도록 돕는 강력한 툴을 나타낸다.
npx prisma studio 명령어를 실행시키면, localhost:5555 가 열리게 된다.
그림과 같이 Add record를 누르고 새로운 user를 생성하고 save를 하면, 새로운 user가 생성이 된다.
이렇게 생성한 user는 유효한 값이다..!
또한 email을 수정하거나, 삭제하거나 user를 수정하거나 삭제하는 등의 기능도 모두 가능하다.
추가된 user는 database.db에서 확인이 가능하다!

SMSToken을 만들어 볼 예정이다.
여기서, SMSToken은
사용자가 SMS로그인을 시도할 때,
사용자가 자신의 핸드폰 번호를 입력 -> 이 번호로 새로운 사용자를 생성하거나, 사용자가 존재한다면, 이 전화번호를 가진 사용자를 찾게 된다. -> 그 후, 사용자에게 토큰을 담아서(인증번호)를 담아서 SMS에 전송 (이 사람이 이 전화번호를 소유한 사람인지 확인하기 위해서) -> 이 토큰이 담긴 SMS를 받은 사용자가 토큰(인증번호)를 입력 -> DB에서 토큰을 받아서 DB내 저장된 토큰이 있는지 찾아볼 것임
이런 과정이 이루어지려면, SMS토큰은 사용자와 연결되어 있어야 한다.
이 사용자에게 보낸 토큰이 예를 들면 '111111'이라고 가정하면, DB에 사용자 - '111111'이런 식으로 연결이 되어있어야 이 토큰과 연결된 사용자가 누군지 찾을 수 있게 된다.
따라서 우리는 DB에서 사용자를 찾고 -> 로그인을 시킬 수 있게 된다.

Prisma에서 두 개의 모델이 서로 관계를 가지려면, 양쪽 모델에 모두 관계 필드가 정의가 되어있어야 한다.
User 모델의 SMSToken 필드는 배열로 정의되어 있는 것을 확인할 수 있다.
즉, 한 명의 User가 여러 개의 SMSToken을 가질 수 있으며, 때로는 아무 SMSToken도 가지지 않을 수 있.
반면에, SMSToken 모델에서 user 필드는 필수이다.
이는 각 SMSToken이 반드시 하나의 User와 연관되어야 함을 의미한다. userId가 정의되지 않은 SMSToken은 존재할 수 없다.
user User @relation(fields: [userId], references: [id])
userId Int
여기서 user User @relation(fields: [userId], references: [id]) 는
이건 DataBase에게 userId를 어디서 찾아야 할지를 알려주는 역할임
fields: [userId]: SMSToken 모델에서 외래 키 역할을 하는 필드
--> 이 필드는 User 모델의 특정 레코드(ID)를 참조한다.
예를 들어, userId가 1이라면, 이 SMSToken은 User 모델에서 id가 1인 사용자와 연결된다.
references: [id]: User 모델에서 참조되는 필드를 지정
--> 여기서 id 필드는 User 모델의 기본 키로, SMSToken 모델의 userId가 참조하는 대상이 된다.
여기 userId만이 정수형으로 저장이 되는데, 데이터베이스에 실제로 저장되는 값은 이거 하나임
이렇게 model SMSToken을 생성하면, schema.prisma를 수정할 때마다 DB에 알려줘야 함을 알아야 한다.
그리고 Prisma Client를 다 생성해주어야 한다는 것도 기억해야 한다.
npx prisma migrate dev 를 실행시켜
현재 데이터베이스와 schema와 sync를 맞춰주어야 한다 !

이렇게 SMSToken을 create 생성해보았다.
token의 값을 '123123'을 주었고, user id가 3인 user와 연결시켜 주었다.
이렇게 생성하면,
userId가 3으로 출력되면서 user의 id가 3인 것과 연결된 것을 확인할 수 있다.
이번에는 SMSToken에 저장된 것을 찾아보자 (findUnique()를 이용)
SMSToken 테이블에서 id가 2인 레코드를 찾고, 그 레코드와 연결된 User 정보도 포함해서 가져온다. (include는 관련된 데이터를 추가로 가져오고 싶을 때 사용하는 옵션)
여기 있는 include 객체는 관계를 포함하는데 사용된다.
만약, SMSToken이 사용자를 가지고 있다면 SMSToken을 검색할 때, 사용자를 포함시킬 수 있다
예를 들면, SMSToken에서 userId를 1로 가져왔을 때,
prisma랑 db는 userId가 user의 id임을 알고 있기 때문에 DB가 실제로 userId가 참조하고 있는 사용자를 찾아서 가져올 수 있는 것이다!

page.tsx에 import를 한 후, 페이지를 새로고침을 해보면, ![]
SMSToken의 id가 2인 SMSToken의 데이터와,
SMSToken에 user가 포함된 데이터가 출력되는 것을 확인할 수 있다!
여기서 userId 가 user의 id와 같음을 확인할 수 있다!
만약, 사용자가 회원탈퇴를 한다.
그럼 사용자에 대한 정보는 사라진다 -> 그럼 사용자와 연결되어 있던 SMSToken은 어떻게 되어야 하는가? --> 역시 마찬가지로 삭제 되어야 한다.

onDelete : Cascade 속성을 적용시켜 주었다.
이 속성을 적용시켜주어야 user가 삭제 되었을 때, 연결되어있는 SMSToken의 행동 역시 결정할 수 있다.
Prisma -> 강력한 번역기
Prisma는 DB를 위한 Client도 생성한다. -> 타입스크립트로 DB랑 소통할 수 있음.
이걸 사용하기 위해서 Prisma에게 DB에 저장될 데이터의모양과 타입을 설명해주어야 한다.
--> (DB의 형상을 Prisma에게 설명해주는 것임) -> npx prisma migrate dev 명령어를 실행하면 -> SQL 코드로 작성된 수 많은 마이그레이션이 생성된다.
그리고 DB를 수정함 -> 우리가 원했던 데이터의 형태로 수정
클라이언트를 생성해주는데, 그 클라이언트는 db.ts에서 초기화함
schema.prisma 에서 무언갈 수정했다면, 변경사항을 DB에게 알리기 위해서 migrate 를 해야 함
--> 그러면 Prisma는 우리를 위해 Client를 다시 생성함
const db = new PrismaClient()