gin-base/database/drivers/pgsql/pgsql_table_fields.go

108 lines
3.5 KiB
Go

// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package pgsql
import (
"context"
"fmt"
"git.magicany.cc/black1552/gin-base/database"
"github.com/gogf/gf/v2/util/gutil"
)
var (
tableFieldsSqlTmp = `
SELECT
a.attname AS field,
t.typname AS type,
a.attnotnull AS null,
(CASE WHEN d.contype = 'p' THEN 'pri' WHEN d.contype = 'u' THEN 'uni' ELSE '' END) AS key,
ic.column_default AS default_value,
b.description AS comment,
COALESCE(character_maximum_length, numeric_precision, -1) AS length,
numeric_scale AS scale
FROM pg_attribute a
LEFT JOIN pg_class c ON a.attrelid = c.oid
LEFT JOIN pg_constraint d ON d.conrelid = c.oid AND a.attnum = d.conkey[1]
LEFT JOIN pg_description b ON a.attrelid = b.objoid AND a.attnum = b.objsubid
LEFT JOIN pg_type t ON a.atttypid = t.oid
LEFT JOIN information_schema.columns ic ON ic.column_name = a.attname AND ic.table_name = c.relname
WHERE c.oid = '%s'::regclass
AND a.attisdropped IS FALSE
AND a.attnum > 0
ORDER BY a.attnum`
)
func init() {
var err error
tableFieldsSqlTmp, err = database.FormatMultiLineSqlToSingle(tableFieldsSqlTmp)
if err != nil {
panic(err)
}
}
// TableFields retrieves and returns the fields' information of specified table of current schema.
func (d *Driver) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*database.TableField, err error) {
var (
result database.Result
link database.Link
usedSchema = gutil.GetOrDefaultStr(d.GetSchema(), schema...)
// TODO duplicated `id` result?
structureSql = fmt.Sprintf(tableFieldsSqlTmp, table)
)
if link, err = d.SlaveLink(usedSchema); err != nil {
return nil, err
}
result, err = d.DoSelect(ctx, link, structureSql)
if err != nil {
return nil, err
}
fields = make(map[string]*database.TableField)
var (
index = 0
name string
ok bool
existingField *database.TableField
)
for _, m := range result {
name = m["field"].String()
// Merge duplicated fields, especially for key constraints.
// Priority: pri > uni > others
if existingField, ok = fields[name]; ok {
currentKey := m["key"].String()
// Merge key information with priority: pri > uni
if currentKey == "pri" || (currentKey == "uni" && existingField.Key != "pri") {
existingField.Key = currentKey
}
continue
}
var (
fieldType string
dataType = m["type"].String()
dataLength = m["length"].Int()
)
if dataLength > 0 {
fieldType = fmt.Sprintf("%s(%d)", dataType, dataLength)
} else {
fieldType = dataType
}
fields[name] = &database.TableField{
Index: index,
Name: name,
Type: fieldType,
Null: !m["null"].Bool(),
Key: m["key"].String(),
Default: m["default_value"].Val(),
Comment: m["comment"].String(),
}
index++
}
return fields, nil
}