@@ -8,7 +8,7 @@ import type {
88 PostgresView ,
99} from '../../lib/index.js'
1010import type { GeneratorMetadata } from '../../lib/generators.js'
11- import { GENERATE_TYPES_DEFAULT_SCHEMA } from '../constants.js'
11+ import { GENERATE_TYPES_DEFAULT_SCHEMA , VALID_FUNCTION_ARGS_MODE } from '../constants.js'
1212
1313export const apply = async ( {
1414 schemas,
@@ -26,15 +26,99 @@ export const apply = async ({
2626 detectOneToOneRelationships : boolean
2727 postgrestVersion ?: string
2828} ) : Promise < string > => {
29+ schemas . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
30+
2931 const columnsByTableId = Object . fromEntries < PostgresColumn [ ] > (
3032 [ ...tables , ...foreignTables , ...views , ...materializedViews ] . map ( ( t ) => [ t . id , [ ] ] )
3133 )
32- columns
33- . filter ( ( c ) => c . table_id in columnsByTableId )
34- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
35- . forEach ( ( c ) => {
36- columnsByTableId [ c . table_id ] . push ( c )
37- } )
34+ for ( const column of columns ) {
35+ if ( column . table_id in columnsByTableId ) {
36+ columnsByTableId [ column . table_id ] . push ( column )
37+ }
38+ }
39+ for ( const tableId in columnsByTableId ) {
40+ columnsByTableId [ tableId ] . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
41+ }
42+
43+ const introspectionBySchema = Object . fromEntries < {
44+ tables : Pick < PostgresTable , 'id' | 'name' | 'schema' | 'columns' > [ ]
45+ views : PostgresView [ ]
46+ functions : { fn : PostgresFunction ; inArgs : PostgresFunction [ 'args' ] } [ ]
47+ enums : PostgresType [ ]
48+ compositeTypes : PostgresType [ ]
49+ } > (
50+ schemas . map ( ( s ) => [
51+ s . name ,
52+ { tables : [ ] , views : [ ] , functions : [ ] , enums : [ ] , compositeTypes : [ ] } ,
53+ ] )
54+ )
55+ for ( const table of tables ) {
56+ if ( table . schema in introspectionBySchema ) {
57+ introspectionBySchema [ table . schema ] . tables . push ( table )
58+ }
59+ }
60+ for ( const table of foreignTables ) {
61+ if ( table . schema in introspectionBySchema ) {
62+ introspectionBySchema [ table . schema ] . tables . push ( table )
63+ }
64+ }
65+ for ( const view of views ) {
66+ if ( view . schema in introspectionBySchema ) {
67+ introspectionBySchema [ view . schema ] . views . push ( view )
68+ }
69+ }
70+ for ( const materializedView of materializedViews ) {
71+ if ( materializedView . schema in introspectionBySchema ) {
72+ introspectionBySchema [ materializedView . schema ] . views . push ( {
73+ ...materializedView ,
74+ is_updatable : false ,
75+ } )
76+ }
77+ }
78+ for ( const func of functions ) {
79+ if ( func . schema in introspectionBySchema ) {
80+ func . args . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
81+ // Either:
82+ // 1. All input args are be named, or
83+ // 2. There is only one input arg which is unnamed
84+ const inArgs = func . args . filter ( ( { mode } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) )
85+
86+ if (
87+ // Case 1: Function has a single parameter
88+ inArgs . length === 1 ||
89+ // Case 2: All input args are named
90+ ! inArgs . some ( ( { name } ) => name === '' )
91+ ) {
92+ introspectionBySchema [ func . schema ] . functions . push ( { fn : func , inArgs } )
93+ }
94+ }
95+ }
96+ for ( const type of types ) {
97+ if ( type . schema in introspectionBySchema ) {
98+ if ( type . enums . length > 0 ) {
99+ introspectionBySchema [ type . schema ] . enums . push ( type )
100+ }
101+ if ( type . attributes . length > 0 ) {
102+ introspectionBySchema [ type . schema ] . compositeTypes . push ( type )
103+ }
104+ }
105+ }
106+ for ( const schema in introspectionBySchema ) {
107+ introspectionBySchema [ schema ] . tables . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
108+ introspectionBySchema [ schema ] . views . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
109+ introspectionBySchema [ schema ] . functions . sort ( ( a , b ) => a . fn . name . localeCompare ( b . fn . name ) )
110+ introspectionBySchema [ schema ] . enums . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
111+ introspectionBySchema [ schema ] . compositeTypes . sort ( ( a , b ) => a . name . localeCompare ( b . name ) )
112+ }
113+
114+ // group types by id for quicker lookup
115+ const typesById = types . reduce (
116+ ( acc , type ) => {
117+ acc [ type . id ] = type
118+ return acc
119+ } ,
120+ { } as Record < number , ( typeof types ) [ number ] >
121+ )
38122
39123 const internal_supabase_schema = postgrestVersion
40124 ? `// Allows to automatically instantiate createClient with right options
@@ -49,44 +133,15 @@ export type Json = string | number | boolean | null | { [key: string]: Json | un
49133
50134export type Database = {
51135 ${ internal_supabase_schema }
52- ${ schemas
53- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
54- . map ( ( schema ) => {
55- const schemaTables = [ ...tables , ...foreignTables ]
56- . filter ( ( table ) => table . schema === schema . name )
57- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
58- const schemaViews = [ ...views , ...materializedViews ]
59- . filter ( ( view ) => view . schema === schema . name )
60- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
61- const schemaFunctions = functions
62- . filter ( ( func ) => {
63- if ( func . schema !== schema . name ) {
64- return false
65- }
66-
67- // Either:
68- // 1. All input args are be named, or
69- // 2. There is only one input arg which is unnamed
70- const inArgs = func . args . filter ( ( { mode } ) => [ 'in' , 'inout' , 'variadic' ] . includes ( mode ) )
71-
72- if ( ! inArgs . some ( ( { name } ) => name === '' ) ) {
73- return true
74- }
75-
76- if ( inArgs . length === 1 ) {
77- return true
78- }
79-
80- return false
81- } )
82- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
83- const schemaEnums = types
84- . filter ( ( type ) => type . schema === schema . name && type . enums . length > 0 )
85- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
86- const schemaCompositeTypes = types
87- . filter ( ( type ) => type . schema === schema . name && type . attributes . length > 0 )
88- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
89- return `${ JSON . stringify ( schema . name ) } : {
136+ ${ schemas . map ( ( schema ) => {
137+ const {
138+ tables : schemaTables ,
139+ views : schemaViews ,
140+ functions : schemaFunctions ,
141+ enums : schemaEnums ,
142+ compositeTypes : schemaCompositeTypes ,
143+ } = introspectionBySchema [ schema . name ]
144+ return `${ JSON . stringify ( schema . name ) } : {
90145 Tables: {
91146 ${
92147 schemaTables . length === 0
@@ -105,9 +160,9 @@ export type Database = {
105160 } ) } ${ column . is_nullable ? '| null' : '' } `
106161 ) ,
107162 ...schemaFunctions
108- . filter ( ( fn ) => fn . argument_types === table . name )
109- . map ( ( fn ) => {
110- const type = types . find ( ( { id } ) => id === fn . return_type_id )
163+ . filter ( ( { fn } ) => fn . argument_types === table . name )
164+ . map ( ( { fn } ) => {
165+ const type = typesById [ fn . return_type_id ]
111166 let tsType = 'unknown'
112167 if ( type ) {
113168 tsType = pgTypeToTsType ( schema , type . name , {
@@ -226,7 +281,7 @@ export type Database = {
226281 ) }
227282 }
228283 ${
229- 'is_updatable' in view && view . is_updatable
284+ view . is_updatable
230285 ? `Insert: {
231286 ${ columnsByTableId [ view . id ] . map ( ( column ) => {
232287 let output = JSON . stringify ( column . name )
@@ -306,28 +361,29 @@ export type Database = {
306361
307362 const schemaFunctionsGroupedByName = schemaFunctions . reduce (
308363 ( acc , curr ) => {
309- acc [ curr . name ] ??= [ ]
310- acc [ curr . name ] . push ( curr )
364+ acc [ curr . fn . name ] ??= [ ]
365+ acc [ curr . fn . name ] . push ( curr )
311366 return acc
312367 } ,
313- { } as Record < string , PostgresFunction [ ] >
368+ { } as Record < string , typeof schemaFunctions >
314369 )
370+ for ( const fnName in schemaFunctionsGroupedByName ) {
371+ schemaFunctionsGroupedByName [ fnName ] . sort ( ( a , b ) =>
372+ b . fn . definition . localeCompare ( a . fn . definition )
373+ )
374+ }
315375
316376 return Object . entries ( schemaFunctionsGroupedByName ) . map (
317377 ( [ fnName , fns ] ) =>
318378 `${ JSON . stringify ( fnName ) } : {
319379 Args: ${ fns
320- . map ( ( { args } ) => {
321- const inArgs = args
322- . toSorted ( ( a , b ) => a . name . localeCompare ( b . name ) )
323- . filter ( ( { mode } ) => mode === 'in' )
324-
380+ . map ( ( { inArgs } ) => {
325381 if ( inArgs . length === 0 ) {
326382 return 'Record<PropertyKey, never>'
327383 }
328384
329385 const argsNameAndType = inArgs . map ( ( { name, type_id, has_default } ) => {
330- const type = types . find ( ( { id } ) => id === type_id )
386+ const type = typesById [ type_id ]
331387 let tsType = 'unknown'
332388 if ( type ) {
333389 tsType = pgTypeToTsType ( schema , type . name , {
@@ -346,10 +402,10 @@ export type Database = {
346402 . join ( ' | ' ) }
347403 Returns: ${ ( ( ) => {
348404 // Case 1: `returns table`.
349- const tableArgs = fns [ 0 ] . args . filter ( ( { mode } ) => mode === 'table' )
405+ const tableArgs = fns [ 0 ] . fn . args . filter ( ( { mode } ) => mode === 'table' )
350406 if ( tableArgs . length > 0 ) {
351407 const argsNameAndType = tableArgs . map ( ( { name, type_id } ) => {
352- const type = types . find ( ( { id } ) => id === type_id )
408+ const type = typesById [ type_id ]
353409 let tsType = 'unknown'
354410 if ( type ) {
355411 tsType = pgTypeToTsType ( schema , type . name , {
@@ -371,7 +427,7 @@ export type Database = {
371427
372428 // Case 2: returns a relation's row type.
373429 const relation = [ ...tables , ...views ] . find (
374- ( { id } ) => id === fns [ 0 ] . return_type_relation_id
430+ ( { id } ) => id === fns [ 0 ] . fn . return_type_relation_id
375431 )
376432 if ( relation ) {
377433 return `{
@@ -394,7 +450,7 @@ export type Database = {
394450 }
395451
396452 // Case 3: returns base/array/composite/enum type.
397- const type = types . find ( ( { id } ) => id === fns [ 0 ] . return_type_id )
453+ const type = typesById [ fns [ 0 ] . fn . return_type_id ]
398454 if ( type ) {
399455 return pgTypeToTsType ( schema , type . name , {
400456 types,
@@ -405,7 +461,7 @@ export type Database = {
405461 }
406462
407463 return 'unknown'
408- } ) ( ) } ${ fns [ 0 ] . is_set_returning_function ? '[]' : '' }
464+ } ) ( ) } ${ fns [ 0 ] . fn . is_set_returning_function ? '[]' : '' }
409465 }`
410466 )
411467 } ) ( ) }
@@ -430,7 +486,7 @@ export type Database = {
430486 ( { name, attributes } ) =>
431487 `${ JSON . stringify ( name ) } : {
432488 ${ attributes . map ( ( { name, type_id } ) => {
433- const type = types . find ( ( { id } ) => id === type_id )
489+ const type = typesById [ type_id ]
434490 let tsType = 'unknown'
435491 if ( type ) {
436492 tsType = `${ pgTypeToTsType ( schema , type . name , {
@@ -447,7 +503,7 @@ export type Database = {
447503 }
448504 }
449505 }`
450- } ) }
506+ } ) }
451507}
452508
453509type DatabaseWithoutInternals = Omit<Database, '__InternalSupabase'>
0 commit comments