func (s *store) Relations(tables []table) ([]relation, error) {
	ts := make([]interface{}, len(tables))
	for i, t := range tables {
		ts[i] = []string{t.Schema, t.Name}
	}
	query := `
		with
		    schemas as (
		        select nspname, oid
		        from pg_namespace
		    ),
		    tables as (
		        select oid, relnamespace, relname, relkind
		        from pg_class
		    ),
		    columns as (
		        select attrelid, attname, attnum
		        from pg_attribute a
		        where a.attisdropped = false
		    )
		select distinct 
		       co.conname            as constraint_name,
		       ss.nspname            as schema_name,
		       s.relname             as table_name,
		       array_agg(sc.attname) as columns,
		       ts.nspname            as target_schema,
		       t.relname             as target_table,
		       array_agg(tc.attname) as target_columns
		from pg_constraint co
		left join tables s on co.conrelid = s.oid
		left join schemas ss on s.relnamespace = ss.oid
		left join columns sc on s.oid = sc.attrelid and sc.attnum = any (co.conkey)
		left join tables t on co.confrelid = t.oid
		left join schemas ts on t.relnamespace = ts.oid
		left join columns tc on t.oid = tc.attrelid and tc.attnum = any (co.confkey)
		where co.contype = 'f'
		  and co.conrelid in (select oid from pg_class c where c.relkind = 'r')
		  and array_position(co.conkey, sc.attnum) = array_position(co.confkey, tc.attnum)
		  and (ss.nspname, s.relname) in (?)
		group by constraint_name, schema_name, table_name, target_schema, target_table
	`
	var relations []relation
	if _, err := s.db.Query(&relations, query, pg.InMulti(ts...)); err != nil {
		return nil, fmt.Errorf("getting relations info error: %w", err)
	}
	return relations, nil
}
Relations gets relations of a selected table
package genna
import (
	"fmt"
	"sort"
	"strings"
	"github.com/dizzyfool/genna/model"
	"github.com/dizzyfool/genna/util"
	"github.com/go-pg/pg/v9"
	"github.com/go-pg/pg/v9/orm"
)
var formatter = orm.Formatter{}
func format(pattern string, values ...interface{}) string {
	return string(formatter.FormatQuery([]byte{}, pattern, values...))
}
type table struct {
	Schema string `pg:"table_schema"`
	Name   string `pg:"table_name"`
}
func (t table) Entity() model.Entity {
	return model.NewEntity(t.Schema, t.Name, nil, nil)
}
type relation struct {
	Constraint    string   `pg:"constraint_name"`
	SourceSchema  string   `pg:"schema_name"`
	SourceTable   string   `pg:"table_name"`
	SourceColumns []string `pg:"columns,array"`
	TargetSchema  string   `pg:"target_schema"`
	TargetTable   string   `pg:"target_table"`
	TargetColumns []string `pg:"target_columns,array"`
}
func (r relation) Relation() model.Relation {
	return model.NewRelation(r.SourceColumns, r.TargetSchema, r.TargetTable)
}
func (r relation) Target() table {
	return table{
		Schema: r.TargetSchema,
		Name:   r.TargetTable,
	}
}
type column struct {
	tableName struct{} `pg:",discard_unknown_columns"`
	Schema     string   `pg:"schema_name"`
	Table      string   `pg:"table_name"`
	Name       string   `pg:"column_name"`
	IsNullable bool     `pg:"nullable"`
	IsArray    bool     `pg:"array"`
	Dimensions int      `pg:"dims"`
	Type       string   `pg:"type"`
	Default    string   `pg:"def"`
	IsPK       bool     `pg:"pk"`
	IsFK       bool     `pg:"fk"`
	MaxLen     int      `pg:"len"`
	Values     []string `pg:"enum,array"`
}
func (c column) Column(useSQLNulls bool, goPGVer int, customTypes model.CustomTypeMapping) model.Column {
	return model.NewColumn(c.Name, c.Type, c.IsNullable, useSQLNulls, c.IsArray, c.Dimensions, c.IsPK, c.IsFK, c.MaxLen, c.Values, goPGVer, customTypes)
}
type store struct {
	db orm.DB
}
func newStore(db orm.DB) *store {
	return &store{db: db}
}
func (s *store) Schemas() ([]string, error) {
	query := `select nspname from pg_catalog.pg_namespace`
	var result []string
	if _, err := s.db.Query(&result, query); err != nil {
		return nil, fmt.Errorf("getting schemas info error: %w", err)
	}
	return result, nil
}
func (s *store) Tables(selected []string) ([]table, error) {
	var schemas []string
	var tables []interface{}
	for _, s := range selected {
		schema, table := util.Split(s)
		if table == "*" {
			schemas = append(schemas, schema)
		} else {
			tables = append(tables, []string{schema, table})
		}
	}
	var where []string
	if len(schemas) > 0 {
		where = append(where, format("(table_schema) in (?)", pg.In(schemas)))
	}
	if len(tables) > 0 {
		where = append(where, format("(table_schema, table_name) in (?)", pg.InMulti(tables...)))
	}
	query := `
        select 
            table_schema,
            table_name
        from information_schema.tables
        where 
            table_type = 'BASE TABLE' and 
            (
                ` + strings.Join(where, "or \n") + `
            )`
	var result []table
	if _, err := s.db.Query(&result, query); err != nil {
		return nil, fmt.Errorf("getting tables info error: %w", err)
	}
	return result, nil
}