134 lines
2.9 KiB
Go
134 lines
2.9 KiB
Go
package orm
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"reflect"
|
|
"time"
|
|
)
|
|
|
|
type Field struct {
|
|
Name string
|
|
ColumnName string
|
|
ColumnType string
|
|
Type reflect.Type
|
|
Original reflect.StructField
|
|
Model *Model
|
|
Index int
|
|
AutoIncrement bool
|
|
PrimaryKey bool
|
|
Nullable bool
|
|
isForeignKey bool
|
|
fk *Relationship
|
|
}
|
|
|
|
func (f *Field) alias() (string, string) {
|
|
columnName := f.Model.Fields[f.Model.IDField].ColumnName
|
|
if f.ColumnType != "" {
|
|
columnName = f.ColumnName
|
|
}
|
|
return fmt.Sprintf("%s.%s", f.Model.TableName, columnName), fmt.Sprintf("%s_%s", f.Model.TableName, f.ColumnName)
|
|
}
|
|
|
|
func (f *Field) aliasWith(a string) (string, string) {
|
|
first := fmt.Sprintf("%s.%s", a, f.ColumnName)
|
|
second := fmt.Sprintf("%s_%s", a, f.ColumnName)
|
|
return first, second
|
|
}
|
|
|
|
func (f *Field) key() string {
|
|
return fmt.Sprintf("%s.%s", f.Model.Name, f.Name)
|
|
}
|
|
|
|
func columnType(ty reflect.Type, isPk, isAutoInc bool) string {
|
|
it := ty
|
|
switch it.Kind() {
|
|
case reflect.Ptr:
|
|
for it.Kind() == reflect.Ptr {
|
|
it = it.Elem()
|
|
}
|
|
case reflect.Int32, reflect.Uint32:
|
|
if isPk || isAutoInc {
|
|
return "serial"
|
|
} else {
|
|
return "int"
|
|
}
|
|
case reflect.Int64, reflect.Uint64, reflect.Int, reflect.Uint:
|
|
if isPk || isAutoInc {
|
|
return "bigserial"
|
|
} else {
|
|
return "bigint"
|
|
}
|
|
case reflect.String:
|
|
return "text"
|
|
case reflect.Float32:
|
|
return "float4"
|
|
case reflect.Float64:
|
|
return "double precision"
|
|
case reflect.Bool:
|
|
return "boolean"
|
|
case reflect.Struct:
|
|
if canConvertTo[time.Time](ty) {
|
|
return "timestamptz"
|
|
}
|
|
if canConvertTo[net.IP](ty) {
|
|
return "inet"
|
|
}
|
|
if canConvertTo[net.IPNet](ty) {
|
|
return "cidr"
|
|
}
|
|
|
|
default:
|
|
return ""
|
|
}
|
|
return ""
|
|
}
|
|
func parseField(f reflect.StructField, minfo *Model, modelMap map[string]*Model, i int) *Field {
|
|
field := &Field{
|
|
Name: f.Name,
|
|
Original: f,
|
|
Index: i,
|
|
}
|
|
tags := parseTags(f.Tag.Get("d"))
|
|
if tags["-"] != "" {
|
|
return nil
|
|
}
|
|
field.PrimaryKey = tags["pk"] != "" || tags["primarykey"] != "" || field.Name == "ID"
|
|
field.AutoIncrement = tags["autoinc"] != ""
|
|
field.Nullable = tags["nullable"] != ""
|
|
field.ColumnType = tags["type"]
|
|
if field.ColumnType == "" {
|
|
field.ColumnType = columnType(f.Type, field.PrimaryKey, field.AutoIncrement)
|
|
}
|
|
field.ColumnName = tags["column"]
|
|
if field.ColumnName == "" {
|
|
field.ColumnName = pascalToSnakeCase(field.Name)
|
|
}
|
|
if field.PrimaryKey {
|
|
minfo.IDField = field.Name
|
|
}
|
|
elem := f.Type
|
|
for elem.Kind() == reflect.Ptr {
|
|
if !field.Nullable {
|
|
field.Nullable = true
|
|
}
|
|
elem = elem.Elem()
|
|
}
|
|
field.Type = elem
|
|
|
|
switch elem.Kind() {
|
|
case reflect.Array, reflect.Slice:
|
|
elem = elem.Elem()
|
|
fallthrough
|
|
case reflect.Struct:
|
|
if canConvertTo[Document](elem) && f.Anonymous {
|
|
minfo.TableName = tags["table"]
|
|
return nil
|
|
} else if field.ColumnType == "" {
|
|
minfo.Relationships[field.Name] = parseRelationship(f, modelMap, minfo.Type, i)
|
|
}
|
|
}
|
|
|
|
return field
|
|
}
|