[supabase] supabase 배우기

안지원·2025년 1월 12일
post-thumbnail

supabase 배우기(생활코딩)

supabase란

백엔드를 개발하기 위해선
1. 데이터베이스(database)
2. 파일 서버(storage)
3. 회원가입, 로그인 인증기능(auth)
4. 프로그래밍적으로 다양한 기능을 처리해야하는 요소(php, express, 장고 등등) - (edge function)

  • 그 기능만 쏙 담은 클라우드 서비스가 수파베이스임
  • 수파베이스는 postSQL의 기능을 사용하면서, JS의 언어를 사용하여 관계형 데이터베이스를 만들 수 있다고 한다.

수파베이스 사용법

  • 수파베이스는 하나의 로그인 계정에 여러개의 organizations를 생성할 수 있다.
  • organizations 하나에 실질적인 프로젝트에 사용되는 project가 있다.
  • project 안에 database, storage, auth, edge functions가 있다.
  • database 안엔 table이 있고, row가 그 안에 있다.

1. 로그인 하기

  • supabase에 로그인을 한다.

2. organizations 만들기

  • 최초 로그인시 내 organizations가 자동으로 하나 생성된다.

3. project 생성하기

  • 현재 organizations에서 프로젝트를 생성한다.
  • region에 내가 서비스를 제공할 국가를 선택하고 create new project를 만들면 된다.

4. project 내 중요 기능들

  • project를 생성하면 대시보드 페이지가 보이는데 왼쪽에 사이드바를 보면 수파베이스의 주요 기능들을 볼 수 있다.
  • database, storage, auth, edge function이 전부 이곳에 있다. + real time
  • 그 중에 database와 관련된 기능은 table editor에 있다.

5. table editor 만들기

  • table editor에 들어가면 새로은 db를 생성할 수 있다.
  • 이제 create a new table로 db를 생성하는데 name은 원하는 작명, description은 필요하면 설명을 넣으면 된다.
  • 생성과정 중에 Enable Row Level Security (RLS) 라는 체크박스를 볼 수 있는데 이건 아직 우리가 사용하기엔 작업의 복잡도가 높아지기 때문에 체크박스를 풀어준다.
  • RLS가 꺼진 프로젝트는 production 환경에서 사용해선 안된다고 한다. - 배포환경에서 사용하면 안된다.(후속 강의에서 가르쳐주실 예정)
  • enable realtime은 강의에서 설명을 안해서 패쓰
  • 이제 columns을 보면 우리가 만들 테이블의 열을 만들 수 있는데, 기본적으로 생성된 id coloumn의 primary 설정이 활성화 되어있는걸 볼 수 있다.
  • 이 primary의 설정을 클릭해보면 is Unique랑 is Identify가 보이는데, is identify는 행을 만들때 마다 id column의 값이 1씩 증가하기 때문에 식별자로 사용할 수 있다. - (아마 새로 만드는 row? 하나마다 고유한 id값을 붙이게 하는걸 말하나봄)
  • 다른 기본적으로 생성된 created_at column을 보면 default value에 now가 보이는데, 이건 값을 지정해주지 않으면 기본적으로 현재 날짜를 보여준다는 설정이다. - (이것도 created_at 날짜를 자동으로 붙이게 하는걸 말하나봄)
  • 이제 원하는 속성을 추가한다. name이 title이랑 body 속성을 추가할건데 type에서 안에 들어가는 데이터의 타입을 설정할 수 있다.(둘 다 text 자료형이니 text 선택)
  • 이제 하단의 save 버튼을 누르면 테이블이 생성된다.

6. table editor 사용하기

  • 상단에 insert 버튼을 클릭하면 새로운 row를 추가해 볼 수 있다.
  • 설정메뉴가 뜰텐데 id는 초기 세팅에서 row를 생성할 때 마다 1씩 증가하는 id가 생성되게 한다 해놨으니 별 다른 입력값을 추가하지 않아도 자동으로 생성된다.
  • created_at 같은 경우도 default값을 넣었기 때문에 괜찮다.
  • 아래엔 우리가 추가한 옵셔널 필드값들이 있는데, 여기에 우리가 설정했던 데이터타입(우린 text로 설정했으니 text타입)에 맞게 데이터를 추가해주고 save를 만들면 row가 새로 생성된다.

