@@ -13,14 +13,37 @@ export type Options = {
1313 output : Writable | string ;
1414
1515 /**
16- * Name overrides for enums, classes, and fields.
16+ * The name of the exported enum (Which encapsulates all tables)
17+ * Default: "Table"
18+ */
19+ tablesEnumName ?: string ;
20+
21+ /**
22+ * Name overrides for enums, schemas, tables and columns.
23+ * Check tests for more info.
1724 *
1825 * @example
1926 * overrides: {
2027 * "identity_provider.linkedin": "LinkedIn"
2128 * }
29+ *
30+ * @example
31+ * Override a table name with a function
32+ *
33+ * overrides: {
34+ * // Overwrite the 'user' table name
35+ * user: (x, type, defaultValue) => UserTable
36+ * }
37+ *
38+ * @example
39+ * Tag all schemas, tables and columns
40+ *
41+ * overrides: {
42+ * // Append "Table" to all tables and TitleCase the name
43+ * "*": (x, type, defaultValue) => type === "table" ? "Table" + upperFirst(camelCase(x.table)) : defaultValue
44+ * }
2245 */
23- overrides ?: Record < string , string > ;
46+ overrides ?: Record < string , OverrideStringFunction > ;
2447
2548 /**
2649 * Overrides of column types.
@@ -153,7 +176,7 @@ export type Options = {
153176 * Generates TypeScript definitions (types) from a PostgreSQL database schema.
154177 */
155178export async function updateTypes ( db : Knex , options : Options ) : Promise < void > {
156- const overrides : Record < string , string > = options . overrides ?? { } ;
179+ const overrides = options . overrides ?? { } ;
157180 const output : Writable =
158181 typeof options . output === "string"
159182 ? fs . createWriteStream ( options . output , { encoding : "utf-8" } )
@@ -218,7 +241,7 @@ export async function updateTypes(db: Knex, options: Options): Promise<void> {
218241 const enumsMap = new Map (
219242 enums . map ( ( x ) => [
220243 x . key ,
221- overrides [ x . key ] ?? upperFirst ( camelCase ( x . key ) ) ,
244+ ( overrides [ x . key ] as string ) ?? upperFirst ( camelCase ( x . key ) ) ,
222245 ] )
223246 ) ;
224247
@@ -243,17 +266,33 @@ export async function updateTypes(db: Knex, options: Options): Promise<void> {
243266 ) ;
244267
245268 // The list of database tables as enum
246- output . write ( "export enum Table {\n" ) ;
247- const tableSet = new Set (
248- columns . map ( ( x ) => {
249- const schema = x . schema !== "public" ? `${ x . schema } .` : "" ;
250- return `${ schema } ${ x . table } ` ;
251- } )
252- ) ;
253- Array . from ( tableSet ) . forEach ( ( value ) => {
254- const key = overrides [ value ] ?? upperFirst ( camelCase ( value ) ) ;
269+ output . write ( `export enum ${ options . tablesEnumName || "Table" } {\n` ) ;
270+
271+ // Unique schema / table combination array
272+ const tables : { table : string ; schema : string } [ ] = [
273+ ...new Set (
274+ columns . map ( ( x ) => JSON . stringify ( { table : x . table , schema : x . schema } ) )
275+ ) ,
276+ ] . map ( ( t ) => JSON . parse ( t ) ) ;
277+
278+ // Write enum tables
279+ for ( const table of tables ) {
280+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
281+ const x = columns . find (
282+ ( x ) => x . table === table . table && x . schema === table . schema
283+ ) ! ;
284+
285+ const tableName =
286+ overrideName ( x , "table" , overrides ) ?? upperFirst ( camelCase ( x . table ) ) ;
287+ let schemaName =
288+ x . schema !== "public" ? upperFirst ( camelCase ( x . schema ) ) : "" ;
289+ schemaName = overrideName ( x , "schema" , overrides ) ?? schemaName ;
290+ const key = `${ schemaName } ${ tableName } ` ;
291+
292+ const schema = x . schema !== "public" ? `${ x . schema } .` : "" ;
293+ const value = `${ schema } ${ x . table } ` ;
255294 output . write ( ` ${ key } = "${ value } ",\n` ) ;
256- } ) ;
295+ }
257296 output . write ( "}\n\n" ) ;
258297
259298 // Construct TypeScript db record types
@@ -262,15 +301,21 @@ export async function updateTypes(db: Knex, options: Options): Promise<void> {
262301 columns [ i - 1 ] && columns [ i - 1 ] . table === x . table
263302 ) ;
264303
265- // Export table type
304+ // Export schema & table type
266305 if ( isTableFirstColumn ) {
267- const tableName = overrides [ x . table ] ?? upperFirst ( camelCase ( x . table ) ) ;
268- const schemaName =
306+ const tableName =
307+ overrideName ( x , "table" , overrides ) ?? upperFirst ( camelCase ( x . table ) ) ;
308+
309+ // Doing it this way because I need to separate the trinary expression from the ?? operator (doesn't work).
310+ let schemaName =
269311 x . schema !== "public" ? upperFirst ( camelCase ( x . schema ) ) : "" ;
312+ schemaName = overrideName ( x , "schema" , overrides ) ?? schemaName ;
313+
270314 output . write ( `export type ${ schemaName } ${ tableName } = {\n` ) ;
271315 }
272316
273317 // Set column type
318+ const columnName = overrideName ( x , "column" , overrides ) ?? x . column ;
274319 const isArrayType = x . type === "ARRAY" ;
275320 let type = overrideType ( x , options ) ?? getType ( x , enumsMap ) ;
276321
@@ -280,7 +325,7 @@ export async function updateTypes(db: Knex, options: Options): Promise<void> {
280325 // Process the "*" type override if provided
281326 type = typePostProcessor ( x , type , options ) ;
282327
283- output . write ( ` ${ x . column } : ${ type } ;\n` ) ;
328+ output . write ( ` ${ columnName } : ${ type } ;\n` ) ;
284329
285330 if ( ! ( columns [ i + 1 ] && columns [ i + 1 ] . table === x . table ) ) {
286331 output . write ( "};\n\n" ) ;
@@ -297,7 +342,7 @@ export async function updateTypes(db: Knex, options: Options): Promise<void> {
297342 }
298343}
299344
300- type Enum = {
345+ export type Enum = {
301346 key : string ;
302347 value : string ;
303348} ;
@@ -312,17 +357,24 @@ export type Column = {
312357 udt : string ;
313358} ;
314359
315- type TypeOverride = Record <
316- string ,
317- string | ( ( x : Column , defaultType ?: string ) => string )
318- > ;
319- type TypePostProcessor = Record <
360+ export type NameOverrideCategory = keyof Column &
361+ ( "table" | "schema" | "column" ) ;
362+ export type OverrideStringFunction =
363+ | string
364+ | ( (
365+ x : Column ,
366+ category : NameOverrideCategory ,
367+ defaultValue : string | null
368+ ) => string | null ) ;
369+
370+ export type TypeOverride = Record < string , string | ( ( x : Column ) => string ) > ;
371+ export type TypePostProcessor = Record <
320372 "*" ,
321373 string | ( ( x : Column , defaultType : string ) => string )
322374> ;
323375
324376export function getType ( x : Column , customTypes : Map < string , string > ) : string {
325- const udt = x . type === "ARRAY" ? x . udt . substring ( 1 ) : x . udt ;
377+ const udt : string = x . type === "ARRAY" ? x . udt . substring ( 1 ) : x . udt ;
326378
327379 switch ( udt ) {
328380 case "bool" :
@@ -390,24 +442,22 @@ export function overrideType(x: Column, options: Options): string | null {
390442 const overrideTableColumnTypes = options . overrideTableColumnTypes ?? true ;
391443 if ( overrideTableColumnTypes && `${ x . table } .${ x . column } ` in typeOverrides ) {
392444 const tableColumnType = typeOverrides [ `${ x . table } .${ x . column } ` ] ;
393- return typeof tableColumnType === "function"
394- ? tableColumnType ( x )
395- : tableColumnType ;
445+ return isFunction ( tableColumnType ) ? tableColumnType ( x ) : tableColumnType ;
396446 }
397447
398448 // Override all matching columns type
399449 const overrideColumnTypes = options . overrideColumnTypes ?? true ;
400450 if ( overrideColumnTypes && x . column in typeOverrides ) {
401451 const columnType = typeOverrides [ x . column ] ;
402- return typeof columnType === "function" ? columnType ( x ) : columnType ;
452+ return isFunction ( columnType ) ? columnType ( x ) : columnType ;
403453 }
404454
405455 // Override the database's default type if provided.
406456 const overrideDefaultTypes = options . overrideDefaultTypes ?? true ;
407457 const udt = x . type === "ARRAY" ? x . udt . substring ( 1 ) : x . udt ;
408458 if ( overrideDefaultTypes && udt in typeOverrides ) {
409459 const type = typeOverrides [ udt ] ;
410- return typeof type === "function" ? type ( x ) : type ;
460+ return isFunction ( type ) ? type ( x ) : type ;
411461 }
412462
413463 return null ;
@@ -428,11 +478,57 @@ export function typePostProcessor(
428478
429479 // If the "*" has been provided, return its value.
430480 if ( "*" in typeOverrides ) {
431- return typeof typeOverrides [ "*" ] === "function"
481+ return isFunction ( typeOverrides [ "*" ] )
432482 ? typeOverrides [ "*" ] ( x , type )
433483 : typeOverrides [ "*" ] ;
434484 }
435485
436486 // Return the default type
437487 return type ;
438488}
489+
490+ // eslint-disable-next-line @typescript-eslint/ban-types
491+ function isFunction ( value : unknown ) : value is Function {
492+ return typeof value === "function" ;
493+ }
494+
495+ export function overrideName (
496+ x : Column ,
497+ category : NameOverrideCategory ,
498+ overrides : Record < string , OverrideStringFunction >
499+ ) : string | null {
500+ let name : string | null = null ;
501+ const defaultValue = x [ category ] ;
502+
503+ if ( category === "column" ) {
504+ // Run override for specific table column
505+ if ( `${ x . table } .${ x . column } ` in overrides ) {
506+ const override = overrides [ `${ x . table } .${ x . column } ` ] ;
507+ name = isFunction ( override )
508+ ? override ( x , category , defaultValue )
509+ : override ;
510+ } else if ( x . column in overrides ) {
511+ // Run override for all columns with same name
512+ const override = overrides [ x . column ] ;
513+ name = isFunction ( override )
514+ ? override ( x , category , defaultValue )
515+ : override ;
516+ }
517+ } else {
518+ // Run override for specific name/key
519+ if ( x [ category ] in overrides ) {
520+ const override = overrides [ x [ category ] ] ;
521+ name = isFunction ( override )
522+ ? override ( x , category , defaultValue )
523+ : override ;
524+ }
525+ }
526+
527+ if ( "*" in overrides ) {
528+ name = isFunction ( overrides [ "*" ] )
529+ ? overrides [ "*" ] ( x , category , name )
530+ : overrides [ "*" ] ;
531+ }
532+
533+ return name ;
534+ }
0 commit comments