supabase / postgres-meta

A RESTful API for managing your Postgres. Fetch tables, add roles, and run queries
https://supabase.com
Apache License 2.0
863 stars 112 forks source link

Hardcoded metadata resulting in broken TypeScript type generation from the Supabase CLI #716

Closed yingw787 closed 5 months ago

yingw787 commented 5 months ago

Bug report

Describe the bug

For differing PostgreSQL schemas outside of schema public, the hardcoded Postgres metadata for schema public does not work, and creates a TypeScript type error.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Install Supabase v1.144.7 in a TypeScript repository.
  2. Create a PostgreSQL schema:
--- Create a new schema named `openai`.
CREATE SCHEMA openai;

--- Set the search path to include the new schema.
SET
  search_path TO openai,
  public;

-- Grant privileges to all tables for various Supabase roles so that the
-- Supabase client instantiated with the public Supabase access token can fetch
-- data, and RLS policies are still enforced per user.
GRANT USAGE ON SCHEMA openai TO postgres,
anon,
authenticated,
service_role,
dashboard_user;

ALTER DEFAULT PRIVILEGES IN SCHEMA openai
GRANT ALL ON TABLES TO postgres,
anon,
authenticated,
service_role,
dashboard_user;

COMMENT ON SCHEMA openai IS 'Schema for storing third-party API calls with OpenAI. This is important for e.g. archiving full conversation messages with OpenAI, which does not have an interface for exporting this information yet since the assistants functionality came out in beta a few days ago as of 11/08/2023.'
  1. Start Supabase using npx supabase start
  2. Reset the Supabase database using npx supabase db reset
  3. Generate the TypeScript types using command or similar: npx supabase gen types typescript --local --schema openai > src/types/supabase-schema-openai-types.ts

Expected behavior

A TypeScript file describing all of the tables, enums, and otherwise TypeScript-migrated models that I can use in a TypeScript project.

However, instead I am receiving this result:

export type Json =
  | string
  | number
  | boolean
  | null
  | { [key: string]: Json | undefined }
  | Json[]

export interface Database {
  openai: {
    Tables: {
      assistants: {
        Row: {
          assistant_id: string | null
          checksum: string | null
          created_at: string
          file_ids: Json | null
          id: number
          model: string | null
          name: string | null
          prompt: string | null
          raw_json_response: Json
          tools: Json | null
          updated_at: string
        }
        Insert: {
          assistant_id?: string | null
          checksum?: string | null
          created_at?: string
          file_ids?: Json | null
          id?: never
          model?: string | null
          name?: string | null
          prompt?: string | null
          raw_json_response: Json
          tools?: Json | null
          updated_at?: string
        }
        Update: {
          assistant_id?: string | null
          checksum?: string | null
          created_at?: string
          file_ids?: Json | null
          id?: never
          model?: string | null
          name?: string | null
          prompt?: string | null
          raw_json_response?: Json
          tools?: Json | null
          updated_at?: string
        }
        Relationships: []
      }
      messages: {
        Row: {
          assistant_id: string | null
          checksum: string | null
          created_at: string
          id: number
          message_id: string | null
          openai_created_at: number | null
          raw_json_response: Json
          role: string | null
          run_id: string | null
          thread_id: string | null
          updated_at: string
        }
        Insert: {
          assistant_id?: string | null
          checksum?: string | null
          created_at?: string
          id?: never
          message_id?: string | null
          openai_created_at?: number | null
          raw_json_response: Json
          role?: string | null
          run_id?: string | null
          thread_id?: string | null
          updated_at?: string
        }
        Update: {
          assistant_id?: string | null
          checksum?: string | null
          created_at?: string
          id?: never
          message_id?: string | null
          openai_created_at?: number | null
          raw_json_response?: Json
          role?: string | null
          run_id?: string | null
          thread_id?: string | null
          updated_at?: string
        }
        Relationships: []
      }
      runs: {
        Row: {
          assistant_id: string | null
          checksum: string | null
          created_at: string
          file_ids: Json | null
          id: number
          model: string | null
          raw_json_response: Json
          run_id: string | null
          status: string | null
          thread_id: string | null
          tools: Json | null
          updated_at: string
        }
        Insert: {
          assistant_id?: string | null
          checksum?: string | null
          created_at?: string
          file_ids?: Json | null
          id?: never
          model?: string | null
          raw_json_response: Json
          run_id?: string | null
          status?: string | null
          thread_id?: string | null
          tools?: Json | null
          updated_at?: string
        }
        Update: {
          assistant_id?: string | null
          checksum?: string | null
          created_at?: string
          file_ids?: Json | null
          id?: never
          model?: string | null
          raw_json_response?: Json
          run_id?: string | null
          status?: string | null
          thread_id?: string | null
          tools?: Json | null
          updated_at?: string
        }
        Relationships: []
      }
      threads: {
        Row: {
          checksum: string | null
          created_at: string
          deleted: boolean | null
          id: number
          raw_json_response: Json
          thread_id: string | null
          updated_at: string
        }
        Insert: {
          checksum?: string | null
          created_at?: string
          deleted?: boolean | null
          id?: never
          raw_json_response: Json
          thread_id?: string | null
          updated_at?: string
        }
        Update: {
          checksum?: string | null
          created_at?: string
          deleted?: boolean | null
          id?: never
          raw_json_response?: Json
          thread_id?: string | null
          updated_at?: string
        }
        Relationships: []
      }
    }
    Views: {
      [_ in never]: never
    }
    Functions: {
      [_ in never]: never
    }
    Enums: {
      [_ in never]: never
    }
    CompositeTypes: {
      [_ in never]: never
    }
  }
}

export type Tables<
  PublicTableNameOrOptions extends
    | keyof (Database["public"]["Tables"] & Database["public"]["Views"])
    | { schema: keyof Database },
  TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
    ? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
        Database[PublicTableNameOrOptions["schema"]]["Views"])
    : never = never
> = PublicTableNameOrOptions extends { schema: keyof Database }
  ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] &
      Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends {
      Row: infer R
    }
    ? R
    : never
  : PublicTableNameOrOptions extends keyof (Database["public"]["Tables"] &
      Database["public"]["Views"])
  ? (Database["public"]["Tables"] &
      Database["public"]["Views"])[PublicTableNameOrOptions] extends {
      Row: infer R
    }
    ? R
    : never
  : never

export type TablesInsert<
  PublicTableNameOrOptions extends
    | keyof Database["public"]["Tables"]
    | { schema: keyof Database },
  TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
    ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
    : never = never
> = PublicTableNameOrOptions extends { schema: keyof Database }
  ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
      Insert: infer I
    }
    ? I
    : never
  : PublicTableNameOrOptions extends keyof Database["public"]["Tables"]
  ? Database["public"]["Tables"][PublicTableNameOrOptions] extends {
      Insert: infer I
    }
    ? I
    : never
  : never

export type TablesUpdate<
  PublicTableNameOrOptions extends
    | keyof Database["public"]["Tables"]
    | { schema: keyof Database },
  TableName extends PublicTableNameOrOptions extends { schema: keyof Database }
    ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"]
    : never = never
> = PublicTableNameOrOptions extends { schema: keyof Database }
  ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends {
      Update: infer U
    }
    ? U
    : never
  : PublicTableNameOrOptions extends keyof Database["public"]["Tables"]
  ? Database["public"]["Tables"][PublicTableNameOrOptions] extends {
      Update: infer U
    }
    ? U
    : never
  : never

export type Enums<
  PublicEnumNameOrOptions extends
    | keyof Database["public"]["Enums"]
    | { schema: keyof Database },
  EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database }
    ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"]
    : never = never
> = PublicEnumNameOrOptions extends { schema: keyof Database }
  ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName]
  : PublicEnumNameOrOptions extends keyof Database["public"]["Enums"]
  ? Database["public"]["Enums"][PublicEnumNameOrOptions]
  : never

Screenshots

N/A

System information

Additional context

Described issue to Supabase support and they confirmed it's an issue with the metadata. Happy to take a shot at updating this and learning to become a contributor.

yingw787 commented 5 months ago

Not sure how I can take a ticket, but I'll fork, reproduce, update the metadata, and create a pull request shortly.