+) AI와의 강력한 통합성

  • 수파베이스의 강점으로 AI와 강력하게 통합되어있다는 점이 있다.
  • 우리가 관계형 데이터베이스를 만들려면 SQL이라는 관계형 데이터베이스용 컴퓨터 언어를 이용해서 표를 만들고, 행을 추가하고를 할 수 있는데 수파베이스는 SQL editor라는 곳에서 그 작업이 가능하다.
  • 이 공간에선 SQL문법을 사용해서 행을 추가하는데? 챗 gpt 처럼 SQL 코드를 짜주는 AI 기능을 사용할 수 있다.
  • 우측 상단에 초록색 사각형 아이콘을 클릭하면 AI assistance가 나오는데 여기에 프롬프트를 작성해주면 코드를 생성해준다.
    ex) page2 테이블을 만들거야. 이 테이블은 id, title, body, created_at이 필요해. title, body는 text type야.
CREATE TABLE public.page2 (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  title text,
  body text,
  created_at timestamp with time zone NOT NULL DEFAULT now()
) WITH (OIDS=FALSE);
  • 이제 이 코드를 복사해서 붙여넣거나, 코드블록 우측 상단에 edit in SQL editor 라는 아이콘을 클릭해 insert code를 클릭하면 SQL 코드에 붙여진다.
  • 그리고 run 버튼을 누르고 Success. No rows returned 라는 문구가 뜬다면 성공적으로 테이블이 생성되었다는 말이고, 다시를 table editor에 가본다면 내가 만든 page2테이블이 생성되어있는걸 볼 수 있다.

내 웹애플리케이션에 supabase 도입하기(vue로 진행)

  • 우선 다가오는 프로젝트가 vue 프로젝트라 vue 연결방식으로 진행한다.
  • 내 웹애플리케이션에 supabase를 연결하는 방법은 다음과 같다.
  1. 내 프로젝트를 만든다
npm create vue@latest .
  1. supabase 패키지를 설치한다.(cdn 방식 사용 안할거임)
npm install @supabase/supabase-js
  1. 웹사이트가 수파베이스에 접근하기 위해 수 많은 수파베이스 project 중에 어떤 project와 연결할지 비밀번호(api key)가 필요한데, 내 project에 API docs에 들어가면 수파베이스의 주요한 기술별로 아주 많이 사용하는 코드들이 샘플로 제공되는데 introduction에 들어가면 initializing에 코드가 존재하는데, 이 코드를 카피해서 supabase를 사용할 파일(보통 src 폴더에 supabase.js로 파일을 만드는듯? - 모듈화를 하려면 따로 만들고, 전역으로 사용할거면 main.js에 넣으면 됨)에 붙여넣으면 된다. + 이렇게 만든 파일을 클라이언트 파일이라고 칭하는듯?
// src/service/supabase.js
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
const supabase = createClient(supabaseUrl, supabaseKey)

3-1. 코드를 카피해서 사용할 수는 있는데 페이지 url이랑 key값이 노출되기 때문에 이 방법보단 .env파일을 생성해 환경변수로 관리하여 필요한 곳에 환경변수를 꺼내쓰면 된다.
.env 파일을 만들고 그 안에 다음과 같이 환경변수를 만들어 url이랑 key값을 저장해준다.

// .env
VITE_SUPABASE_URL=YOUR_SUPABASE_URL					// url
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY		// api key

3-2. 추가로 api key 코드가 initialize엔 환경변수 설정으로만 보일텐데, key값은 project 사이드바 하단의 설정(project settings)에 들어가 API를 클릭하면 project API keys를 볼 수 있다.
이곳에 key가 2개 있는데, anon public은 일반 API 이용자 전용 코드고, service_role은 모든걸 다 사용할 수 있는 어드민 이용자 전용 코드다.(절대절대 노출되면 안되는 코드다.)
우리는 anon public API코드를 사용하면 된다. 이 키를 복사해서 환경변수에 저장하자.

  • 여기까지 supabase.js에 설정이 다 되었다면 supabase를 사용하기 위한 연결세팅은 다 끝났다.

데이터베이스 내 모든 columns 가져오기

  • 이제 연결된 supabase project에서 데이터를 가져올 수 있다.
  • table editor에 들어가 테이블들을 클릭해보면 우측 상단에 API docs가 있는데, API들을 가져올 수 있는 방법이 담긴 문서를 확인할 수 있다.
  • 여기의 명령어를 복사해서 데이터를 가져와보자.
  • 그런데 supabase는 ajax로 데이터 가져오는게 아닌가보네?
    ####. read rows (데이터 읽기)
  1. reac all rows
  • 해당 테이블의 row데이터들을 전부 가져온다.
let { data: page, error } = await supabase
  .from('page')
  .select('*')        
const getAllData = async () => {
  let { data: res, error } = await supabase.from("page").select("*");
  if (res) {
    console.log(res);		// [{...}] 또는 2개 이상의 row데이터를 만들었다면 (n) [{…}, {…}]
  } else {
    console.log(error);
  }
};

insert rows(데이터 전송하기)

  1. insert a row
  • row데이터를 1개 전송한다.
  • 흠 ajax 사용 안하나보네
<script setup>
const { data, error } = await supabase
  .from('page')
  .insert([
    { title: 'someValue', body: 'otherValue' },	// 전송할 데이터를 형식에 맞춰 보내기(근데 지금은 데이터 아무렇게나 넣어도 그냥 보내짐 - 규칙같은걸 설정해야 하나? 로직이나)
  ])
  .select()
</script>
<script setup>
const sendData = ref([{ title: "", body: "" }]);

const sendOneData = async () => {
  const { data, error } = await supabase
    .from("page")
    .insert([sendData])
    .select();
};

onMounted(() => {
  getAllData();
});
</script>
  • 다른 기능은 천천히 살펴보자

로그인 기능(git hub)

  • 소셜 로그인 기능을 supabase에서 사용할 수 있다.
  • 카카오, 구글, 페이스북 등 다양한 OAuth들이 있는데 우리는 그 중 난이도가 쉬운편인 깃허브 로그인을 사용해본다.
  1. project의 Authentication -> providers에 들어가면 여러가지 소셜 로그인들을 확인할 수 있는데, 그 중 깃허브를 클릭한다.
  2. 깃허브 OAuth를 사용하기 위한 클라이언트 설정 슬라이드가 나오는데 여기서 github enabled 버튼을 활성화 시켜주고, Callback URL(for OAuth)라는 로그인 redirection 주소를 복사한 뒤 깃허브로 넘어간다.
  3. 깃허브에 로그인 한 후 설정에 들어가 사이드바 맨 아래에 있는 developer settings에 들어간다.
  4. OAuth Apps를 클릭하고 New OAuth app을 눌러 새로운 OAuth를 생성한다.
  5. 어플리케이션명과 연결시킬 홈페이지 URL을 입력한 후 Authorization callback URL에 아까 복사했던 callback URL을 붙여준다.
  6. 이제 Reguster application을 클릭하면 Client ID와 Client secrets가 보이는데, 이를 supabase 클라이언트 설정 슬라이드의 Client ID, Client Secret에 넣어주면 된다.
  7. Client ID는 그대로 복사해서 넣어주면 되고, Client Secret은 generate a new client secret을 눌러 새로운 키를 생성하면 된다.(이건 절대절대 노출되어선 안된다.)
  8. 클라이언트 설정 슬라이드의 내용을 다 채웠으면 save를 눌러 저장한다.
  • 이제 supabase 깃허브를 인증을 하는 제공자로 등록하고, 복잡한 OAuth 절차를 알아서 다 처리해준다.

User Management 활용해서 로그인 구현하기

  • 이제 직접 로그인 기능을 사용하는 방법은 다음과 같다.
  1. project 사이드 바에 API Docs -> User Magement에 들어간다.
  2. 이곳엔 로그인 정보를 전송하고, 토근을 받을 수 있는 코드예시가 있다. 이걸 참조해서 개발하면 된다.

