supabase / cli

Supabase CLI. Manage postgres migrations, run Supabase locally, deploy edge functions. Postgres backups. Generating types from your database schema.
https://supabase.com/docs/reference/cli/about
MIT License
1.08k stars 209 forks source link

Generate types for views as well #385

Closed enyo closed 2 years ago

enyo commented 2 years ago

When running supabase gen types typescript only types for tables are generated. This makes it difficult to select data from views.

enyo commented 2 years ago

As a workaround this works well for now:

interface DatabaseWithViews extends Database {
  public: Database['public'] & {
    Tables: Database['public']['Tables'] & {
      my_view_name: {
        Row: {
          view_column: string
          // etc...
        }
      }
    }
  }
}

const supabase = createClient<DatabaseWithViews>(url, anonKey);

EDIT: actually, strike that. I don't know why, but extending the interface doesn't work. It always returns any

soedirgo commented 2 years ago

It's not feasible to generate types for views since view definitions are dynamic - e.g. we don't know the column information for a view, since columns are tied to tables, not views.

I'll see if I can extend supabase-js to allow you to add additional Tables in the near future.

enyo commented 2 years ago

Excellent @soedirgo . I think it's fine if they need to be added manually, but atm I don't think it's possible? I don't understand why extending the Database the way I did in my previous post didn't work.

soedirgo commented 2 years ago

I think I figured it out - can you do this instead?

import { Database } from './types'

type DatabaseWithViews = Database & {
  public: {
    Tables: {
      my_view_name: {
        Row: { ... }
        ...
      }
    }
  }
}

I don't think it's necessary to modify supabase-js to support this after all, though we should document this in our docs.

profiluefter commented 2 years ago

PostgREST successfully generates types for views in the OpenAPI endpoint (http://localhost:54321/rest/v1/?apikey=). Can't this be used?

I haven't looked at the code but would have expected that this OpenAPI definition would be used for generating the TypeScript types. Given that there's already the requirement that a supabase instance has to be running it should be possible to use the OpenAPI information for views.

In my current situation (not yet upgraded to V2) it makes more sense to just use any OpenAPI generator.

soedirgo commented 2 years ago

It doesn't seem to be perfect - e.g. if I create a view with a column now() as now_col, the OpenAPI description will say you can insert and supply the now_col, but it'll return an error if you actually do that. Also, it doesn't take into account table fields that must not be supplied, e.g. for generated columns.

But the choice to use a separate tool (supabase/postgres-meta) is because of development velocity - it's much faster to release a fix on postgres-meta & update the image version in the CLI, than it is to release a fix on PostgREST and wait for it to be deployed on the hosted platform.

enyo commented 2 years ago

I think I figured it out - can you do this instead?

import { Database } from './types'

type DatabaseWithViews = Database & {
[...]

I didn't get this to work. It's the same issue as with my attempt of extending the interface. When I use this type, all the type inference breaks. The data objects returned by the supabase calls are any.

soedirgo commented 2 years ago

Needs support from the postgrest-js side for views - will loop back here once that's updated

soedirgo commented 2 years ago

postgrest-js has been updated to support views.

enyo commented 2 years ago

@soedirgo so does this mean that views are now included in the generated output, or that creating this union type now works?

soedirgo commented 2 years ago

Views are now included in the generated types. I believe you need CLI v1.3.0+ and postgrest-js@2.0.0-rc.5+ for it (npm update @supabase/postgrest-js should do it).

enyo commented 2 years ago

Very cool. Just in case anybody else was looking for this: I needed to restart supabase locally for this to work. Simply upgrading the cli wasn't enough.

enyo commented 2 years ago

@soedirgo at the moment, all fields in views are type | null. Is there anything we can do to avoid all fields being nullable?

soedirgo commented 2 years ago

I don't think so - this is a limitation on the Postgres side, it doesn't store column nullability accurately for views. I believe you get the same thing from PostgREST's OpenAPI.

profiluefter commented 2 years ago

It's possible to manually set the nullability for views to make the generated types work. This, however, doesn't check if what you're doing is actually correct so make sure that the columns you are setting to not null are actually definitely not null.

I don't know if there are other implications of changing these values so make sure you understand it better than I do before using this in an important project.

UPDATE pg_catalog.pg_attribute
SET attnotnull = TRUE
WHERE (attrelid, attname) IN
      (('view_name'::regclass, 'column_1'),
       ('view_name'::regclass, 'column_2'),
       ('view_name'::regclass, 'column_3'));
soedirgo commented 2 years ago

@profiluefter Thanks! We actually implicitly assume view columns are nullable in the typegen, so that needs to be updated as well.