본문 바로가기
Swfit/Database

Supabase PostgreSQL custom function 사용하기

by GGShin 2024. 1. 13.

Supabase를 직접 iOS 개발 시 사용해 보며 느꼈던 Supabase의 최대 장점은 바로 custom function이었습니다.

Supabase는 PostgreSQL를 사용하는 database인데,

custom function은 필요한 PostgreSQL function을 사용자가 직접 만들어서 function 이름으로 바로 쿼리가 가능하게 해주는 기능입니다.

 

사용 방법


만든 function은 rpc라는 method를 통해서 사용할 수 있습니다.

let value: String = try await supabase.database
  .rpc("hello_world")
  .execute()
  .value

 

위에 예시는 "hello_world"라는 이름의 function을 사용하는 방법을 보여주고 있습니다.

arguments가 있는 function 사용방법도 아래에서 다루어 보도록 하겠습니다.

.execute()는 function을 실행하는 operator입니다. 뒤이어 온 .value의 경우, return 값이 있는 경우 사용해주면 됩니다. 만일 return 값이 없는 function이라면 생략해 줄 수 있습니다. 예시의 "hello_world"는 String type의 값을 반환하는 function 임을 알 수 있습니다. 

 

 

결국 custom function을 Swift에서 사용하려면, 

 

1. Supabase Dashboard에서 function을 만든다.

2. rpc 메서드에 인자로 넣어서 사용한다.

 

이렇게 해주면 됩니다.

사용 예시


위에서 명시한 순서대로 custom function을 사용해보겠습니다.

NOTE: Supabase에 먼저 project를 생성한 후에 아래 작업이 가능합니다!

 

1. Supabase Dashboard에서 function 만들기.

 

생성한 프로젝트로 들어가면 좌측 패널에 여러 아이콘이 있습니다. 아이콘 중에 terminal처럼 생긴 아이콘이 SQL Editor인데요, 그곳에서 모든 db query를 작성할 수 있습니다. Editor에서 table을 만들기도 하고, 지금 다루는 function을 만들기도 합니다. 뿐만 아니라, 생성한 table과 function을 바로 테스트해볼 수도 있어서 굉장히 편리합니다.

 

function을 만들기 전에, Student라는 table을 먼저 만들어주겠습니다.

Editor에 query를 작성해주고, 우측 하단에 Run 버튼을 눌러줍니다. 

쿼리에 문제가 없다면, 아래처럼 Success가 나오며 테이블 생성이 완료됩니다.

Student table 생성

 

좌측에 Table Editor로 들어가보면, student table이 잘 생성되었음을 확인할 수 있습니다.

 

 


*TIP:

SQL 쿼리가 익숙하지 않은 경우라도 쉽게 사용할 수 있도록 AI를 활용할 수도 있게 되어있습니다. 

query를 작성할 때 원하는 쿼리의 내용을 명시해주면 AI가 잘 작성해줍니다. 

 

이렇게 좌측 패널에서 SQL Editor에 들어가면 Query를 만들 수 있는 창이 나옵니다.

위에 초록 부분이 AI에게 요청할 수 있는 텍스트 필드입니다.

 

AI에게 student라는 테이블에 uuid type의 id column과 text type의 name column을 만들어달라고 했더니, 

잘 만들어 주었습니다. 


이제 student table에 row을 넣는 function을 만들어보겠습니다.

Function도 마찬가지로 SQLEditor로 들어가서 만들면 됩니다.

 

'New query' 버튼을 누르면 새로운 editor 창이 뜨는데, 거기에 작성해주시면 됩니다.

 

 

create
or replace function insert_row_to_student (id uuid, name text) returns VOID as $$
BEGIN
  INSERT INTO student (id, name) VALUES (id, name);
END;
$$ language plpgsql;

 

"insert_row_to_student"라는 이름의 function이고, table column별 데이터 타입에 맞게 파라미터도 설정해주었습니다. Insert만 할 것이라서 return값은 Void입니다. (역시나 AI의 도움을 받으면 좀 더 쉽게 작성할 수 있습니다.)

 

쿼리문을 보면 제일 하단에 language가 plpgsql되어있는데, 바로 PostgresSQL을 지칭하는 단어입니다. 꼭 PostgresSQL만 사용해야 하는 것은 아니고 SQL도 사용 가능합니다.  

 

