Skip to content

Supabase Pagination

Hyemin Heo edited this page Jan 12, 2025 · 1 revision

Supabase pagination

Supabase SDK range를 통해 pagination을 구현해보자.

range 메서드는 뜯어보면 offset / limit 두 개의 쿼리를 결합해 만들어졌다.

Query Parameters

  • offset=n

가져올 데이터의 시작 index (0이 첫번째 데이터)

The from and to values are 0-based and inclusive: range(from: 1, to: 3) will include the second, third and fourth rows of the query.

https://000.supabase.co/rest/v1/notification?offset=0&limit=5

주의

DB의 row 크기를 넘어가는 경우, 416 에러가 남

DB에 47개 row가 존재, offset=100으로 지정한 경우

image

한가지 특이점은 row의 count+1에 해당하는 부분은 에러가 아니라 빈 배열이 반환된다.

마지막 페이지 요청의 기준점으로 삼아도 되지 않을까?

스크린샷 2025-01-08 오후 10 32 17

또 다른 방법은

Response Header의 Content-Range에서 DB row의 count를 얻을 수 있다.

일반적으로 서버에서 총 페이지 수를 내려주는데, 그 방식으로 구현을 진행한다면 이 값을 쓰는 게 훨씬 낫겠다.

image

  • limit=n

데이터를 최대 n개 가져오는 방식

https://000.supabase.co/rest/v1/notification?limit=5

스크린샷 2025-01-08 오후 10 35 39

  • 해당 쿼리의 Supabase SDK 참고

    /// Limit the query result by starting at an offset (`from`) and ending at the offset (`from + to`).
      ///
      /// Only records within this range are returned.
      /// This respects the query order and if there is no order clause the range could behave unexpectedly.
      /// The `from` and `to` values are 0-based and inclusive: `range(from: 1, to: 3)` will include the second, third and fourth rows of the query.
      ///
      /// - Parameters:
      ///   - from: The starting index from which to limit the result.
      ///   - to: The last index to which to limit the result.
      ///   - referencedTable: Set this to limit rows of referenced tables instead of the parent table.
      public func range(
        from: Int,
        to: Int,
        referencedTable: String? = nil
      ) -> PostgrestTransformBuilder {
        let keyOffset = referencedTable.map { "\($0).offset" } ?? "offset"
        let keyLimit = referencedTable.map { "\($0).limit" } ?? "limit"
    
        mutableState.withValue {
          if let index = $0.request.query.firstIndex(where: { $0.name == keyOffset }) {
            $0.request.query[index] = URLQueryItem(name: keyOffset, value: "\(from)")
          } else {
            $0.request.query.append(URLQueryItem(name: keyOffset, value: "\(from)"))
          }
    
          // Range is inclusive, so add 1
          if let index = $0.request.query.firstIndex(where: { $0.name == keyLimit }) {
            $0.request.query[index] = URLQueryItem(
              name: keyLimit,
              value: "\(to - from + 1)"
            )
          } else {
            $0.request.query.append(URLQueryItem(
              name: keyLimit,
              value: "\(to - from + 1)"
            ))
          }
        }
    
        return self
      }
Clone this wiki locally