24.3.21 (+ Next.js프젝 중 / React / TS)
+ 수정
< Supabase - rpc 활용하기 ( Remote Procedure Calls) >
1. RPC 란?
You can call Postgres functions as Remote Procedure Calls, logic in your database that you can execute from anywhere. Functions are useful when the logic rarely changes—like for password resets and updates. (공식문서)
-
RPC 는 Remote Procedure Calls의 약자.
즉, Postgres 함수를 불러와 쓸 수 있도록 한 것인데,
내가 직접 데이터베이스에서 Postgres 함수를 만들어서 코드에서 사용할 수 있다.
잘 안변하는 로직 (패스워드 초기화나 업데이트)에 적합하다고 한다.
아래는 supabase 를 사용해 data를 가져와 변수에 담을 때의 코드인데,
const { data, error } = await supabase.from('users').select('scrappedCommunityPosts').eq('userId', userId);
원래 supabase 테이블의 데이터를 가져오거나 업데이트 시
위 처럼, select , eq, .. update, delete 등 supabase의 문법 을 써서 사용하는데,
rpc를 활용하면 sql문을 통해 만든 함수를 사용해, 데이터를 가져오거나 바꿀 수 있다.
(더욱 복잡하게 함수를 만들어 쓸 수 있는거같다)
2. Supabase를 통해 문자열 원소를 배열에 추가하려면 ? - 고민
내 경우 스크랩한 글을 담은 목록을 만들기 위해,
수퍼베이스 테이블에 문자열이 원소인 배열값을 가진 컬럼 column을 만들었고, (text [ ])
여기 배열에 문자열(글 고유 ID)을 추가하고 삭제하는 식으로 진행할 예정이었다.
(나중에 튜터님께 여쭤보니 한 칼럼에는 하나의 값이 들어가는 것 (1:1)이 좋아서, 배열로 만드는 것은 비추천하셨지만.. ㅠ일단 배열값의 column 을 만들었고 여기에 원소를 추가하는 방법을 알았기 때문에 공유한다 !!)
그렇다면 supabase를 통해서 어떻게 문자열 원소를 배열에 추가할 수 있을까?
-
이전에 firebase를 썼었을 때는 아래와 같이 firebase의 updateDoc과 arrayUnion 메서드를 활용했었다.
// 즐겨찾기 추가
export const addFavoriteChannel = async (userUid, channelId) => {
try {
await updateDoc(doc(db, 'users', userUid), {
favChannels: arrayUnion(channelId)
});
} catch (error) {
console.error('cannot add favorite to firestore: ', error);
}
};
이번에 supabase를 써봤을 때는, ..
이런 firebase의 arrayUnion과 같은 용이한 메서드가 존재하지 않기때문에 난항을 겪었다 .. ㅠㅡ
검색을 해봐도 찾기 은근 힘들었다.
물론 rpc를 활용하지 않을 수도 있다.
직접 js코드로, 기존 배열 데이터를 가져와서 [... , newString ] 과 같이, 스프레드 연산자 (...) 를 써서 그 뒤에 추가한 뒤
원소 추가된 배열을 supase의 column에 'update' 해주는 방법도 있겠다.
(지금 생각해보면 그 방법이 훨씬 편했을지도..!? 하지만 이 방법은.. 수퍼베이스 테이블 배열 칼럼에, 원소를 직접 추가해준게 아니라, 새로운 배열값으로 업데이트해주는 방법이다. 그래서 시간이 더 걸릴지도 모른다는 우려가 있다. ?!)
sql editor - rpc 를 쓰는 방법이 더 효율적이냐고하면 나도 잘 모르겠다 ㅎㅎ
그런데 만약 이러한 로직을 한 번만 쓰는게 아니라, 여러 번 수행할거라면
만들어둔 rpc 함수를 가져와서 (돌려)쓰면 되니까 여러번 활용할 고정된 로직이 필요하다면 적합한 듯 하다!
여튼 구글링을 해봤을 때 외국 커뮤 답변에서도
배열에 원소 추가하는 건 rpc 를 자주 쓴다는 답변을 봤기 때문에 한번 시도해보고싶었다.
(근데 난 postgreSQL 등 sql 에 익숙하지않아서... ㅠㅠ
sql에 익숙하다면 supabase의 sql editor를 정말 잘 활용할 수 있을 것이다. )
여튼 구글링 끝에 rpc 를 활용해서 배열 타입 컬럼에 문자열 원소를 추가할 수 있게 되었다!!
(+ chat gpt의 도움은 덤..ㅎㅎ)
3. 💚핵심! - Supabase에서 SQL editor로 Postgres function함수 만들어 rpc활용하기
아래 editor 내용 참고!
참고로 sql editor 에서 함수명 등에는 대문자가 들어가면 안된다.
스네이크 케이스 형태 (ex. add_post_to_scrapped_posts) 로 쓰면 된다.
(테이블 생성 시에도 칼럼명은 스네이크 케이스가 좋다 .. 하지만 나는 그냥 카멜케이스를 써버렸고ㅎㅎ
칼럼명에 카멜케이스를 쓴 경우, sql문에서 그냥 쓰면 안되고, " " 큰따옴표로 감싸서 써줄 수 있다.
아래 "scrappedCommunityPosts"처럼! )
-- sql editor
CREATE OR REPLACE FUNCTION add_post_to_scrapped_posts (user_id VARCHAR,post_id TEXT) RETURNS VOID AS $$
DECLARE
existing_array TEXT[];
BEGIN
-- 기존 배열을 가져옵니다.
SELECT INTO existing_array "scrappedCommunityPosts" FROM "users" WHERE "userId" = user_id;
-- 새 문자열을 배열에 추가합니다.
existing_array := array_append(existing_array, post_id);
-- 업데이트된 배열을 데이터베이스에 저장합니다.
UPDATE "users"
SET "scrappedCommunityPosts" = existing_array
WHERE "userId" = user_id;
END;
$$ LANGUAGE plpgsql;
add_post_to_...posts 라는 이름의 함수를 생성한다. 인자는 user_id 와 post_id , 인자에 모두 꼭 타입을 옆에 명시해줘야.
SELECT INTO 로 기존 배열을 가져온다.
"scrappedCommunityPosts" 자리에 가져올 컬럼명을 써준다. (배열 값을 가진 컬럼) ..
SELECT INTO existing_array "컬럼명" FROM "테이블명" WHERE 조건
(WHERE 말고 LIMIT 1 등으로 제한해줄수도있다)
여기서는 users 테이블의 userId 컬럼의 값과 , 인자 user_id 가 동일하다는 조건을 주었다.
그 조건 하에 해당 컬럼의 배열값을 가져온다.
(여기서 이 WHERE 뒤의 조건이 핵심이었다 !!! 이게 있어야만 원하는 컬럼 배열값 을 가져오고 추가해줄 수 있다.)
그리고 := array_append 를 써서 배열에 원소를 추가해준다. !!
(PostgreSQL에서 제공하는 배열 함수)
js에서 [ ... , ] 스프레드 연산자를 쓴 것과 동일한 이치같다
그리고 업데이트된 배열을 SET 해주면 됨
그리고 여기서 UPDATE 뒤에 WHERE 조건은 꼭 붙여야 브라우저에서 에러가 안난다.
그럼 이렇게 sql editor 를 통해 함수를 만들었다면 이제 코드에서 쓸 수 있다. (참고로 코드는 타입스크립트)
supabase 는 클라이언트로 연결했을테니 supabase.rpc 해서 쓰면된다
return 값이 있다면 data 를 받고, 없다면 그냥 아래처럼 error 객체만 받아서 에러 시 메세지를 띄울 수 있다.
supabase.rpc("함수명", {'파라미터명': 넘겨줄 인자 })
// update.. 나머지 scrappedPosts 유지하면서 그 배열에 추가
export const addScrappedPost = async (userId: string, postId: string) => {
console.log(userId);
const { error } = await supabase.rpc('add_post_to_scrapped_posts', { post_id: postId, user_id: userId });
if (error) {
console.error(`Failed to add data to Supabase - ${error.message}`);
}
};
+
근데 만약 함수를 잘못 만들었다면?
이게 함수가 한번 만들면 저장이 되는데, 이름이 겹친다든지? 문제가 생길 수 있다.
일단 저장된 함수를 확인해보려면 왼쪽 탭의 맨 아래의 API Docs -> Stored Procedures 메뉴를 확인해보면 나와있다.
여기 이미지에서 add_post_to_scrapped_posts 가 아까 만든 함수이다.
이걸 눌러 들어가면 친절하게 아래 두번째 이미지와 같이, rpc 쓰는 법도 나와있다. 인자 타입도 나와있음
아래와 같이 잘못 만든 함수는 sql editor에서 없애주면 된다. ( ) 안에 꼭 인자 타입까지 써줄 것!
DROP FUNCTION IF EXISTS add_post_to_scrappedposts (new_string TEXT);
DROP FUNCTION IF EXISTS 함수명 (인자명 인자타입);
'DB & BaaS' 카테고리의 다른 글
[BaaS] Supabase - Stroage RLS policy 설정해줘야 모두 이미지등록 가능! (0) | 2024.03.24 |
---|---|
[BaaS] Supabase foreign key (외래 키) 활용해 테이블 생성하고 조회하기 (1) | 2024.03.21 |
[BaaS/TS] Supabase - Supabase CLI로 Database의 타입 생성하기 (0) | 2024.03.20 |
[BaaS/Next.js] Supabase 소개 / next.js 프로젝트와 함께 설치해서 테이블 데이터 가져와보기 (0) | 2024.03.20 |