DB에서 Index를 만들자
DB는 potato를 찾아달라고 해서 기본적으로 a부터 찾기 시작함. 이게 기본 동작임.
하지만 index를 만들면 I부터 시작하는 식.
기본적으로 MsSQL DB는 relation이 생길 때마다 index 자동 생성해줌.

그러나 pscale은 이렇게 동작하지 않고, index를 생성하지 않기 때문에
User의 모든 Product를 보여달라고 하면
pscale은 DB에서 Product테이블 가서 모든 product를 뒤져서 해당 USER의 id를 가진 product를 골라온다.
너무 느리겠지. 그리고 테이블 읽을 때마다 돈 내기 때문에 비용문제도 생김.
다시말하지만 MySQL은 이런 인덱스를 알아서 생성한다.
인덱스를 통해 DB에 어떤 상품이 있는지 알 수있다.
그래서 새 상품 만들면 DB에 새 상품 데이터가 추가될거고, 추가로 index도 업데이트가 된다.
인덱스는 DB와 분리된 것이라 보면 됨.
그래서 id가 1인 유저가 상품을 등록하면 상품이 DB에 추가되고, 인덱스도 업데이트 된다.
그래서 아이디가 1인 유저의 상품을 조회하면 시간이 오래 걸리는 DB를 검색하는 대신
바로 인덱스를 조회한다.


아래 정리 잘 돼있네.
https://spiderwebcoding.tistory.com/6

아무튼 이렇게 바꾸고, 해당 브랜치에 연결 된 상태에서 기존과 똑같이 아래 명령어를 내리면 된다.

npx prisma db push

그리고 deploy request를 보내자.

깃헙처럼 변경된게 보여진다.

메인 브랜치가 업데이트 된걸로보아 merge가 된거다.
그래서 indexes 브랜치를 지울 수 있음. 역할이 끝났거든.
근데 그냥 dev브랜치 따서 지우지말고 계속 푸시하면되겠찌.

planet scale에서 Database를 dev와 prod로 나누어보자.
prod 브랜치로 promote하면 아래 3가지 좋은 점이 있다.
1, 스키마 직접수정 불가
2. 가용성 증대
3. 자동백업

그리고 브랜치를 만들고 연결해보자.

pscale connect carrot-market indexes
//indexes는 새 브랜치 이름

To update your main branch, you can make schema changes to this branch. Once you're ready, open a deploy request with your changes.

브랜치 바뀌면 데이터도 사라짐. 같은 스키마를 갖고 있지만 data는 다르다.

14.0 Upload Form
늘 하던 패턴의 반복.
Model -> Form(useForm()) -> useMutation() 
14.1 Detail Page
14.2 Send Message
14.3 See Message
14.4 Mutations and Refresh
14.5 Seeding - prisma의 seeding 가짜 데이트베이스 많이 생성 하는 법.

1. seed.ts파일 생성

seed.ts파일 생성

2. 한 유저가 많이 생성 한것처럼 코드짜고

import { PrismaClient } from "@prisma/client";
// next.js의 바깥쪽

const client = new PrismaClient();

async function main() {
  [...Array.from(Array(500).keys())].forEach(async (item) => {
    await client.stream.create({
      data: {
        name: String(item),
        description: String(item),
        price: item,
        user: {
          connect: {
            id: 13, //내 아이디
          },
        },
      },
    });
    console.log(`${item}/500`);
  });
}
main()
  .catch((e) => console.log(e))
  .finally(() => client.$disconnect());


