@@ -15,15 +15,13 @@ export const apply = ({
15
15
materializedViews,
16
16
functions,
17
17
types,
18
- arrayTypes,
19
18
} : {
20
19
schemas : PostgresSchema [ ]
21
20
tables : ( PostgresTable & { columns : unknown [ ] } ) [ ]
22
21
views : ( PostgresView & { columns : unknown [ ] } ) [ ]
23
22
materializedViews : ( PostgresMaterializedView & { columns : unknown [ ] } ) [ ]
24
23
functions : PostgresFunction [ ]
25
24
types : PostgresType [ ]
26
- arrayTypes : PostgresType [ ]
27
25
} ) : string => {
28
26
let output = `
29
27
export type Json = string | number | boolean | null | { [key: string]: Json } | Json[]
@@ -63,6 +61,15 @@ export interface Database {
63
61
const schemaEnums = types
64
62
. filter ( ( type ) => type . schema === schema . name && type . enums . length > 0 )
65
63
. sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
64
+ const schemaDomainTypes = types
65
+ . flatMap ( ( type ) => {
66
+ const baseType =
67
+ type . schema === schema . name &&
68
+ type . base_type_id &&
69
+ types . find ( ( { id } ) => id === type . base_type_id )
70
+ return baseType ? [ { type, baseType } ] : [ ]
71
+ } )
72
+ . sort ( ( { type : { name : a } } , { type : { name : b } } ) => a . localeCompare ( b ) )
66
73
const schemaCompositeTypes = types
67
74
. filter ( ( type ) => type . schema === schema . name && type . attributes . length > 0 )
68
75
. sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
@@ -82,8 +89,9 @@ export interface Database {
82
89
`${ JSON . stringify ( column . name ) } : ${ pgTypeToTsType (
83
90
column . format ,
84
91
types ,
85
- schemas
86
- ) } ${ column . is_nullable ? '| null' : '' } `
92
+ schemas ,
93
+ { nullable : column . is_nullable }
94
+ ) } `
87
95
) ,
88
96
...schemaFunctions
89
97
. filter ( ( fn ) => fn . argument_types === table . name )
@@ -93,7 +101,7 @@ export interface Database {
93
101
fn . return_type ,
94
102
types ,
95
103
schemas
96
- ) } | null `
104
+ ) } `
97
105
) ,
98
106
] }
99
107
}
@@ -117,11 +125,9 @@ export interface Database {
117
125
output += ':'
118
126
}
119
127
120
- output += pgTypeToTsType ( column . format , types , schemas )
121
-
122
- if ( column . is_nullable ) {
123
- output += '| null'
124
- }
128
+ output += pgTypeToTsType ( column . format , types , schemas , {
129
+ nullable : column . is_nullable ,
130
+ } )
125
131
126
132
return output
127
133
} ) }
@@ -136,11 +142,9 @@ export interface Database {
136
142
return `${ output } ?: never`
137
143
}
138
144
139
- output += `?: ${ pgTypeToTsType ( column . format , types , schemas ) } `
140
-
141
- if ( column . is_nullable ) {
142
- output += '| null'
143
- }
145
+ output += `?: ${ pgTypeToTsType ( column . format , types , schemas , {
146
+ nullable : column . is_nullable ,
147
+ } ) } `
144
148
145
149
return output
146
150
} ) }
@@ -163,8 +167,9 @@ export interface Database {
163
167
`${ JSON . stringify ( column . name ) } : ${ pgTypeToTsType (
164
168
column . format ,
165
169
types ,
166
- schemas
167
- ) } ${ column . is_nullable ? '| null' : '' } `
170
+ schemas ,
171
+ { nullable : column . is_nullable }
172
+ ) } `
168
173
) }
169
174
}
170
175
${
@@ -179,7 +184,9 @@ export interface Database {
179
184
return `${ output } ?: never`
180
185
}
181
186
182
- output += `?: ${ pgTypeToTsType ( column . format , types , schemas ) } | null`
187
+ output += `?: ${ pgTypeToTsType ( column . format , types , schemas , {
188
+ nullable : true ,
189
+ } ) } `
183
190
184
191
return output
185
192
} ) }
@@ -198,7 +205,9 @@ export interface Database {
198
205
return `${ output } ?: never`
199
206
}
200
207
201
- output += `?: ${ pgTypeToTsType ( column . format , types , schemas ) } | null`
208
+ output += `?: ${ pgTypeToTsType ( column . format , types , schemas , {
209
+ nullable : true ,
210
+ } ) } `
202
211
203
212
return output
204
213
} ) }
@@ -239,17 +248,7 @@ export interface Database {
239
248
}
240
249
241
250
const argsNameAndType = inArgs . map ( ( { name, type_id, has_default } ) => {
242
- let type = arrayTypes . find ( ( { id } ) => id === type_id )
243
- if ( type ) {
244
- // If it's an array type, the name looks like `_int8`.
245
- const elementTypeName = type . name . substring ( 1 )
246
- return {
247
- name,
248
- type : `(${ pgTypeToTsType ( elementTypeName , types , schemas ) } )[]` ,
249
- has_default,
250
- }
251
- }
252
- type = types . find ( ( { id } ) => id === type_id )
251
+ const type = types . find ( ( { id } ) => id === type_id )
253
252
if ( type ) {
254
253
return {
255
254
name,
@@ -272,19 +271,13 @@ export interface Database {
272
271
const tableArgs = args . filter ( ( { mode } ) => mode === 'table' )
273
272
if ( tableArgs . length > 0 ) {
274
273
const argsNameAndType = tableArgs . map ( ( { name, type_id } ) => {
275
- let type = arrayTypes . find ( ( { id } ) => id === type_id )
274
+ const type = types . find ( ( { id } ) => id === type_id )
276
275
if ( type ) {
277
- // If it's an array type, the name looks like `_int8`.
278
- const elementTypeName = type . name . substring ( 1 )
279
276
return {
280
277
name,
281
- type : `( ${ pgTypeToTsType ( elementTypeName , types , schemas ) } )[]` ,
278
+ type : pgTypeToTsType ( type . name , types , schemas ) ,
282
279
}
283
280
}
284
- type = types . find ( ( { id } ) => id === type_id )
285
- if ( type ) {
286
- return { name, type : pgTypeToTsType ( type . name , types , schemas ) }
287
- }
288
281
return { name, type : 'unknown' }
289
282
} )
290
283
@@ -308,8 +301,9 @@ export interface Database {
308
301
`${ JSON . stringify ( column . name ) } : ${ pgTypeToTsType (
309
302
column . format ,
310
303
types ,
311
- schemas
312
- ) } ${ column . is_nullable ? '| null' : '' } `
304
+ schemas ,
305
+ { nullable : column . is_nullable }
306
+ ) } `
313
307
) }
314
308
}`
315
309
}
@@ -340,6 +334,21 @@ export interface Database {
340
334
)
341
335
}
342
336
}
337
+ DomainTypes: {
338
+ ${
339
+ schemaDomainTypes . length === 0
340
+ ? '[_ in never]: never'
341
+ : schemaDomainTypes . map (
342
+ ( { type : domain_ , baseType } ) =>
343
+ `${ JSON . stringify ( domain_ . name ) } : ${ pgTypeToTsType (
344
+ baseType . name ,
345
+ types ,
346
+ schemas ,
347
+ { nullable : domain_ . is_nullable }
348
+ ) } `
349
+ )
350
+ }
351
+ }
343
352
CompositeTypes: {
344
353
${
345
354
schemaCompositeTypes . length === 0
@@ -377,58 +386,72 @@ export interface Database {
377
386
const pgTypeToTsType = (
378
387
pgType : string ,
379
388
types : PostgresType [ ] ,
380
- schemas : PostgresSchema [ ]
389
+ schemas : PostgresSchema [ ] ,
390
+ opts : { nullable ?: boolean } = { }
381
391
) : string => {
382
- if ( pgType === 'bool' ) {
383
- return 'boolean'
384
- } else if ( [ 'int2' , 'int4' , 'int8' , 'float4' , 'float8' , 'numeric' ] . includes ( pgType ) ) {
385
- return 'number'
386
- } else if (
387
- [
388
- 'bytea' ,
389
- 'bpchar' ,
390
- 'varchar' ,
391
- 'date' ,
392
- 'text' ,
393
- 'citext' ,
394
- 'time' ,
395
- 'timetz' ,
396
- 'timestamp' ,
397
- 'timestamptz' ,
398
- 'uuid' ,
399
- 'vector' ,
400
- ] . includes ( pgType )
401
- ) {
402
- return 'string'
403
- } else if ( [ 'json' , 'jsonb' ] . includes ( pgType ) ) {
404
- return 'Json'
405
- } else if ( pgType === 'void' ) {
406
- return 'undefined'
407
- } else if ( pgType === 'record' ) {
408
- return 'Record<string, unknown>'
409
- } else if ( pgType . startsWith ( '_' ) ) {
410
- return `(${ pgTypeToTsType ( pgType . substring ( 1 ) , types , schemas ) } )[]`
411
- } else {
412
- const enumType = types . find ( ( type ) => type . name === pgType && type . enums . length > 0 )
413
- if ( enumType ) {
414
- if ( schemas . some ( ( { name } ) => name === enumType . schema ) ) {
415
- return `Database[${ JSON . stringify ( enumType . schema ) } ]['Enums'][${ JSON . stringify (
416
- enumType . name
417
- ) } ]`
392
+ const type = types . find ( ( type ) => type . name === pgType )
393
+ const strictTsType = pgTypeToStrictTsType ( )
394
+ return strictTsType
395
+ ? `${ strictTsType } ${ opts . nullable ?? type ?. is_nullable ? ' | null' : '' } `
396
+ : 'unknown'
397
+
398
+ function pgTypeToStrictTsType ( ) {
399
+ if ( pgType === 'bool' ) {
400
+ return 'boolean'
401
+ } else if ( [ 'int2' , 'int4' , 'int8' , 'float4' , 'float8' , 'numeric' ] . includes ( pgType ) ) {
402
+ return 'number'
403
+ } else if (
404
+ [
405
+ 'bytea' ,
406
+ 'bpchar' ,
407
+ 'varchar' ,
408
+ 'date' ,
409
+ 'text' ,
410
+ 'citext' ,
411
+ 'time' ,
412
+ 'timetz' ,
413
+ 'timestamp' ,
414
+ 'timestamptz' ,
415
+ 'uuid' ,
416
+ 'vector' ,
417
+ ] . includes ( pgType )
418
+ ) {
419
+ return 'string'
420
+ } else if ( [ 'json' , 'jsonb' ] . includes ( pgType ) ) {
421
+ return 'Json'
422
+ } else if ( pgType === 'void' ) {
423
+ return 'undefined'
424
+ } else if ( pgType === 'record' ) {
425
+ return 'Record<string, unknown>'
426
+ } else if ( pgType . startsWith ( '_' ) ) {
427
+ return `(${ pgTypeToTsType ( pgType . substring ( 1 ) , types , schemas ) } )[]`
428
+ } else if ( type != null ) {
429
+ if ( type . base_type_id != null ) {
430
+ if ( schemas . some ( ( { name } ) => name === type . schema ) ) {
431
+ return `Database[${ JSON . stringify ( type . schema ) } ]['DomainTypes'][${ JSON . stringify (
432
+ type . name
433
+ ) } ]`
434
+ }
435
+ return undefined
436
+ }
437
+
438
+ if ( type . enums . length > 0 ) {
439
+ if ( schemas . some ( ( { name } ) => name === type . schema ) ) {
440
+ return `Database[${ JSON . stringify ( type . schema ) } ]['Enums'][${ JSON . stringify ( type . name ) } ]`
441
+ }
442
+ return type . enums . map ( ( variant ) => JSON . stringify ( variant ) ) . join ( '|' )
418
443
}
419
- return enumType . enums . map ( ( variant ) => JSON . stringify ( variant ) ) . join ( '|' )
420
- }
421
444
422
- const compositeType = types . find ( ( type ) => type . name === pgType && type . attributes . length > 0 )
423
- if ( compositeType ) {
424
- if ( schemas . some ( ( { name } ) => name === compositeType . schema ) ) {
425
- return `Database[${ JSON . stringify (
426
- compositeType . schema
427
- ) } ]['CompositeTypes'][${ JSON . stringify ( compositeType . name ) } ]`
445
+ if ( type . attributes . length > 0 ) {
446
+ if ( schemas . some ( ( { name } ) => name === type . schema ) ) {
447
+ return `Database[${ JSON . stringify ( type . schema ) } ]['CompositeTypes'][${ JSON . stringify (
448
+ type . name
449
+ ) } ]`
450
+ }
451
+ return undefined
428
452
}
429
- return 'unknown'
430
453
}
431
454
432
- return 'unknown'
455
+ return undefined
433
456
}
434
457
}
0 commit comments