DeFiCh/jellyfish

View on GitHub
packages/whale-api-client/src/whale.api.response.ts

Summary

Maintainability
A
55 mins
Test Coverage
import { WhaleApiError } from './errors'
import { Method } from './whale.api.client'

export interface WhaleApiResponse<T> {
  data: T
  page?: ApiPage
  error?: WhaleApiError
}

export interface ApiPage {
  /**
   * The next token for the next slice in the greater list.
   * For simplicity, next token must a string or be encoded as a string.
   * If the next token is in other formats such as bytes or number,
   * it must be parsed by the controller.
   */
  next?: string
}

/**
 * ApiPagedResponse class facilitate the ability to pagination query chaining.
 * It extends the Array class and can be accessed like an array, `res[0]`, `res.length`.
 *
 * After accessing all the items in the Array, you can use the same ApiPagedResponse
 * to query the next set of items. Hence allowing you query pagination chaining until you
 * exhaustive all items in the list.
 *
 * @example
 *   let response: ApiPagedResponse = await client.address.listToken(...)
 *   for (const item of response) {
 *     console.log(item)
 *   }
 *
 *   // To query next set of items:
 *   let response = await client.pagination(response)
 *   for (const item of response) {
 *     console.log(item)
 *   }
 */
export class ApiPagedResponse<T> extends Array<T> {
  private readonly _paginate: {
    page?: ApiPage
    method: Method
    endpoint: string
  }

  /**
   * @param {WhaleApiResponse} response that holds the data array and next token
   * @param {Method} method of the REST endpoint
   * @param {string} endpoint to paginate query
   */
  constructor (response: WhaleApiResponse<T[]>, method: Method, endpoint: string) {
    super(...response.data)
    this._paginate = {
      page: response.page,
      method: method,
      endpoint: endpoint
    }
  }

  /**
   * Built-in methods such as map, filter creates a new array for functional programming.
   * It does that with the constructor found in the static Symbol.species class property.
   * This needs to be overridden as ApiPagedResponse constructor has a different signature.
   */
  static get [Symbol.species] (): ArrayConstructor {
    return Array
  }

  /**
   * @return {string} endpoint to paginate query
   */
  get endpoint (): string {
    return this._paginate.endpoint
  }

  /**
   * @return {Method} method of the REST endpoint
   */
  get method (): Method {
    return this._paginate.method
  }

  /**
   * @return {boolean} whether there a next set of items to paginate
   */
  get hasNext (): boolean {
    return this.nextToken !== undefined
  }

  /**
   * @return {string} next token
   */
  get nextToken (): string | undefined {
    return this._paginate.page?.next
  }
}