구현

  1. 우선 내 프로젝트에서 수파베이스에게 이 사이트는 신뢰할 수 있는 사이트다, 인증기능을 장착할 수 있는 사이트다라는 것을 화이트리스트 처리해줘야 한다.
  • supabase의 사이드바에 Authentication -> URL Configuration에 들어간다.
  • redirect URLs에서 Add URL 버튼을 클릭해준다.
  • URL에 내 사이트 주소를 입력한다(ex. http://localhost:5173)
  • save url을 누르면 supabase가 해당 웹사이트에 대한 로그인 접근을 신뢰할 수 있게 해준다 = 내가 사용할 주소들을 전부 add url 해준다.(http://localhost:5173, http://localhost:5174, http://localhost:5175 등등) - 이걸 해줘야 인증이 되어도 사이트에서 로그인이 실패하는 현상을 해결할 수 있다.
  1. 이제 OAuth 로그인 관련 코드를 작성해준다.
  • User Management의 Log in with Third Party OAuth 코드를 참조한다.
const { data, error } = await supabase.auth.signInWithOAuth({ 
// 여기서 supabase 변수는 supabase.js에서 export해온 클라이언트 정보다. => import를 해야한다.
  provider: 'github'
})
  • 적용한 코드
<script setup>
import { supabase } from "@/service/supabase";

const signInWithGithub = async () => {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: "github",
    options: {					
      redirectTo: "http://localhost:5173",	// options:{redirect}를 추가해줘야 로그인 인증이 끝나면 해당 경로로 이동(redirect) 해준다.
    },
  });
};
</script>

<template>
  <h1>Supabase Oauth</h1>
  <button @click="signInWithGithub()">로그인</button>
</template>
  1. 이제 로그인 버튼을 클릭하면 깃허브 OAuth 로그인 페이지로 redirect하게 된다.
  2. 깃허브 OAuth 로그인 페이지에서 로그인을 끝마치면 options의 redirectTo 주소로 redirect 된다.
  3. 이제 supabase project 사이드바의 Authentication에 들어가면 내가 방금 추가한 로그인 한 정보를 확인할 수 있다.
  4. 이 로그인 정보는 내가 supabase에서 직접 삭제하지 않는 이상 로그아웃 시에도 남아있으며 다음번에 로그인 할 때 별 다른 인증페이지 없이 바로 그 아이디로 로그인 처리된다.
  • 놀라울 정도로 쉽게 로그인/회원가입을 구현했다 ㄷㄷ
  • 하지만 아직 우리 페이지는 사용자가 로그인을 했는지 안했는지 확인할 UI나 처리가 없다.

로그인 후 후속조치(로그아웃, 세션정보 가져오기)

  • 로그인 된 이후에 추가할 것들에 대해 알아보자
  1. 세션 정보를 받아온다.
  • 로그인을 했으니 해당 유저의 세션정보를 가져올 수 있게 된다.
  • 다음은 로그인한 유저의 세션정보를 가져오는 코드다.
const user = await supabase.auth.getSession();
  • 이걸 적용한 함수를 만들면
<script setup>
import { supabase } from "@/service/supabase";
import { ref } from "vue";

const signInWithGithub = async () => {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: "github",
    options: {
      redirectTo: "http://localhost:5173",
    },
  });
};

const session = ref("");
const getUserInfo = async () => {
  const user = await supabase.auth.getSession();
  session.value = user.data.session;
};
</script>
  • 이제 로그인한 사용자의 세션정보가 session 변수에 담긴다.
  • 이걸 활용해 session에 값이 담겨있으면 로그아웃 버튼을 보여주고, 값이 담겨있지 않다면 로그인 버튼을 보여주면 된다.
  1. 로그아웃 코드를 만든다.
  • 로그아웃 코드는 다음과 같다.
let { error } = await supabase.auth.signOut()
  • 이걸 적용한 함수는 다음과 같다.
const logout = async () => {
  let { error } = await supabase.auth.signOut();
  checkUserSession();
};
  • 총 종합해서 로그인/로그아웃 상태 구현 코드를 확인해보면 다음과 같다.
<script setup>
import { supabase } from "@/service/supabase";
import { onMounted, ref } from "vue";

const signInWithGithub = async () => {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: "github",
    options: {
      redirectTo: "http://localhost:5173",
    },
  });
};

const logout = async () => {
  let { error } = await supabase.auth.signOut();
  checkUserSession();
};

const session = ref(null);
const checkUserSession = async () => {
  const user = await supabase.auth.getSession();
  session.value = user.data.session;
};

onMounted(() => {
  checkUserSession();
});
</script>

<template>
  <h1>Supabase Oauth</h1>
  {{ session }}
  <button @click="signInWithGithub()" v-if="session === null">로그인</button>
  <button @click="logout()" v-else>로그아웃</button>
</template>

일반적인 로그인 인증요청 과정

  • 일반적인 로그인 인증요청 과정은 다음과 같다.
  • 유저 -> 웹 클라이언트 -> 서버 -> 데이터베이스
  • 이곳에 있는 서버가 유저의 데이터베이스로의 접근을 인증/통제(Authentication)하고 데이터를 가공(Edge functions)하는 역할을 담당한다.
  • 최근엔 firebase, supabase 등의 등장으로 서버의 역할을 대체하는 서버리스(serverless)애플리케이션이 등장했다.
  • 그래서 우린 서비스 운영에 대해선 걱정 한해도 되고 코딩에 집중하면 된다.

본격적인 테이블 만들기

  • 이제 이 애플리케이션이 사용할 테이블을 만들어보자.
  • 이젠 Enable Row Level Security(RLS)를 체크해서 본격적으로 사용할 수 있는 테이블을 만들거다.
  1. table editor에서 새로운 테이블을 생성하는데 Enable Row Level Security(RLS)를 체크해준다.
  2. columns에 필요한 column을 입력해준다
  • 여기서 필수적으로 user_id라는 column을 만들고 type을 uuid로 지정한 뒤, Default Value를 auth.uid()함수로 설정해준다.
  • 이는 나중에 key값 등으로 활용하게 될 유니크한 고유아이디를 만드는 작업이니 반드시 만든다.
  • 추가로 user_id 옆에 있는 링크 버튼을 클릭하면 상세설정을 할 수 있는다
  • schema를 auth로 설정하고 table to reference를 users로 설정하면 public.RLS_table(내 테이블명) -> auth.users 부분이 나오는데 user_id -> id 로 설정해준다.

링크 버튼을 클릭하고 나오는 상세 설정에서 schema를 auth로, table to reference를 users로 설정하는 이유는 데이터베이스의 관계를 정의하기 위함입니다. 이렇게 하면 public.RLS_table의 user_id와 auth.users 테이블의 id가 참조 관계를 가지게 됩니다. 이는 데이터 무결성과 일관성을 유지하는 데 도움이 됩니다.

  • Action if referenced row is removed 부분에 Cascade로 설정해준다.

Action if referenced row is removed 옵션을 Cascade로 설정하는 것은 참조된 행이 삭제될 때, 연결된 모든 행도 함께 삭제되도록 하는 설정입니다. 예를 들어, 사용자가 삭제되면 해당 사용자가 소유한 모든 데이터도 함께 삭제됩니다. 이는 데이터 정리를 용이하게 하고, 데이터베이스에서 고아 데이터를 방지하는 데 유용합니다.
한 마디로 id값이 삭제되면 그 row 자체가 삭제되는거임

  • 이제 save를 누르면 RLS가 적용된 테이블이 완성된다.
  • 만들어진 테이블에 새로 row를 추가하는데 user_id에 select record 라는 링크가 보이는데 이걸 클릭하면 auth.users의 정보가 보이게 되는데 아무 유저를 클릭하면 해당 user 테이블의 id column값이 uuid에 담기게 되고, 이렇게 만들어진 row는 그 유저의 소유가 된다.

RLS로 로그인/비로그인 데이터 제공기능 구축하기

  • RLS정책을 설정하려면 우측 상단의 Add RLS policy를 클릭해서 Authentication -> policies로 이동한다.
  • policies 페이지 우측 상단의 create policy 버튼을 클릭하면 정책을 설정도록 도와주는 설정창이 나오게 된다.
  • 우측에
    읽기(Enable read access for all users) - SELECT - 누구나 읽을 수 있게 하겠다.
    추가(Enable insert for authenticated users only) - INSERT
    수정(Enable update for users based on email) - UPDATE
    삭제(Enable delete for users based on user_id) - DELETE
    등 중요한 오퍼레이션별로 샘플들이 정리되어 있는걸 볼 수 있다.
  • 이 버튼들을 클릭하면 해당 오퍼레이션을 좌측에 설정할 수 있게 해준다.
  • 좌측에 내용은 policy설정에 대한 내용이다.
  • 그 중 policy command를 보면 5가지 선택항목이 있는데 이는 어떤 오퍼레이션을 허용할 것이냐, 어떤 오퍼레이션에 대한 정책이냐는 내용이다.
  • 5가지 중에서 적용할 오퍼레이션을 적용하면 된다.

