@@ -8,11 +8,7 @@ import type {
88 PostgresView ,
99} from '../../lib/index.js'
1010import type { GeneratorMetadata } from '../../lib/generators.js'
11- import {
12- GENERATE_TYPES_DEFAULT_SCHEMA ,
13- VALID_FUNCTION_ARGS_MODE ,
14- VALID_UNNAMED_FUNCTION_ARG_TYPES ,
15- } from '../constants.js'
11+ import { GENERATE_TYPES_DEFAULT_SCHEMA , VALID_FUNCTION_ARGS_MODE } from '../constants.js'
1612
1713export const apply = async ( {
1814 schemas,
@@ -45,17 +41,18 @@ export const apply = async ({
4541 } ,
4642 { } as Record < number , ( typeof types ) [ number ] >
4743 )
44+
4845 const getFunctionTsReturnType = ( fn : PostgresFunction , returnType : string ) => {
4946 return `${ returnType } ${ fn . is_set_returning_function && fn . returns_multiple_rows ? '[]' : '' }
50- ${
51- fn . returns_set_of_table && fn . args . length === 1 && fn . args [ 0 ] . table_name
52- ? `SetofOptions: {
53- from: ${ JSON . stringify ( typesById [ fn . args [ 0 ] . type_id ] . format ) }
54- to: ${ JSON . stringify ( fn . return_table_name ) }
55- isOneToOne: ${ fn . returns_multiple_rows ? false : true }
47+ ${
48+ fn . returns_set_of_table && fn . args . length === 1 && fn . args [ 0 ] . table_name
49+ ? `SetofOptions: {
50+ from: ${ JSON . stringify ( typesById [ fn . args [ 0 ] . type_id ] . format ) }
51+ to: ${ JSON . stringify ( fn . return_table_name ) }
52+ isOneToOne: ${ fn . returns_multiple_rows ? false : true }
53+ }`
54+ : ''
5655 } `
57- : ''
58- } `
5956 }
6057
6158 const getFunctionReturnType = ( schema : PostgresSchema , fn : PostgresFunction ) : string => {
@@ -373,42 +370,42 @@ export type Database = {
373370 return '[_ in never]: never'
374371 }
375372 const schemaFunctionsGroupedByName = schemaFunctions
376- . filter ( ( func ) => {
377- // Get all input args (in, inout, variadic modes)
378- const inArgs = func . args . filter ( ( { mode } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) )
379- // Case 1: Function has no parameters
380- if ( inArgs . length === 0 ) {
381- return true
382- }
383-
384- // Case 2: All input args are named
385- if ( ! inArgs . some ( ( { name } ) => name === '' ) ) {
386- return true
387- }
388-
389- // Case 3: All unnamed args have default values
390- if ( inArgs . every ( ( arg ) => ( arg . name === '' ? arg . has_default : true ) ) ) {
391- return true
392- }
393-
394- // Case 4: Single unnamed parameter of valid type (json, jsonb, text)
395- // Exclude all functions definitions that have only one single argument unnamed argument that isn't
396- // a json/jsonb/text as it won't be considered by PostgREST
397- if (
398- ( inArgs . length === 1 &&
399- inArgs [ 0 ] . name === '' &&
400- VALID_UNNAMED_FUNCTION_ARG_TYPES . has ( inArgs [ 0 ] . type_id ) ) ||
401- // OR if the function have a single unnamed args which is another table (embeded function)
402- ( inArgs . length === 1 &&
403- inArgs [ 0 ] . name === '' &&
404- inArgs [ 0 ] . table_name &&
405- func . return_table_name )
406- ) {
407- return true
408- }
409-
410- return false
411- } )
373+ // .filter((func) => {
374+ // // Get all input args (in, inout, variadic modes)
375+ // const inArgs = func.args.filter(({ mode }) => VALID_FUNCTION_ARGS_MODE.has(mode))
376+ // // Case 1: Function has no parameters
377+ // if (inArgs.length === 0) {
378+ // return true
379+ // }
380+
381+ // // Case 2: All input args are named
382+ // if (!inArgs.some(({ name }) => name === '')) {
383+ // return true
384+ // }
385+
386+ // // Case 3: All unnamed args have default values
387+ // if (inArgs.every((arg) => (arg.name === '' ? arg.has_default : true))) {
388+ // return true
389+ // }
390+
391+ // // Case 4: Single unnamed parameter of valid type (json, jsonb, text)
392+ // // Exclude all functions definitions that have only one single argument unnamed argument that isn't
393+ // // a json/jsonb/text as it won't be considered by PostgREST
394+ // if (
395+ // (inArgs.length === 1 &&
396+ // inArgs[0].name === '' &&
397+ // VALID_UNNAMED_FUNCTION_ARG_TYPES.has(inArgs[0].type_id)) ||
398+ // // OR if the function have a single unnamed args which is another table (embeded function)
399+ // (inArgs.length === 1 &&
400+ // inArgs[0].name === '' &&
401+ // inArgs[0].table_name &&
402+ // func.return_table_name)
403+ // ) {
404+ // return true
405+ // }
406+
407+ // return false
408+ // })
412409 . reduce (
413410 ( acc , curr ) => {
414411 acc [ curr . name ] ??= [ ]
@@ -417,238 +414,33 @@ export type Database = {
417414 } ,
418415 { } as Record < string , PostgresFunction [ ] >
419416 )
420- const sortedGroupdSchemaFunctions = Object . entries (
421- schemaFunctionsGroupedByName
422- ) . toSorted ( ( a , b ) => a [ 0 ] . localeCompare ( b [ 0 ] ) )
423-
424- return sortedGroupdSchemaFunctions . map ( ( [ fnName , fns ] ) => {
425- // Group functions by their argument names signature to detect conflicts
426- const fnsByArgNames = new Map < string , PostgresFunction [ ] > ( )
427- fns . sort ( ( fn1 , fn2 ) => fn1 . id - fn2 . id )
428-
429- fns . forEach ( ( fn ) => {
430- const namedInArgs = fn . args
431- . filter ( ( { mode, name } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) && name !== '' )
432- . map ( ( arg ) => arg . name )
433- . sort ( )
434- . join ( ',' )
435-
436- if ( ! fnsByArgNames . has ( namedInArgs ) ) {
437- fnsByArgNames . set ( namedInArgs , [ ] )
438- }
439- fnsByArgNames . get ( namedInArgs ) ! . push ( fn )
440- } )
441417
442- // For each group of functions sharing the same argument names, check if they have conflicting types
443- const conflictingSignatures = new Set < string > ( )
444- fnsByArgNames . forEach ( ( groupedFns , argNames ) => {
445- if ( groupedFns . length > 1 ) {
446- // Check if any args have different types within this group
447- const firstFn = groupedFns [ 0 ]
448- const firstFnArgTypes = new Map (
449- firstFn . args
450- . filter (
451- ( { mode, name } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) && name !== ''
452- )
453- . map ( ( arg ) => [ arg . name , String ( arg . type_id ) ] )
454- )
455-
456- const hasConflict = groupedFns . some ( ( fn ) => {
457- const fnArgTypes = new Map (
458- fn . args
459- . filter (
460- ( { mode, name } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) && name !== ''
461- )
462- . map ( ( arg ) => [ arg . name , String ( arg . type_id ) ] )
463- )
464-
465- return [ ...firstFnArgTypes . entries ( ) ] . some (
466- ( [ name , typeId ] ) => fnArgTypes . get ( name ) !== typeId
467- )
418+ return Object . entries ( schemaFunctionsGroupedByName ) . map ( ( [ fnName , fns ] ) => {
419+ const functionSignatures = fns . map ( ( fn ) => {
420+ const inArgs = fn . args . filter ( ( { mode } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) )
421+
422+ let argsType = 'Record<PropertyKey, never>'
423+ if ( inArgs . length > 0 ) {
424+ const argsNameAndType = inArgs . map ( ( { name, type_id, has_default } ) => {
425+ const type = types . find ( ( { id } ) => id === type_id )
426+ let tsType = 'unknown'
427+ if ( type ) {
428+ tsType = pgTypeToTsType ( schema , type . name , {
429+ types,
430+ schemas,
431+ tables,
432+ views,
433+ } )
434+ }
435+ return { name, type : tsType , has_default }
468436 } )
469-
470- if ( hasConflict ) {
471- conflictingSignatures . add ( argNames )
472- }
437+ argsType = `{ ${ argsNameAndType . map ( ( { name, type, has_default } ) => `${ JSON . stringify ( name ) } ${ has_default ? '?' : '' } : ${ type } ` ) } }`
473438 }
474- } )
475439
476- // Generate all possible function signatures as a union
477- const signatures = ( ( ) => {
478- const allSignatures : string [ ] = [ ]
479-
480- // First check if we have a no-param function
481- const noParamFns = fns . filter (
482- ( fn ) =>
483- fn . args . length === 0 ||
484- // If all the params of a function have non potgrest proxyable arguments
485- fn . args . every ( ( arg ) => ! VALID_FUNCTION_ARGS_MODE . has ( arg . mode ) )
486- )
487- const unnamedFns = fns . filter ( ( fn ) => {
488- // Only include unnamed functions that:
489- // 1. Have a single unnamed parameter
490- // 2. The parameter is of a valid type (json, jsonb, text)
491- // 3. All parameters have default values
492- const inArgs = fn . args . filter ( ( { mode } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) )
493- return (
494- inArgs . length === 1 &&
495- inArgs [ 0 ] . name === '' &&
496- ( VALID_UNNAMED_FUNCTION_ARG_TYPES . has ( inArgs [ 0 ] . type_id ) ||
497- inArgs [ 0 ] . has_default ) &&
498- ! fn . return_table_name
499- )
500- } )
501-
502- // Special case: one no-param function and unnamed param function exist
503- if ( noParamFns . length > 0 ) {
504- const noParamFn = noParamFns [ 0 ]
505- const unnamedWithDefaultsFn = unnamedFns . find ( ( fn ) =>
506- fn . args . every ( ( arg ) => arg . has_default )
507- )
508-
509- // If we have a function with unnamed params that all have defaults, it creates a conflict
510- if ( unnamedWithDefaultsFn ) {
511- // Only generate the error signature in this case
512- const conflictDesc = [
513- `${ fnName } ()` ,
514- `${ fnName } ( => ${ typesById [ unnamedWithDefaultsFn . args [ 0 ] . type_id ] ?. name || 'unknown' } )` ,
515- ]
516- . sort ( )
517- . join ( ', ' )
518-
519- allSignatures . push ( `{
520- Args: Record<PropertyKey, never>
521- Returns: { error: true } & "Could not choose the best candidate function between: ${ conflictDesc } . Try renaming the parameters or the function itself in the database so function overloading can be resolved"
522- }` )
523- } else {
524- // No conflict - just add the no params signature
525- allSignatures . push ( `{
526- Args: Record<PropertyKey, never>
527- Returns: ${ getFunctionTsReturnType ( noParamFn , getFunctionReturnType ( schema , noParamFn ) ) }
528- }` )
529- }
530- }
531- if ( unnamedFns . length > 0 ) {
532- // If we don't have a no-param function, process the unnamed args
533- // Take only the first function with unnamed parameters that has a valid type
534- const validUnnamedFn = unnamedFns . find (
535- ( fn ) =>
536- fn . args . length === 1 &&
537- fn . args [ 0 ] . name === '' &&
538- VALID_UNNAMED_FUNCTION_ARG_TYPES . has ( fn . args [ 0 ] . type_id )
539- )
540-
541- if ( validUnnamedFn ) {
542- const firstArgType = typesById [ validUnnamedFn . args [ 0 ] . type_id ]
543- const tsType = firstArgType
544- ? pgTypeToTsType ( schema , firstArgType . name , {
545- types,
546- schemas,
547- tables,
548- views,
549- } )
550- : 'unknown'
551-
552- allSignatures . push ( `{
553- Args: { "": ${ tsType } }
554- Returns: ${ getFunctionTsReturnType ( validUnnamedFn , getFunctionReturnType ( schema , validUnnamedFn ) ) }
555- }` )
556- }
557- }
558- const unnamedSetofFunctions = fns . filter ( ( fn ) => {
559- // Only include unnamed functions that:
560- // 1. Have a single unnamed parameter
561- // 2. The parameter is of a valid type (json, jsonb, text)
562- // 3. All parameters have default values
563- const inArgs = fn . args . filter ( ( { mode } ) => VALID_FUNCTION_ARGS_MODE . has ( mode ) )
564- return inArgs . length === 1 && inArgs [ 0 ] . name === '' && fn . return_table_name
565- } )
566- if ( unnamedSetofFunctions . length > 0 ) {
567- const unnamedEmbededFunctionsSignatures = unnamedSetofFunctions . map ( ( fn ) => {
568- const firstArgType = typesById [ fn . args [ 0 ] . type_id ]
569- const tsType = firstArgType
570- ? pgTypeToTsType ( schema , firstArgType . name , {
571- types,
572- schemas,
573- tables,
574- views,
575- } )
576- : 'Record<PropertyKey, never>'
577- return `{ Args: ${ tsType } , Returns: ${ getFunctionTsReturnType ( fn , getFunctionReturnType ( schema , fn ) ) } }`
578- } )
579- allSignatures . push ( ...unnamedEmbededFunctionsSignatures )
580- }
440+ return `{ Args: ${ argsType } ; Returns: ${ getFunctionTsReturnType ( fn , getFunctionReturnType ( schema , fn ) ) } }`
441+ } )
581442
582- // For functions with named parameters, generate all signatures
583- const namedFns = fns . filter ( ( fn ) => ! fn . args . some ( ( { name } ) => name === '' ) )
584- namedFns . forEach ( ( fn ) => {
585- const inArgs = fn . args . filter ( ( { mode } ) => mode === 'in' )
586- const namedInArgs = inArgs
587- . filter ( ( arg ) => arg . name !== '' )
588- . map ( ( arg ) => arg . name )
589- . sort ( )
590- . join ( ',' )
591-
592- // If this argument combination would cause a conflict, return an error type signature
593- if ( conflictingSignatures . has ( namedInArgs ) ) {
594- const conflictingFns = fnsByArgNames . get ( namedInArgs ) !
595- const conflictDesc = conflictingFns
596- . map ( ( cfn ) => {
597- const argsStr = cfn . args
598- . filter ( ( { mode } ) => mode === 'in' )
599- . map ( ( arg ) => {
600- const type = typesById [ arg . type_id ]
601- return `${ arg . name } => ${ type ?. name || 'unknown' } `
602- } )
603- . sort ( )
604- . join ( ', ' )
605- return `${ fnName } (${ argsStr } )`
606- } )
607- . sort ( )
608- . join ( ', ' )
609-
610- allSignatures . push ( `{
611- Args: { ${ inArgs
612- . map ( ( arg ) => `${ JSON . stringify ( arg . name ) } : unknown` )
613- . sort ( )
614- . join ( ', ' ) } }
615- Returns: { error: true } & "Could not choose the best candidate function between: ${ conflictDesc } . Try renaming the parameters or the function itself in the database so function overloading can be resolved"
616- }` )
617- } else if ( inArgs . length > 0 ) {
618- // Generate normal function signature
619- const returnType = getFunctionReturnType ( schema , fn )
620- allSignatures . push ( `{
621- Args: ${ `{ ${ inArgs
622- . map ( ( { name, type_id, has_default } ) => {
623- const type = typesById [ type_id ]
624- let tsType = 'unknown'
625- if ( type ) {
626- tsType = pgTypeToTsType ( schema , type . name , {
627- types,
628- schemas,
629- tables,
630- views,
631- } )
632- }
633- return `${ JSON . stringify ( name ) } ${ has_default ? '?' : '' } : ${ tsType } `
634- } )
635- . sort ( )
636- . join ( ', ' ) } }`}
637- Returns: ${ getFunctionTsReturnType ( fn , returnType ) }
638- }` )
639- }
640- } )
641-
642- // Remove duplicates and sort
643- return Array . from ( new Set ( allSignatures ) ) . sort ( )
644- } ) ( )
645-
646- if ( signatures . length > 0 ) {
647- // Remove duplicates, sort, and join with |
648- return `${ JSON . stringify ( fnName ) } : ${ signatures . join ( '\n | ' ) } `
649- } else {
650- return `${ JSON . stringify ( fnName ) } : ${ fns . map ( ( fn ) => `{ Args: {}, Returns: ${ getFunctionTsReturnType ( fn , getFunctionReturnType ( schema , fn ) ) } }` ) . join ( '\n |' ) } `
651- }
443+ return `${ JSON . stringify ( fnName ) } :\n${ functionSignatures . map ( ( sig ) => `| ${ sig } ` ) . join ( '\n' ) } `
652444 } )
653445 } ) ( ) }
654446 }
0 commit comments