supabase / postgrest-js

Isomorphic JavaScript client for PostgREST.
https://supabase.com
MIT License
964 stars 128 forks source link

feat: add dynamic schema to postgrest client #455

Closed sjones6 closed 10 months ago

sjones6 commented 10 months ago

Resolves https://github.com/supabase/postgrest-js/issues/280

What kind of change does this PR introduce?

New feature

What is the current behavior?

See discussion on https://github.com/supabase/postgrest-js/issues/280

The current behavior is that the PostgrestClient is created with a schema passed into the constructor. The class instance cannot reference tables or rpc calls for any other schemas unless a new instance is created.

// implicitly "public" schema
const postgrestPublic = new PostgrestClient<Database>(REST_URL)

// explicit specification of non-public schema
const postgrestPersonal = new PostgrestClient<Database, 'personal'>(REST_URL, { schema: 'personal' })

postgrestPublic.from('users').select() // select users from the "public" schema

postgresPersonal.from('users').select() // select users from the "personal" schema

What is the new behavior?

A single class instance exposes a facade method to reference other schemas:

const postgrest = new PostgrestClient<Database>(REST_URL) // implicitly "public" schema

postgrestPublic.from('users').select(); // select users from the "public" schema

postgrestPublic.schema('personal').from('users').select(); // select users from the "personal" schema

Type inference for responses also work, assuming a Database type has been supplied:

Screenshot 2023-08-05 at 12 09 27 PM

Table schema:

Screenshot 2023-08-05 at 12 10 09 PM

Compare without .schema('personal'):

Screenshot 2023-08-05 at 12 13 11 PM

Additional context

Assuming this PR is accepted, this PR https://github.com/supabase/supabase-js/pull/828 could be modified like so:

export default class SupabaseClient {
  /* snip */

  /**
   * Perform a query on a schema distinct from the default schema supplied via
   * the `options.db.schema` constructor parameter.
   *
   * The schema needs to be on the list of exposed schemas inside Supabase.
   *
   * @param schema - The name of the schema to query
   */
  schema(
    schema: string & keyof Database
  ): PostgrestClient<Database[typeof schema] extends GenericSchema ? Database[typeof schema] : any, any> {
    return this.rest.schema(schema);
  }
}

This would allow the following:

const supabase = createClient(supabaseURL, supabaseAnonKey);

supabase.schema('personal').from('users').select();
supabase.schema('personal').rpc('get_status', { name_param: 'kiwicopple' });

Add any other context or screenshots.

github-actions[bot] commented 10 months ago

:tada: This PR is included in version 1.8.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket: