2019-08-17 18:32:01 +02:00
|
|
|
package postgres
|
|
|
|
|
|
|
|
|
|
import (
|
2021-07-27 17:39:21 +02:00
|
|
|
"context"
|
2019-08-17 18:32:01 +02:00
|
|
|
"database/sql"
|
2023-07-21 13:20:44 +02:00
|
|
|
"fmt"
|
2022-12-05 22:45:45 +05:30
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
"github.com/go-jet/jet/v2/generator/metadata"
|
|
|
|
|
"github.com/go-jet/jet/v2/qrm"
|
2019-08-17 18:32:01 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// postgresQuerySet is dialect query set for PostgreSQL
|
|
|
|
|
type postgresQuerySet struct{}
|
|
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
func (p postgresQuerySet) GetTablesMetaData(db *sql.DB, schemaName string, tableType metadata.TableType) ([]metadata.Table, error) {
|
2021-07-27 17:39:21 +02:00
|
|
|
query := `
|
2026-02-01 18:16:50 -03:00
|
|
|
SELECT table_name as "table.name", obj_description((quote_ident(table_schema)||'.'||quote_ident(table_name))::regclass, 'pg_class') as "table.comment"
|
2019-08-17 18:32:01 +02:00
|
|
|
FROM information_schema.tables
|
2022-12-05 22:45:45 +05:30
|
|
|
WHERE table_schema = $1 and table_type = $2
|
|
|
|
|
ORDER BY table_name;
|
2019-08-17 18:32:01 +02:00
|
|
|
`
|
2021-07-27 17:39:21 +02:00
|
|
|
var tables []metadata.Table
|
2019-08-17 18:32:01 +02:00
|
|
|
|
2022-01-12 19:03:50 +01:00
|
|
|
_, err := qrm.Query(context.Background(), db, query, []interface{}{schemaName, tableType}, &tables)
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to query %s metadata: %w", tableType, err)
|
|
|
|
|
}
|
2021-07-27 17:39:21 +02:00
|
|
|
|
2024-02-01 15:20:49 +01:00
|
|
|
// add materialized views separately, because materialized views are not part of standard information schema
|
|
|
|
|
if tableType == metadata.ViewTable {
|
|
|
|
|
matViewQuery := `
|
|
|
|
|
select matviewname as "table.name"
|
|
|
|
|
from pg_matviews
|
|
|
|
|
where schemaname = $1;
|
|
|
|
|
`
|
|
|
|
|
var matViews []metadata.Table
|
|
|
|
|
|
|
|
|
|
_, err := qrm.Query(context.Background(), db, matViewQuery, []interface{}{schemaName}, &matViews)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to query materialized view metadata: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tables = append(tables, matViews...)
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
for i := range tables {
|
2024-02-01 15:20:49 +01:00
|
|
|
tables[i].Columns, err = getColumnsMetaData(db, schemaName, tables[i].Name)
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to query %s columns metadata: %w", tableType, err)
|
|
|
|
|
}
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
return tables, nil
|
2019-08-17 18:32:01 +02:00
|
|
|
}
|
|
|
|
|
|
2024-02-01 15:20:49 +01:00
|
|
|
func getColumnsMetaData(db *sql.DB, schemaName string, tableName string) ([]metadata.Column, error) {
|
2021-07-27 17:39:21 +02:00
|
|
|
query := `
|
2024-02-01 15:20:49 +01:00
|
|
|
select
|
|
|
|
|
attr.attname as "column.Name",
|
2024-09-26 14:33:23 +02:00
|
|
|
col_description(attr.attrelid, attr.attnum) as "column.Comment",
|
2024-02-01 15:20:49 +01:00
|
|
|
exists(
|
|
|
|
|
select 1
|
|
|
|
|
from pg_catalog.pg_index indx
|
|
|
|
|
where attr.attrelid = indx.indrelid and attr.attnum = any(indx.indkey) and indx.indisprimary
|
|
|
|
|
) as "column.IsPrimaryKey",
|
|
|
|
|
not attr.attnotnull as "column.isNullable",
|
|
|
|
|
attr.attgenerated = 's' as "column.isGenerated",
|
2024-08-13 14:52:54 -06:00
|
|
|
attr.atthasdef as "column.hasDefault",
|
2025-10-16 15:09:07 +02:00
|
|
|
(case when tp.typcategory = 'A' then greatest(1, attr.attndims) --cockroach num dims fix
|
|
|
|
|
else 0
|
|
|
|
|
end) as "dataType.dimensions",
|
|
|
|
|
(case coalesce(elem.typtype, tp.typtype)
|
|
|
|
|
when 'b' then 'base'
|
|
|
|
|
when 'd' then 'base'
|
|
|
|
|
when 'e' then 'enum'
|
|
|
|
|
when 'r' then 'range'
|
|
|
|
|
end) as "dataType.Kind",
|
2024-02-01 15:20:49 +01:00
|
|
|
(case when tp.typtype = 'd' then (select pg_type.typname from pg_catalog.pg_type where pg_type.oid = tp.typbasetype)
|
2025-10-16 15:09:07 +02:00
|
|
|
when tp.typcategory = 'A' then elem.typname
|
2024-02-01 15:20:49 +01:00
|
|
|
else tp.typname
|
2025-10-16 15:09:07 +02:00
|
|
|
end) as "dataType.Name",
|
2024-02-01 15:20:49 +01:00
|
|
|
false as "dataType.isUnsigned"
|
|
|
|
|
from pg_catalog.pg_attribute as attr
|
|
|
|
|
join pg_catalog.pg_class as cls on cls.oid = attr.attrelid
|
|
|
|
|
join pg_catalog.pg_namespace as ns on ns.oid = cls.relnamespace
|
|
|
|
|
join pg_catalog.pg_type as tp on tp.oid = attr.atttypid
|
2025-10-16 15:09:07 +02:00
|
|
|
left join pg_catalog.pg_type elem ON tp.typelem = elem.oid -- only for arrays
|
2024-02-01 15:20:49 +01:00
|
|
|
where
|
|
|
|
|
ns.nspname = $1 and
|
|
|
|
|
cls.relname = $2 and
|
|
|
|
|
not attr.attisdropped and
|
|
|
|
|
attr.attnum > 0
|
|
|
|
|
order by
|
|
|
|
|
attr.attnum;
|
2021-07-27 17:39:21 +02:00
|
|
|
`
|
|
|
|
|
var columns []metadata.Column
|
2022-01-12 19:03:50 +01:00
|
|
|
_, err := qrm.Query(context.Background(), db, query, []interface{}{schemaName, tableName}, &columns)
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to query '%s' columns metadata: %w", tableName, err)
|
|
|
|
|
}
|
2021-07-27 17:39:21 +02:00
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
return columns, nil
|
2019-08-17 18:32:01 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
func (p postgresQuerySet) GetEnumsMetaData(db *sql.DB, schemaName string) ([]metadata.Enum, error) {
|
2021-07-27 17:39:21 +02:00
|
|
|
query := `
|
|
|
|
|
SELECT t.typname as "enum.name",
|
2026-02-01 18:16:50 -03:00
|
|
|
obj_description(t.oid, 'pg_type') as "enum.comment",
|
2021-07-27 17:39:21 +02:00
|
|
|
e.enumlabel as "values"
|
2019-08-17 18:32:01 +02:00
|
|
|
FROM pg_catalog.pg_type t
|
|
|
|
|
JOIN pg_catalog.pg_enum e on t.oid = e.enumtypid
|
|
|
|
|
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
|
|
|
|
WHERE n.nspname = $1
|
|
|
|
|
ORDER BY n.nspname, t.typname, e.enumsortorder;`
|
|
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
var result []metadata.Enum
|
2019-08-17 18:32:01 +02:00
|
|
|
|
2022-01-12 19:03:50 +01:00
|
|
|
_, err := qrm.Query(context.Background(), db, query, []interface{}{schemaName}, &result)
|
2023-07-21 13:20:44 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to query enums metadata for schema '%s': %w", schemaName, err)
|
|
|
|
|
}
|
2019-08-17 18:32:01 +02:00
|
|
|
|
2023-07-21 13:20:44 +02:00
|
|
|
return result, nil
|
2019-08-17 18:32:01 +02:00
|
|
|
}
|