diff --git a/src/dialects/postgres.parser.ts b/src/dialects/postgres.parser.ts index 90f3026..bef933b 100644 --- a/src/dialects/postgres.parser.ts +++ b/src/dialects/postgres.parser.ts @@ -9,66 +9,58 @@ const pgArrayAggToArray = (agg: string) => agg.replace(/{/g, '').replace(/}/g, ' const getColumnType = (dbType: string): PropertyType => { switch (dbType) { - case 'uuid': return 'uuid'; - case 'bigint': - case 'int8': - case 'bigserial': - case 'serial8': - case 'integer': - case 'int': - case 'int4': - case 'smallint': - case 'int2': - case 'serial': - case 'serial4': - case 'smallserial': - case 'serial2': - return 'number'; - case 'double precision': - case 'float8': - case 'numeric': - case 'decimal': - case 'real': - case 'float4': - return 'float'; - case 'money': - return 'currency'; - case 'boolean': - return 'boolean'; - case 'time': - case 'time with time zone': - case 'timetz': - case 'time without time zone': - case 'timestamp': - case 'timestamp with time zone': - case 'timestamptz': - case 'timestamp without time zone': - return 'datetime'; - case 'date': - return 'date'; - case 'json': - case 'jsonb': - return 'key-value'; - case 'text': - case 'character varying': - case 'char': - case 'varchar': - default: - return 'string'; + case 'USER-DEFINED': + return 'mixed'; + case 'uuid': + return 'uuid'; + case 'bigint': + case 'int8': + case 'bigserial': + case 'serial8': + case 'integer': + case 'int': + case 'int4': + case 'smallint': + case 'int2': + case 'serial': + case 'serial4': + case 'smallserial': + case 'serial2': + return 'number'; + case 'double precision': + case 'float8': + case 'numeric': + case 'decimal': + case 'real': + case 'float4': + return 'float'; + case 'money': + return 'currency'; + case 'boolean': + return 'boolean'; + case 'time': + case 'time with time zone': + case 'timetz': + case 'time without time zone': + case 'timestamp': + case 'timestamp with time zone': + case 'timestamptz': + case 'timestamp without time zone': + return 'datetime'; + case 'date': + return 'date'; + case 'json': + case 'jsonb': + return 'key-value'; + case 'text': + case 'character varying': + case 'char': + case 'varchar': + default: + return 'string'; } }; -const getColumnInfo = (column: Record): ColumnInfo => ({ - name: column.column_name as string, - isId: column.key_type === 'PRIMARY KEY', - position: column.ordinal_position as number, - defaultValue: column.column_default, - isNullable: column.is_nullable === 'YES', - isEditable: column.is_updatable === 'YES', - type: column.referenced_table ? 'reference' : getColumnType(column.data_type as string), - referencedTable: (column.referenced_table ?? null) as string | null, -}); - export class PostgresParser extends BaseDatabaseParser { public static dialects = ['postgresql' as const]; @@ -96,10 +88,10 @@ export class PostgresParser extends BaseDatabaseParser { public async getTables(schemaName: string) { const query = await this.knex.raw(` - SELECT table_name - FROM information_schema.tables - WHERE table_type='BASE TABLE' - AND table_schema='${schemaName}' + SELECT table_name + FROM information_schema.tables + WHERE table_type='BASE TABLE' + AND table_schema='${schemaName}' `); const result = await query; @@ -177,7 +169,7 @@ export class PostgresParser extends BaseDatabaseParser { const relations = await relQuery; - return columns.map((col) => { + return Promise.all(columns.map(async (col) => { const rel = relations.rows.find((r) => { const cols = pgArrayAggToArray(r.col); if (cols.length > 1) return null; // AdminJS doesn't support multiple foreign keys @@ -189,7 +181,35 @@ export class PostgresParser extends BaseDatabaseParser { col.referenced_table = rel.referenced_table; } - return new Property(getColumnInfo(col)); - }); + return new Property(await this.getColumnInfo(col)); + })); + } + + + async getColumnInfo(column: Record): Promise { + return { + name: column.column_name as string, + isId: column.key_type === 'PRIMARY KEY', + position: column.ordinal_position as number, + defaultValue: column.column_default, + isNullable: column.is_nullable === 'YES', + isEditable: column.is_updatable === 'YES', + type: column.referenced_table ? ('reference' as PropertyType) : getColumnType(column.data_type as string), + referencedTable: (column.referenced_table ?? null) as string | null, + availableValues: await this.getAvailableValues(column), + } + } + + async getAvailableValues(column: Record): Promise { + if (column.data_type !== 'USER-DEFINED' || !column.udt_name) { + return null; + } + const query = this.knex + .from('pg_catalog.pg_enum as e') + .select('e.enumlabel') + .leftJoin('pg_catalog.pg_type as t', (c) => c.on('e.enumtypid', 't.oid')) + .where('t.typname', column.udt_name); + const labels = await query; + return labels.map((l) => l.enumlabel as string) } }