-
-
Notifications
You must be signed in to change notification settings - Fork 144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: throw on error types #494
base: master
Are you sure you want to change the base?
Conversation
57323f8
to
204cdf1
Compare
CC @soedirgo @steve-chavez @wyozi any thoughts on this? Copying my comment on supabase/supabase-js#801 I got impatient so I published it under @rebundled/postgrest-js. Here's how you can use it with npm install @rebundled/postgrest-js import { CookieOptions, createServerClient } from '@supabase/ssr'
import { PostgrestClient } from '@rebundled/postgrest-js'
import { cookies } from 'next/headers'
import { Database } from '~/db'
export const createClient = () => {
const client = createServerClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return cookieStore.get(name)?.value
},
},
},
)
// @ts-expect-error `.rest` is protected
const { rest } = client
const wrapper = new PostgrestClient<Database>(rest.url, {
fetch: rest.fetch,
headers: rest.headers,
schema: rest.schemaName,
}).throwOnError()
return Object.assign(wrapper, {
rest,
realtime: client.realtime,
auth: client.auth,
})
} You can then use like: import {createClient} from '..'
export default async () => {
const client = createClient()
const { data: user } = await client.from('users').select('*').single()
console.log(`Hello ${user.username}`) // no need to check truthiness/ throw manually
} If you need access to the non-throwing client, you can use |
It seems like a good change that I would find useful, but then again I'm a mere contributor :) Seems like Supabase team is not responding to PRs very quickly at the moment, which is the reason why there's e.g. 3 separate spread operator PRs open at the moment. |
+1 on getting this reviewed & merged plz |
Tagging some more people who seem to have been reviewing PRs and commiting code etc., indicating to me this project is not abandoned: @soedirgo @abhadu This PR only really affects types, and adds new type tests to make sure there aren't new regressions and that the types work correctly. It's also a big quality-of-life improvement so I think it's worth taking a look! I've updated from master, but it was fairly painful resolving the merge conflicts. This was work that would not have existed if this had gone in before @soedirgo's change f91aa29 - and I would rather not have to keep resolving merge conflicts if all that needs to happen is for this to be reviewed! |
What kind of change does this PR introduce?
Re supabase/supabase-js#885 and supabase/supabase-js#801 (would likely need a small change to supabase-js too once this is published, to close them)
What is the current behavior?
throwOnError()
has no effect at compile-timeSee issues above.
What is the new behavior?
The return type of a
.throwOnError()
'd query is always a "success" response at compile time. i.e.error
is always null anddata
isn't unioned withnull
(though it can still be null for.maybeSingle()
etc.)Breaking change (albeit fairly small one):
.throwOnError()
now has to be either at the "start" or the "end" of a chain. This is no longer allowed:It would have to be either:
or the client can be configured to have all queries throw on error:
Additional context
The motivator for me wanting this is the ugliness of littering supabase codebases with go-like
err != nil
checks:It gets even worse if you need multiple queries in the same scope. It's becomes awkward to alias
data
to anything meaningful, because then you also need toYou also need to avoid lint rules that get angry at throwing a "raw" value without re-wrapping.
This would allow doing
export const createDBClient = () => createClient(...).throwOnError()
in a single helper, then all queries would have the throwy behaviour. The above example would become:Implementation
It ended up being a bigger change than I'd hoped, because the
ThrowOnError
typearg needed to be passed around everywhere. The breaking change was needed because the oldthrowOnError()
implementation had a return type ofthis
- and as far as I know there's no such concept in TypeScript asthis but with typearg ThrowOnError = true
. So, an abstract class can't have a method that returns a variant of its implementer - meaning thethrowOnError
method onPostgrestBuilder
needs to return aPostgrestBuilder
, not the concrete implementation viathis
. So it knows about theResult
type but not about the rest of the fanciness onPostgrestTransformBuilder
.It might be possible to keep the old put-throwOnError-anywhere behaviour, but it would require quite a bit more fiddling and this seemed like a big enough change for me on a repo I'm not familiar with.