Skip to content
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

Return types for RPC cannot have nullable properties #841

Open
dbuhon opened this issue Nov 9, 2023 · 2 comments
Open

Return types for RPC cannot have nullable properties #841

dbuhon opened this issue Nov 9, 2023 · 2 comments

Comments

@dbuhon
Copy link

dbuhon commented Nov 9, 2023

The supabase gen types appears to lack support for RPC functions returning objects with nullable properties.

Steps to reproduce:

Define an RPC function:

   CREATE TYPE status_type_enum AS ENUM ('rotten', 'ripe'); 
   
   CREATE FUNCTION get_bananas(
     _limit INT DEFAULT NULL,
     _offset INT DEFAULT 0
   )
   RETURNS TABLE (
     id UUID,
     text TEXT,
     current_status status_type_enum -- Is there a way to make this nullable in TS?
   )
   LANGUAGE plpgsql
   AS $$
   BEGIN
     RETURN QUERY
     SELECT
       b.id,
       b.text,
       s.status_type AS current_status
     FROM bananas b
     LEFT JOIN statuses s ON b.id = s.banana_id AND s.user_id = auth.uid()
     LIMIT _limit
     OFFSET _offset;
   END;
   $$;

Run the command:

npx supabase gen types

Examine the generated types:
It doesn't seem possible to make current_status nullable out of the box, even though it can be missing.

   get_bananas: {
     Args: {
       _limit?: number;
       _offset?: number;
     };
     Returns: {
       id: string;
       text: string;
       current_status: Database['public']['Enums']['status_type_enum'];
       // current_status: null | Database['public']['Enums']['status_type_enum'];
     }[];
   };

Workaround

Extend the generated types from another file to overwrite properties.

@Marviel
Copy link

Marviel commented Jan 4, 2024

One thing that changing this will likely do is affect a lot of people's code.

(i.e. types that were previously non-null are now suddenly going to throw a lot of typescript compile errors)

So it may be wise to have this behind some sort of feature flag, i.e. --rpc-allow-null-results or something like that.

@wmarrujo
Copy link

wmarrujo commented Oct 4, 2024

here's my workaround:

type PartialNullBy<T, E extends keyof T> = {[K in keyof T]: K extends E ? (T[K] | null) : T[K]}
type PartialBy<T, K extends keyof T> = Omit<T, K> & Pick<Partial<T>, K>
type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never
type Debug<T> = T extends Function ? T : {[K in keyof T]: T[K]}

use the PartialNullBy type for supabase to wrap the object part of what you get back. I've included the ArrayElement type so you can apply it to the object part of the type when you're getting a whole array (table) of objects. I also included a PartialBy just for completeness, which will do the same thing using undefined instead.

let {data} = await locals.supabase.rpc("get_bananas")
let better = data as Array<PartialNullBy<ArrayElement<typeof data>, "current_status" | "another_column_if_you_want">>

now, the resultant type will look gross, but you can wrap the whole thing with Debug to check that it evaluated correctly

@sweatybridge sweatybridge transferred this issue from supabase/cli Nov 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants