1. Github 저장소 만들기

  • 데이터베이스 세팅을 위해, 먼저 지금까지 작성해온 프로젝트를 Github에 push해야 한다.

  • 아래 가이드를 보고, github에 repository를 만들어보자.
    - 참고

 

2. Vercel에 배포하기

  • Vercel은 웹 애플리케이션과 정적 웹 사이트를 쉽게 배포하고, 호스팅할 수 있도록 해주는 클라우드 플랫폼으로, Next.js를 만든 팀에서 제공하고 있다.
    • 회원가입 후, 다음 링크의 가이드대로 본인의 프로젝트를 Vercel에 배포할 수 있다.
  • 이 부분부터 차근차근 진행하면 된다.

  • 성공 시, 아래와 같이 Status가 Ready인 상태로, 배포된 것을 확인할 수 있을 것이다.

 

3. Postgres Database 만들기

  • PostgreSQL은 매우 강력한 오픈소스 ORDBMS(객체 관계형 데이터베이스 관리 시스템)으로, 연산자, 복잡 자료형, 집계 함수, 자료형 변환자, 확장 기능자 등 다양한 데이터베이스 객체를 사용자가 임의로 만들 수 있는 기능을 제공한다.

  • 먼저 Vercel에 배포한 프로젝트를 선택하고, 상위에 있는 탭에서 Storage를 선택한다.

  • 그 다음, Connect Store -> 새로 만들기 -> Postgres -> 계속 진행... 의 선택을 거쳐 데이터베이스를 만든다.
    • 데이터베이스 Region은 워싱턴 DC로 진행하면 된다.
    • 데이터베이스를 동일한 지역에 배치하거나 애플리케이션 코드에 가깝게 배치하면, 데이터 요청을 위한 대기 시간을 줄일 수 있다.

  • 그 다음, Quickstart영역의 .env.local탭을 선택하여 나온 코드를 복사한 다음, 코드 편집기의 .env에 copy/paste를 진행한다.

    • Show secret으로, 실제 값을 확인하여 복사해야 한다.
    • 추가로, repository push 이전에, .gitignore 파일에 .env.local이 있는지 확인해야 한다.

  • 마지막으로, 터미널에 npm i @vercel/postgres를 입력하고, 실행하여 Vercel Postgres SDK를 설치한다.

 

4. 데이터베이스 시드

  • 간단히 말해, 데이터를 default로 입력해두는 것을 의미한다. (데이터베이스에 씨앗을 뿌려놓는다는 의미라 한다.)
  • 프로젝트 폴더의 scripts/seed.js에는 invoices, customers, user, revenue 테이블을 생성하고 시드하기 위한 지침이 포함되어 있다.
    • 아래 코드에서는, SQL을 사용하여 각 테이블을 생성하고, /app/lib/placeholder-data.js의 데이터를 이용해 INSERT 과정을 거친다.
    • 이렇게 데이터를 채우는 과정을 데이터베이스 시딩이라고 한다.
const { sql } = require('@vercel/postgres');
const {
  invoices,
  customers,
  revenue,
  users,
} = require('../app/lib/placeholder-data.js');
const bcrypt = require('bcrypt');

async function seedUsers() {
  try {
    await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
    // Create the "invoices" table if it doesn't exist
    const createTable = await sql`
      CREATE TABLE IF NOT EXISTS users (
        id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        email TEXT NOT NULL UNIQUE,
        password TEXT NOT NULL
      );
    `;

    console.log(`Created "users" table`);

    // Insert data into the "users" table
    const insertedUsers = await Promise.all(
      users.map(async (user) => {
        const hashedPassword = await bcrypt.hash(user.password, 10);
        return sql`
        INSERT INTO users (id, name, email, password)
        VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
        ON CONFLICT (id) DO NOTHING;
      `;
      }),
    );

    console.log(`Seeded ${insertedUsers.length} users`);

    return {
      createTable,
      users: insertedUsers,
    };
  } catch (error) {
    console.error('Error seeding users:', error);
    throw error;
  }
}

