Skip to content

add unwrap() method to supabase client #92

Closed
@andykais

Description

@andykais

Feature request

add an unwrap() method or a an either monad left() method to pull the data out of a postgrest response.

Is your feature request related to a problem? Please describe.

Not exactly a problem, but the way the client is designed requires every database query to individually handle database failures. For the most part, I want to assume that the query succeeded, and throw an error if it did not. That makes most of my db calls look like this:

  const res = await context.supabase
    .from<tables['my_table']>('my_table')
    .select()
    .filter('status', 'eq', 'COMPLETED')
    .limit(1)
  if (res.error) throw new Error(`SupabaseError: query failed: \n${res.error}`)

Describe the solution you'd like

The solution I would like best, would be to add a method which can optionally unwrap the { error: object } | { data: object[] } response from supabase into just the data field. If there is an error present, the client should throw an error. This should not break any existing workflows, its just an optional convenience method.

Usage:

const data: table['my_table'] = await supabase.from<table['my_table']>('my_table')
  .select()
  .unwrap()

// handling an error:
try {
  const data = await supabase.from('my_table').delete().unwrap()
} catch (e) {
  if (e.name === 'SupabaseError') {
    // handle it
  } else {
    throw e
  }
}

Describe alternatives you've considered

I have attempted building this on top of the supabase client, but because of the way queries are built, I need to use proxies:

  const supabase_proxy_handler = {
    get: function (target: any, prop: string) {
      if (prop === 'unwrap') {
        return new Promise((resolve, reject) => {
          target.then((res: PostgrestResponse) => {
            if (res.error) throw new Error(`SupabaseError: query failed: \n${JSON.stringify(res.error)}`)
            else return res.data
          })
        })
      } else {
        return target[prop]
      }
    },
  }
  const supabase_proxy = new Proxy(supabase, supabase_proxy_handler)

This technically works, but manipulating the types to include the unwrap() method is harder.

Additional context

unwrap is a common pattern in several languages & libraries. Here is an example in rust: https://doc.rust-lang.org/rust-by-example/error/option_unwrap.html

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions