@@ -8,11 +8,7 @@ import type {
8
8
PostgresView ,
9
9
} from '../../lib/index.js'
10
10
import 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'
16
12
17
13
export const apply = async ( {
18
14
schemas,
@@ -45,17 +41,18 @@ export const apply = async ({
45
41
} ,
46
42
{ } as Record < number , ( typeof types ) [ number ] >
47
43
)
44
+
48
45
const getFunctionTsReturnType = ( fn : PostgresFunction , returnType : string ) => {
49
46
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
+ : ''
56
55
} `
57
- : ''
58
- } `
59
56
}
60
57
61
58
const getFunctionReturnType = ( schema : PostgresSchema , fn : PostgresFunction ) : string => {
@@ -373,42 +370,42 @@ export type Database = {
373
370
return '[_ in never]: never'
374
371
}
375
372
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
+ // })
412
409
. reduce (
413
410
( acc , curr ) => {
414
411
acc [ curr . name ] ??= [ ]
@@ -417,238 +414,33 @@ export type Database = {
417
414
} ,
418
415
{ } as Record < string , PostgresFunction [ ] >
419
416
)
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
- } )
441
417
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 }
468
436
} )
469
-
470
- if ( hasConflict ) {
471
- conflictingSignatures . add ( argNames )
472
- }
437
+ argsType = `{ ${ argsNameAndType . map ( ( { name, type, has_default } ) => `${ JSON . stringify ( name ) } ${ has_default ? '?' : '' } : ${ type } ` ) } }`
473
438
}
474
- } )
475
439
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
+ } )
581
442
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' ) } `
652
444
} )
653
445
} ) ( ) }
654
446
}
0 commit comments