[TIL] 9월 27일 PostgresQL

기록하며 공부하자·2021년 9월 27일
0

프론트엔드 과정중 백엔드 실습을할 기회가 생겼다.

프론트엔드 컴퓨터에서 입력한 값은 백엔드 컴퓨터로 이동되고 백엔드 컴퓨터에서 데이터 베이스 컴퓨터로 이동된다.

또한 프론트엔드 컴퓨터에서 백엔드컴퓨터로 특정한값을 요청하면 백엔드 컴퓨터에서 데이터 베이스 컴퓨터에서 데이터를 받아 프론트엔드로 전달해준다.

프론트엔드 개발을 원할하게 하기위해서는 백엔드 과정도 당연히 이해가 되어야 유기적인 업무가 가능할거 같다.

PostgresQl

데이터베이스 종류는 크게 SQL언어, noSQL언어 2가지의 종류가 있다.

SQL언어의 종류는 mySql, Oracle, PostgreQL 등이있으며
noSQL언어의 종류는 MongoDB, Firebase 등은 noSQL 등이 있다.

SQL 언어는 데이터가 엑셀 형식으로 저장되는 방식이고
noSQL 언어는 데이터가 객체 형식으로 저장되는 방식이다.

백엔드 데이터 실습은 PostgresQL으로 진행했으며 기존에 playground에서 실습했던 Mutation, Query등을 직접 만들어보는 실습을 진행했다.

DB관리 툴(dbever)

DB 현황들을 눈으로 보고 관리할수 있도록 도와주는 프로그램이 있다.

https://dbeaver.io/

위주소로 접속해 dbever를 다운받는다.

dbever에 접속하여 db언어 설정, host id, port, ip 등을 설정 한다.

설정이 완료되면 db의 테이블 및 현황들을 눈으로 확인할수 있다.

vscode 연결 및 테이블 만들기

index.js와 db를 연결해 주어야 한다.

dbever에서 생성시 적어주었던 정보들과 동일하게 적어준다.
이렇게 되면 기본 설정은 끝난다 이제 이파일에 테이블에 들어갈 내용들을 적은 파일을 import 해준다.

Product table

Product.postgresql.ts 라는 파일을 만들어주고 BaseEntity, Column, Entity, PrimaryGeneratedColumn 을 typeorm에서 import 해온다.

아직 이내용에대해서 다 알지는 못하지만 미리 불러온 내용들은 db의 항목들을 정할때 사용된다.

Column은 열을 만드는데 상단 제목을 만드는것과 같은 역할을 한다.
PrimaryGeneratedColumn은 동일하게 열을 만들지만 자동으로 숫자를 추가해서 부여한다거나 임의의 id를 부여할수 있는 기능이다.

Column안에는 typed을 정할수 있다.

이렇게 정한 타입들은 Mutation, Query 등을 사용할때 맞춰줘야 한다.

index.js import

이제 이렇게 정한 파일들을 index.js 파일에 import 한다.

graphql을 사용하기에 ApolloServer, gql을 import 해주고, Product.postgres 파일을 import 한다.

typeDefs = gql 안쪽으로 Product.postgres파일에서 정의했던 Column들의 이름과 타입을 적어준다.

이렇게 완료하면 dbever에서 테이블이 생성되고 entity 관계도에서도 확인할수 있다.

이제 등록된 데이터들이 이곳에 쌓이고 어떠한 정보를 가지고 있는지 눈으로 확인할수 있다.

Mutation, Query 만들기

기존 graphql 실습시 진행했던 playground를 보면 아래와 같다.

Mutation

Query

이렇게 docs에서 정의가 되어있어서 Mutation과 Query를 사용했다.

이부분도 이런식으로 설정이 되어야 데이터를 Mutation 하거나 Query로 조회할수 있다.

상세 코드(typeDefs)

  input CreateBoardInput {
    writer: String
    title: String
    age: Int
  }
 input CreateProductInput {
    name: String
    detail: String
    price: Int
  }
input UpdateProductInput {
    name: String
    detail: String
    price: Int
  }
type Return {
    message: String
    number: Int
    _id: String
  }
type Board {
    number: Int
    writer: String
    title: String
    age: Int
  }
type Product {
    number: Int
    _id: String
    seller: String
    name: String
    detail: String
    price: Int
    # page: Int
    # createdAt: Date
  }
