24.3.21 (+ Next.jsํ์ ์ค / React / TS)
+ ์์
< Supabase - rpc ํ์ฉํ๊ธฐ ( Remote Procedure Calls) >
Call a Postgres function | Supabase
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. create or replace function hello_world() return
supabase.com
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 ํจ์๋ช
(์ธ์๋ช
์ธ์ํ์
);