async function seedInvoices() {
  try {
    await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;

    // Create the "invoices" table if it doesn't exist
    const createTable = await sql`
    CREATE TABLE IF NOT EXISTS invoices (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    customer_id UUID NOT NULL,
    amount INT NOT NULL,
    status VARCHAR(255) NOT NULL,
    date DATE NOT NULL
  );
`;

    console.log(`Created "invoices" table`);

    // Insert data into the "invoices" table
    const insertedInvoices = await Promise.all(
      invoices.map(
        (invoice) => sql`
        INSERT INTO invoices (customer_id, amount, status, date)
        VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
        ON CONFLICT (id) DO NOTHING;
      `,
      ),
    );

    console.log(`Seeded ${insertedInvoices.length} invoices`);

    return {
      createTable,
      invoices: insertedInvoices,
    };
  } catch (error) {
    console.error('Error seeding invoices:', error);
    throw error;
  }
}

async function seedCustomers() {
  try {
    await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;

    // Create the "customers" table if it doesn't exist
    const createTable = await sql`
      CREATE TABLE IF NOT EXISTS customers (
        id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        email VARCHAR(255) NOT NULL,
        image_url VARCHAR(255) NOT NULL
      );
    `;

    console.log(`Created "customers" table`);

    // Insert data into the "customers" table
    const insertedCustomers = await Promise.all(
      customers.map(
        (customer) => sql`
        INSERT INTO customers (id, name, email, image_url)
        VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
        ON CONFLICT (id) DO NOTHING;
      `,
      ),
    );

    console.log(`Seeded ${insertedCustomers.length} customers`);

    return {
      createTable,
      customers: insertedCustomers,
    };
  } catch (error) {
    console.error('Error seeding customers:', error);
    throw error;
  }
}

async function seedRevenue() {
  try {
    // Create the "revenue" table if it doesn't exist
    const createTable = await sql`
      CREATE TABLE IF NOT EXISTS revenue (
        month VARCHAR(4) NOT NULL UNIQUE,
        revenue INT NOT NULL
      );
    `;

    console.log(`Created "revenue" table`);

    // Insert data into the "revenue" table
    const insertedRevenue = await Promise.all(
      revenue.map(
        (rev) => sql`
        INSERT INTO revenue (month, revenue)
        VALUES (${rev.month}, ${rev.revenue})
        ON CONFLICT (month) DO NOTHING;
      `,
      ),
    );

    console.log(`Seeded ${insertedRevenue.length} revenue`);

    return {
      createTable,
      revenue: insertedRevenue,
    };
  } catch (error) {
    console.error('Error seeding revenue:', error);
    throw error;
  }
}

(async () => {
  await seedUsers();
  await seedCustomers();
  await seedInvoices();
  await seedRevenue();
})();
  • seed.js를 실행시키기 위해서는, package.json 파일에 스크립트를 한 줄 추가해야 하는데, 다음과 같이 추가해주면 된다.
  • 이제, npm run seed를 입력하면 아래와 같이 시딩 작업이 진행되는 것을 확인할 수 있다.

 

5. 데이터베이스 탐색

  • Vercel의 사이드 탭 Data에서는, 방금 생성한 4개의 테이블을 탐색할 수 있다. 실제로, 방금scripts/seed.js를 실행하여 만들어낸 각 항목이 placeholder-data.js와 일치하는 것을 확인할 수 있다.

  • 또한, Query탭으로 전환할 경우, 데이터베이스와 상호작용 또한 가능하다.

    • SQL 표준명령을 지원하기 때문에, DROP TABLE customers와 같은 명령을 입력하면. customer 테이블이 삭제된다.
    • 아래는 invoices, customers 테이블을 JOIN하여, invoices 테이블의 Customer_id열과, customers 테이블의 Id열을 기준으로 결합을 진행한 다음, invoices.Amount가 666인 조건을 만족하는 invoices.Amountcustomers.Name을 검색하는 예제 SQL문이다.
profile
프론트엔드 입문 개발자입니다.

0개의 댓글