type Query {
    fetchBoard: Board
    fetchBoards: [Board]
    fetchProducts(page: Int): [Product]
    fetchProduct(productId: ID): Product
  }
type Mutation {
    # createBoard(writer: String, title: String, age: Int): Return
createBoard(createBoardInput: CreateBoardInput): Return
    updateBoard: Return
    deleteBoard: Return
    createProduct(
      seller: String
      createProductInput: CreateProductInput
    ): Return
    updateProduct(productId: ID, updateProductInput: UpdateProductInput): Return
    deleteProduct(productId: ID): Return
  }
`;

type을 정의할때는 어떠한 db들을 정했는지 이름과 type을 적어주고 Mutation시 Input할 내용에 대해서는 Input으로 정의해 준다.

정의를 다 해준다음 Query, Mutation 타입에는 create, fetch등의 이름과 리턴받을 항목들 그리고 input시 필요한 argument들에 대해서 기입해 준다.

상세코드(resolver)

const resolvers = {
  Query: {
    fetchBoard: async () => {
      //데이터베이스에서 해당하는 데이터 꺼내서 브라우저에 던져주기(응답주기)

      const result = await Board.findOne({
        where: { number: 1, deletedAt: null },
      });
      return result;
      // result?.age;
      // result?.title;
      // result?.writer;

      // return { writer: result?.writer, title: result?.title, age: result?.age };
    },

    fetchBoards: async () => {
      const result = await Board.find({ where: { deletedAt: null } }); // [{...},{...},{...}]
      return result;
    },

    fetchProducts: async () => {
      const result = await Product.find({ where: { deletedAt: null } });
      return result;
    },

    fetchProduct: async (_: any, args: any) => {
      const result = await Product.findOne({
        where: { _id: args.productId, deletedAt: null },
      });

      return result;
    },
  },
  Mutation: {
    createBoard: async (_: any, args: any) => {
      //데이터베이스 데이터 입력하기

      // const result = await Board.insert({
      //   title: args.title,
      //   writer: args.writer,
      //   age: args.age,
      // });

      const result = await Board.insert({
        ...args.createBoardInput,
        // title: args.createBoardInput.title,
        // writer: args.createBoardInput.writer,
        // age: args.createBoardInput.age,
      });

      console.log(result);

      return { message: "성공했습니다.", number: result.identifiers[0].number };
    },

    updateBoard: async (_: any, args: any) => {
      await Board.update({ number: 3 }, { writer: "영희" });
      // 앞 중괄호는 조건, 뒤 중괄호는 변경할 값

      return { message: "수정완료!!!" };
    },

    deleteBoard: async () => {
      // await Board.delete({ number: 4 });

      await Board.update({ number: 5 }, { deletedAt: new Date() });

      return { message: "삭제완료" };
    },

    //실제는 이렇게하지 않고 isDeleted true or flase 이런식으로 구현함
    //isDeletedAt 공란, 2021.09.18 이런식으로 구현함

    createProduct: async (_: any, args: any) => {
      const result = await Product.insert({
        seller: args.seller,
        ...args.createProductInput,
      });

      return { message: "성공했습니다.", number: result.identifiers[0].number };
    },

    updateProduct: async (_: any, args: any) => {
      // await Product.update({ number: 7 }, { seller: "무무무무" });

      const result = await Product.update(
        { _id: args.productId },
        { ...args.updateProductInput }
      );

      return {
        message: "수정완료~~~",
        // number: result.identifiers[0].number,
        _id: args.productId,
      };
    },

    deleteProduct: async (_: any, args: any) => {
      await Product.update({ _id: args.productId }, { deletedAt: new Date() });

      return { message: "삭제완료~~~" };
    },
  },
};

위 코드중 Board는 하드코딩 Product는 하드코딩으로 진행하지 않았다.

Query부분은 각각의 항목을 보여주는 fetchProduct, fetchBoard 등은 findOne를 사용했고
전체를 보는 방식인 fetchProducts, fetchBoards는 find를 사용했다.

fineOne에서는 어떤 key값으로 찾을것인지 입력해 줘야한다.

Mutation 부분에서는 Input으로 넣어준 값, return 받을 값들을 적어준다.

위 typeDefs 부분에서 Input을 모두 정의해 주었기 때문에 스프레드 연산자로 간편하게 작성한다.

profile
프론트엔드 개발자 입니다.

0개의 댓글