마찬가지로, Run을 누르고 문제가 없으면 Success가 뜹니다. 만들어진 function은 Database로 가면 볼 수 있습니다.

 

좌측 패널 아이콘에서 Database를 선택해주고, Functions로 들어가보면 지금까지 만들어 둔 Function들의 목록이 나옵니다.

그 중에 방금 만든 "insert_row_to_student"도 있습니다.

 

이렇게 하면 function 생성이 끝났습니다!

Swift에서 사용해보기 전에, SQL Editor에서 function test를 해보겠습니다.

 

Function이름을 쓰면 VSCode 처럼 변수 타입도 보여줘서 편리합니다.

 

이렇게 function 을 작성하고, 역시 Run을 눌러주면 됩니다. 

 

그러고 다시 student table로 가보면 row가 잘 추가되어 있음을 확인할 수 있습니다.

 

insert뿐만 아니라 fetch나 delete등 모든 쿼리가 editor로도 사용이 가능하니, 필요할 때 사용하면 되겠습니다.

그러면 가장 기다리던 Swift에서 사용하는 방법을 살펴보겠습니다.

 

2. rpc 메서드에 인자로 넣어서 사용하기

 

rpc는 생성한 function을 호출할 수 있도록 해주는 method로, 

database라는 PostgresClient instance에 정의되어 있습니다.

import Supabase
import Foundation

func saveStudent(name: String) async throws {
        try await supabase.database
            .rpc(
                "insert_row_to_student",
                params: [
                    "id": "\(UUID())",
                    "name": name
                ]
            )
            .execute()
    }

 

위에서 "hello_world" function을 사용할 때는, parameter가 따로 없었기 때문에 function명만 명시해주었지만 저희가 만든 function은 argument가 들어가므로 params부분에 추가해줘야 합니다. 

이렇게만 해주면 끝입니다 :) 

 

return void였기 때문에 따로 .value operator를 붙여주지는 않았습니다.

 

그리고 만약에 fetch 함수였는데, return 값을 String, Int 등 원시 타입이 아닌 custom struct로 받고 싶은 경우에는 어떻게 하면 될까요?

예를 들어, Student table에서 name이 "K"로 시작하는 row를 모두 불러오는 경우에, Swift에서는 어떻게 받으면 좋을까요?

 

"hello_world"에서 String type return을 받았던 것과 마찬가지로

return 값을 할당받을 변수의 타입을 원하는 struct로 명시해주면 됩니다.

 struct Student: Codable {
        let id: UUID
        let name: String
    }
    
 let row: Student = try await supabase.database
        .rpc(
            "fetch_name_starts_with_k"
        )
        .execute()
        .value

 

이렇게 해주면 됩니다!

참 쉽죠? ㅎㅎ

 

그리고 Table별로 보안 설정을 할 수가 있습니다. 

기본적으로 RowLevelSecurity라는 것을 적용하는데, 필요에 따라서 수정해서 사용하면 됩니다.

Firebase도 Rule을 설정하게 되어있는데 Supabase도 동일한 기능을 제공해줍니다. 아직 기본 설정으로만 사용해보았는데, 조금 더 구체적으로 알아보게 되면 또 정리해보도록 하겠습니다.

 

호기심 반 기대 반으로 사용해 보게 된 Supabase였는데 마음에 드는 구석이 많이 있습니다. 

한 가지 조금 불편한 건, Dashboard에 좌측 패널에 아이콘만 있는데, 아이콘 마다 아래에 작게 텍스트로 어떤 항목인지 명시해 주면 더 편할 것 같더라구요. 직관적이기는 하지만, 몇 가지는 좀 헷갈리는 게 있기도 합니다.

 


참고자료

1. Call Postgres function

https://supabase.com/docs/reference/swift/rpc?example=call-a-postgres-function-without-arguments

 

Supabase Swift Client - Call a Postgres function

By default PostgREST returns all JSON results in an array, even when there is only one item, use single() to return the first object unenclosed by an array.

supabase.com

 

 

2. Table, data query 관련 정보

https://supabase.com/docs/guides/database/tables?database-method=sql

 

Tables and Data | Supabase Docs

When naming tables, use lowercase and underscores instead of spaces (e.g., table_name, not Table Name).

supabase.com

 

반응형