183 lines
4.9 KiB
Go
183 lines
4.9 KiB
Go
package gormcol
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"gorm.io/gorm/schema"
|
|
)
|
|
|
|
// NamingStrategy is the GORM naming strategy used for column/table name resolution.
|
|
// Defaults to gorm.io/gorm/schema.NamingStrategy.
|
|
// Set this to NamingStrategy when using within a project that has a database connection.
|
|
var NamingStrategy schema.Namer = schema.NamingStrategy{}
|
|
|
|
type Tabler interface {
|
|
TableName() string
|
|
}
|
|
|
|
// Field represents a GORM column descriptor with table context.
|
|
// Define package-level variables to get type-safe column references:
|
|
//
|
|
// var PsAccess = struct {
|
|
// IDProfile gormcol.Field
|
|
// IDAuthorizationRole gormcol.Field
|
|
// }{
|
|
// IDProfile: gormcol.Field{Table: "ps_access", Column: "id_profile"},
|
|
// IDAuthorizationRole: gormcol.Field{Table: "ps_access", Column: "id_authorization_role"},
|
|
// }
|
|
type Field struct {
|
|
Table string
|
|
Column string
|
|
}
|
|
|
|
// Column returns the column name from a Field descriptor.
|
|
//
|
|
// gormcol.Column(prestadb.PsAccess.IDAuthorizationRole) // "id_authorization_role"
|
|
func Column(f Field) string {
|
|
return f.Column
|
|
}
|
|
|
|
// ColumnOnTable returns "table.column" from a Field descriptor.
|
|
//
|
|
// gormcol.ColumnOnTable(prestadb.PsAccess.IDAuthorizationRole) // "ps_access.id_authorization_role"
|
|
func ColumnOnTable(f Field) string {
|
|
return f.Table + "." + f.Column
|
|
}
|
|
|
|
// TableField returns the table name from a Field descriptor.
|
|
func TableField(f Field) string {
|
|
return f.Table
|
|
}
|
|
|
|
// -- Reflection-based utilities (for structs without Field descriptors) --
|
|
|
|
// Col extracts the GORM column name from the `gorm:"column:..."` struct tag.
|
|
//
|
|
// gormcol.Col[prestadb.PsAccess]("IDAuthorizationRole") // "id_authorization_role"
|
|
func Col[T any](fieldName string) string {
|
|
var zero T
|
|
typ := reflect.TypeOf(zero)
|
|
return columnFromType(typ, fieldName)
|
|
}
|
|
|
|
// ColOf extracts a GORM column name from a field on a nested struct referenced
|
|
// by structFieldName.
|
|
func ColOf[T, S any](structFieldName, fieldName string) string {
|
|
var zero T
|
|
typ := reflect.TypeOf(zero)
|
|
|
|
field, ok := typ.FieldByName(structFieldName)
|
|
if !ok {
|
|
panic(fmt.Sprintf("gormcol: struct %q has no field %q", typ.Name(), structFieldName))
|
|
}
|
|
|
|
return columnFromType(field.Type, fieldName)
|
|
}
|
|
|
|
// Tbl returns the table name for a GORM model.
|
|
// Uses TableName() method if the struct implements Tabler,
|
|
// otherwise falls back to the GORM naming strategy.
|
|
//
|
|
// gormcol.Tbl[prestadb.PsAccess]() // "ps_access"
|
|
func Tbl[T any]() string {
|
|
var zero T
|
|
if t, ok := any(zero).(Tabler); ok {
|
|
return t.TableName()
|
|
}
|
|
typ := reflect.TypeOf(zero)
|
|
return NamingStrategy.TableName(typ.Name())
|
|
}
|
|
|
|
// ColOnTbl returns the column prefixed with the table name (reflection-based).
|
|
//
|
|
// gormcol.ColOnTbl[prestadb.PsAccess]("IDAuthorizationRole") // "ps_access.id_authorization_role"
|
|
func ColOnTbl[T any](fieldName string) string {
|
|
return Tbl[T]() + "." + Col[T](fieldName)
|
|
}
|
|
|
|
// PK returns the primary key column name for a GORM model.
|
|
//
|
|
// gormcol.PK[prestadb.PsAccess]() // "id_authorization_role"
|
|
func PK[T any]() string {
|
|
var zero T
|
|
typ := reflect.TypeOf(zero)
|
|
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
field := typ.Field(i)
|
|
gormTag := field.Tag.Get("gorm")
|
|
if gormTag == "" || gormTag == "-" {
|
|
continue
|
|
}
|
|
for _, part := range strings.Split(gormTag, ";") {
|
|
if strings.TrimSpace(part) == "primaryKey" {
|
|
return parseGormColumn(gormTag)
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Columns returns all GORM column names for a struct type.
|
|
//
|
|
// gormcol.Columns[prestadb.PsAccess]() // []string{"id_profile", "id_authorization_role"}
|
|
func Columns[T any]() []string {
|
|
var zero T
|
|
typ := reflect.TypeOf(zero)
|
|
|
|
var cols []string
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
field := typ.Field(i)
|
|
if field.PkgPath != "" {
|
|
continue
|
|
}
|
|
col := parseGormColumn(field.Tag.Get("gorm"))
|
|
if col == "" {
|
|
col = NamingStrategy.ColumnName(typ.Name(), field.Name)
|
|
}
|
|
cols = append(cols, col)
|
|
}
|
|
return cols
|
|
}
|
|
|
|
// ColByJSON finds the GORM column name by matching the struct field's json tag.
|
|
//
|
|
// gormcol.ColByJSON[prestadb.PsAccess]("id_authorization_role") // "id_authorization_role"
|
|
func ColByJSON[T any](jsonName string) string {
|
|
var zero T
|
|
typ := reflect.TypeOf(zero)
|
|
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
field := typ.Field(i)
|
|
jsonTag := field.Tag.Get("json")
|
|
if jsonTag == "" {
|
|
continue
|
|
}
|
|
tagName := strings.Split(jsonTag, ",")[0]
|
|
if tagName == jsonName {
|
|
return columnFromType(typ, field.Name)
|
|
}
|
|
}
|
|
panic(fmt.Sprintf("gormcol: struct %q has no field with json tag %q", typ.Name(), jsonName))
|
|
}
|
|
|
|
func columnFromType(typ reflect.Type, fieldName string) string {
|
|
field, ok := typ.FieldByName(fieldName)
|
|
if !ok {
|
|
panic(fmt.Sprintf("gormcol: struct %q has no field %q", typ.Name(), fieldName))
|
|
}
|
|
|
|
gormTag := field.Tag.Get("gorm")
|
|
if gormTag == "" || gormTag == "-" {
|
|
return NamingStrategy.ColumnName(typ.Name(), fieldName)
|
|
}
|
|
|
|
col := parseGormColumn(gormTag)
|
|
if col != "" {
|
|
return col
|
|
}
|
|
|
|
return NamingStrategy.ColumnName(typ.Name(), fieldName)
|
|
}
|