3. npm i ts-node 설치(https://www.npmjs.com/package/ts-node)
이게 뭐냐? TypeScript execution and REPL for node.js, with source map and native ESM support.
REPL이란  : Node. js Read-Eval-Print-Loop (REPL) is an easy-to-use command-line tool, used for processing Node. js expressions. It captures the user's JavaScript code inputs, interprets, and evaluates the result of this code. It displays the result to the screen, and repeats the process till the user quits the shell.
브라우저 개발자 모드에 있는 console대신 쓸수 있는 듯

이거말하는듯

5. package.json맨 아래에 해당 명령어 추

6. 그리고 바로 npx prisma db seed 명령어 치면 에러 남.
SyntaxError: Cannot use import statement outside a module

7. 그럼 package.json에서 다음처럼 수정
참고: https://www.prisma.io/docs/guides/database/seed-database 

그리고 . npx prisma db seed다시 치면
데이터 400개쯤 만들다가 get kicked out 됨.
왜? planetscale은 무료로 1000개정도 커넥션 제공하는데 이건 문제가 안됨.
https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/connection-pool#external-connection-poolers

대신, pool time out 때문에 그렇다.
Pool은 데이터 모으는거고, pool timeout은 이게 정해진 시간 넘도록 특정 쿼리 처리 못하면 exception을 던지고 다음 쿼리로 감.
The default connection pool timeout is 10 seconds. If the query engine does not process a particular query within that time, it throws an exception and moves on to the next query in the queue.
근데 serverless가 아닌 일반 서버는 데이터베이스가 허용하는 연결의 수 제한이 매우 작음
근데 우리는 planetscale이 1000개의 동시연결이 가능하단걸 prisma에게 알려주지 않았다.
그래서 prisma에서 시간 초과가 되었다. 우린 일반 DB보다 훨씬 빨랐기 때문에!

연결 limit을 늘리거나, 커넥션이 더 길어져도 된다면 그걸 늘리면 됨.
schema.prisma 파일에  추가
https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/connection-pool#external-connection-poolers

 

datasource db { provider = "postgresql" url = "postgresql://johndoe:mypassword@localhost:5432/mydb?connection_limit=5&pool_timeout=2" }





14.6 Pagination
Try not to fry our database
아래처럼 포함하고 있는 관계에도 pagination할 수 있다. 
아니 무조건 해야 한다. 

다 돈이거든

 

prisma 로그 출력하는 방법


참고로 표준출력이란 stdout: https://ko.wikipedia.org/wiki/%ED%91%9C%EC%A4%80_%EC%8A%A4%ED%8A%B8%EB%A6%BC

SELECT `carrot-market`.`Stream`.`id`, `carrot-market`.`Stream`.`created`, `carrot-market`.`Stream`.`updated`, `carrot-market`.`Stream`.`name`, `carrot-market`.`Stream`.`description`, `carrot-market`.`Stream`.`price`, `carrot-market`.`Stream`.`userId` FROM `carrot-market`.`Stream` WHERE 1=1 ORDER BY `carrot-market`.`Stream`.`id` ASC LIMIT ? OFFSET ?

 

'클론코딩-캐럿마켓 > 전반' 카테고리의 다른 글

16 NEXTJS IMAGES  (0) 2023.01.12
15 CLOUDFLARE IMAGES - 사진 다루기  (0) 2023.01.11
13 Profile  (0) 2023.01.09
12 동네생활  (0) 2023.01.06
11 Products  (0) 2023.01.04

12.0 Models
포스트와 그 포스트에 대한 궁금증과, 답변, 궁금해요 모델 추가.

model Post {
  id         Int         @id @default(autoincrement())
  created    DateTime    @default(now())
  updated    DateTime    @updatedAt
  user       User        @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId     Int
  question   String      @db.MediumText
  answers    Answer[]
  wonderings Wondering[]

  @@index([userId])
}

model Answer {
  id      Int      @id @default(autoincrement())
  created DateTime @default(now())
  updated DateTime @updatedAt
  user    User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId  Int
  post    Post     @relation(fields: [postId], references: [id], onDelete: Cascade)
  postId  Int
  answer  String   @db.MediumText

  @@index([userId])
  @@index([postId])
}

model Wondering {
  id      Int      @id @default(autoincrement())
  created DateTime @default(now())
  updated DateTime @updatedAt
  user    User     @relation(fields: [userId], references: [id], onDelete: Cascade)
  userId  Int
  post    Post     @relation(fields: [postId], references: [id], onDelete: Cascade)
  postId  Int

  @@index([userId])
  @@index([postId])
}

 

12.1 Forms and Handlers
12.2 Post Detail
12.3 궁금해요
12.4 Answer
12.5 All Posts

12.6 useCoords
12.7 Geo Search
12.8 Geo Bug


const posts = await client.post.findMany({
        include: {
          user: {
            select: {
              id: true,
              name: true,
              avatar: true,
            },
          },
          _count: {
            select: {
              wonderings: true,
              answers: true,
            },
          },
        },
        where: {
          latitude: { gte: parsedLatitude - 0.01, lte: parsedLatitude + 0.01 },
          longitude: {
            gte: parsedLongitude - 0.01,
            lte: parsedLongitude + 0.01,
          },
        },
      });

 

Type 'number' is not assignable to type 'null'.ts(2322)
해결 null as any로 바꾸면 된다는데

 
next.js에서는 페이지를 미리 만들어 놓기 때문에, 초기값으로 그려진다.

그래서 longitude, latitude가 null이었으니 제대로 동작 안하지. 

 

'클론코딩-캐럿마켓 > 전반' 카테고리의 다른 글

14 Streams - seeding  (0) 2023.01.11
13 Profile  (0) 2023.01.09
11 Products  (0) 2023.01.04
10 AUTHORIZATION - SWR  (0) 2023.01.04
9 AUTHENTICATION  (0) 2022.12.27

9.0 Introduction
authentication = 유저가 누구인지 알아내는 것.
authorization = 유저가 권한이 있는지 알아내는 것.

이 섹션에서 구현할 로직
1. Phone Number Sended to Backend --> User? Login : Sign in
2. Create Token -- Connect to User with Random Number
3. Enter Phone Number(Twillo) --> User receive Token(Random Number) by SMS
4. Enter Token --> Send Token to Backend --> Token? Log the user In!

9.1 Account Logic

findUnique는 User나 null 줄것이다.
upsert

string을 number로 바꾸려면 앞에 + 붙여주면 됨.
+"123" => 123
123 + "" => "123"

Update or create records (upsert)
upsert()는 기존 데이터를 업데이트하거나 새 데이터베이스 레코드를 생성합니다. 다음 쿼리는 upsert를 사용하여 특정 이메일 주소로 사용자 레코드를 업데이트하거나, 존재하지 않는 경우 해당 사용자 레코드를 생성합니다.
출처: 사용자 sugar댓글

VSCode의 block 주석 하는 법: Shift + Alt + A or 상단메뉴 Edit -> Toggle block comment

자동으로 if문 처럼 동작하
최종 shortened버전

 

9.2 Token Logic

아래 index는 https://www.prisma.io/docs/concepts/components/prisma-schema/relations/relation-mode

9.3 Twilo Setup
9.4 Sending SMS

https://console.twilio.com/us1/develop/sms/try-it-out/send-an-sms?frameUrl=%2Fconsole%2Fsms%2Fgetting-started%2Fbuild%3Fx-target-region%3Dus1
npm i twilio
트윌로는 현재 node 16까지밖에 지원 안함.
그래서 nvm에서 노드 16으로 바꿔서 하니 잘 깔림.

 

느낌표 있으면 typescript한테 있는 타입이라고 말해주는 것.

9.5 Sending Email
npm install --save @sendgrid/mail
//아직 메일 인증되지 않아서 에러가 뜨는 것 같음
일단 넘어가자.

 

9.6 Token UI 

prisma stuio에서

User삭제하려고 하면 안됨.
User가 지워질 때, Token 물고있어서
그러면 어떻게 하냐?.( onDelete )
Cascade: 부모도 삭제해라.
SetNull: user값을 null로 둔다.
근데 여기선 그런 것은 필요없으니 Cascade로 두자.

구조분해
https://velog.io/@plu457/JavaScript-%EA%B5%AC%EC%A1%B0%EB%B6%84%ED%95%B4-%ED%95%A0%EB%8B%B9

 

9.7 Serverless Sessions
iron session을 써보자.
npm i iron-session


유저가 입력한 payload로 token을 검색하면
id:19인 튜플을 뽑아온다.

include라는 옵션을 주면, 
schema.prisma에서 정의한 릴레이션대로, 
user를 가지고 오는데 해당 모델(Token)의 userId로
참조하는 모델(User)의 id를 매칭한다.
매칭이 되면 이제
Token에 해당되는 User정보도 가져오는거지.


9.8 Profile Handler
9.9 Cleaning Code

9.10 NextAuth - 너무 매직같아서 안씀

 

'클론코딩-캐럿마켓 > 전반' 카테고리의 다른 글

11 Products  (0) 2023.01.04
10 AUTHORIZATION - SWR  (0) 2023.01.04
8 REFACTORING  (0) 2022.12.27
7 REACT HOOK FORM  (0) 2022.12.26
6 DATABASE SETUP  (0) 2022.12.26

+ Recent posts