select(읽기 기능 구현)

  • 먼저 읽기 버튼(SELECT)을 눌러 오퍼레이션 설정을 해본다.
  • 읽기 버튼을 눌러 설정했을떄 Use options above to edit 라는 코드형식으로 된 부분(SQL이다.)을 보면 using{} 부분의 true만 수정이 가능하게 되어있다.
  • 이 부분은 true냐 false냐에 따라 아무나 내용을 볼 수 있게 하거나 그러지 못하게 할 수 있다.
  • 이제 save policy 버튼을 누르면 select 기능을 담은 정책이 추가된다.
  • 이제 읽기 기능을 구현해보자
<script setup>
import { supabase } from "@/service/supabase";
import { onMounted, ref } from "vue";

const tag = ref("");
const refreshHistory = async () => {
  const { data: record, error } = await supabase.from("RLS_table").select("*");
  tag.value = record;
  console.log(record);
};

onMounted(() => {
  refreshHistory();
});
</script>

<template>
  <div>
    {{ tag }}
  </div>
</template>
  • 이렇게 RLS_table에 담겨있는 데이터들을 전부 가져오는 코드를 실행시켰을때, 정상적으로 코드를 가져오는걸 확인할 수 있다.
  • select로 policy를 설정해서 누구나 볼 수 있게 했기 때문이다.

insert(쓰기 기능 구현)

  • 이번엔 쓰기 기능을 구현해보자
  • policy 설정에 들어가서 이번엔 insert 버튼을 클릭한 뒤 저장하여 보내기 정책을 만든다.
  • 이제 insert문을 사용해서 데이터베이스에 전송을 해보자
// props를 활용해서 코드 리팩토링 한 상태인데 App.vue에서 tag랑 refreshHistory를 받아와서 사용하고있다.
<script setup>
import { supabase } from "@/service/supabase";
import { ref } from "vue";

const props = defineProps({
  tag: {
    type: Object,
  },
  refreshHistory: {
    type: Function,
  },
});

const title = ref("");
const body = ref("");

const recordHandler = async () => {
  const { data, error } = await supabase
    .from("RLS_table")
    .insert([{ title: title.value, body: body.value }]);
  console.log(data);
  alert("전송완료");
  props.refreshHistory();
};
</script>

<template>
  <div>
    <input type="text" v-model="title" placeholder="title" />
    <input type="text" v-model="body" placeholder="body" />
    <button @click="recordHandler()">전송</button>
  </div>
</template>
  • 이제 데이터를 입력하고 전송버튼을 눌러보면 전송이 안된다고 나온다.
  • 그 이유는 로그인이 안됐기 때문이다.
  • 다시 로그인을 해보고 전송하기를 눌러보면 정상적으로 데이터가 전송되는걸 볼 수 있다.

delete(삭제기능 구현하기)

  • 이번엔 삭제기능을 구현해보자
  • policy에 들어가 delete를 클릭한다.
  • 이번엔 using {}에 이상한 조건문이 들어가있다.
(select auth.uid()) = user_id
  • user_id는 RLS_table의 user_id column의 id값이다.
  • select auth.uid()는 현재 로그인한 사용자의 유저 id값이다.
  • 이 두 개의 값이 일치한다면 삭제가 된다.
  • 이제 코드를 구현해보자.
  • delete 코드는 다음과 같다.
const { error } = await supabase
  .from('RLS_table')
  .delete()
  .eq('id', 'id')			// 특정 id값이 일치하면 해당 row를 삭제
  • 이걸 적용해보면
<script setup>
import { supabase } from "@/service/supabase";
import { onMounted } from "vue";

const props = defineProps({
  tag: {
    type: Object,
  },
  refreshHistory: {
    type: Function,
  },
});

const deleteHandler = async (id) => {	// 파라미터에 id값을 담아
  const { data, error } = await supabase
    .from("RLS_table")
    .delete()
    .eq("id", id);			// 파라미터 id값을 담아 전송
  console.log(data);
  props.refreshHistory();
};
</script>

<template>
  <div>
    <div v-for="(data, idx) in props.tag">
      <p>{{ data.title }}</p>
      <p>{{ data.body }}</p>
      <button @click="deleteHandler(data.id)">삭제</button>	// 현재 위치에 해당하는 id값 인자로 전달
    </div>
  </div>
</template>
  • 이렇게 된다.
  • 로그아웃 상태에서 글을 삭제하려 하면 delete 정책에 위배되어 삭제되지 않는다.(id값이 다르기 때문)

update(업데이트 기능 구현)

  • 데이터를 수정해주는 업데이트 기능을 만들어볼거다.
  • 이번엔 policy에 들어가서 UPDATE를 클릭한다.
  • 이번에도 Use options above to edit에 다른 코드가 추가되는걸 볼 수 있다.(심지어 2개)
using {
  (select auth.jwt()) ->> 'email' = email
}
with check {
  (select auth.jwt()) ->> 'email' = email
}
  • 그런데 이 값은 jwt토큰을 기준으로 잡혀있고 형식도 좀 달라 소셜로그인인 우리는 uid()와 다른 형식을 사용한다.
using {
  (select auth.uid()) = user_id
}
with check {
  (select auth.uid()) = user_id
}
  • 여기서 using이랑 check의 차이가 있다면
  • using은 using expression으로 SELECT, UPDATE, DELETE를 사용할땐 where문이란 걸 사용하는데, 이 where문은 조회를 하는 문이고 즉 조회를 한 후에 그 대상에 대한 SELECT, UPDATE, DELETE 후속조치를 하는 것이다.
  • 이 where문을 사용할때 using이 참이면 데이터를 가져오고 false면 데이터를 가져오지 않는다.
  • 따라서 using 앞에 (select auth.uid()) = user_id 이 조건문은 해당 글이 삭제하려는 유저의 글이 맞는지 확인하고 맞으면 가져오게 해주는 where문의 조건이다.(어떤 작업을 하기 전 사전진행)
  • check는 with check expression으로 UPDATE, INSERT를 할 때 사용되며, 행이 추가되거나 변경(수정)될때 쓰기에 관련된 것이다. 역시 참이면 실행이 되고, 거짓이면 원래상태로 롤백 처리가 된다.(사후진행)
  • 따라서 UPDATE는 사전작업과 사후작업을 동시에 처리해야 데이터 수정을 할 수 있게 된다.
  • 이제 update 코드를 짤건데 이거는 갑자기 강사님이 끊으셔서 내가 직접 만들어야 한다;
  • 일단 UPDATE 코드는 다음과 같다.
const { data, error } = await supabase
  .from('RLS_table')
  .update({ other_column: 'otherValue' })		// 수정 전송할 데이터
  .eq('id', id)			// 업데이트할 대상(id값으로 검사)
  .select()
  • 코드를 적용해보면
<script setup>
import { supabase } from "@/service/supabase";

const props = defineProps({
  tag: {
    type: Object,
  },
  refreshHistory: {
    type: Function,
  },
});

const updateHandler = async (updateData, id) => {
  const { data, error } = await supabase
    .from("RLS_table")
    .update(updateData) // 수정 전송할 데이터
    .eq("id", id) // 업데이트할 대상(id값으로 검사)
    .select();
  console.log(data);
  props.refreshHistory();
};
</script>

<template>
  <div v-for="(data, idx) in tag">
    <div>
      <input type="text" placeholder="title 수정" />
      <button @click="updateHandler({ title: 'dd' }, data.id)">
        title 수정
      </button>
    </div>
    <div>
      <input type="text" placeholder="body 수정" />
      <button @click="updateHandler({ body: 'ss' }, data.id)">body 수정</button>
    </div>
  </div>
</template>

<style lang="scss" scoped></style>
  • 이건 아직 미완
  • v-model 적용해서 하는게 아닌가..
profile
frontend개발자가 되기 위해 노력합니다.

0개의 댓글