Skip to content

Commit

Permalink
fix: fix parser model
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkgos committed Mar 18, 2024
1 parent 5b5c476 commit accd556
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 95 deletions.
21 changes: 12 additions & 9 deletions go_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func (t *GoType) Clone() *GoType {
}

// String returns the string representation of a type.
func (t GoType) String() string {
func (t *GoType) String() string {
switch {
case t.Ident != "":
return t.Ident
Expand All @@ -175,37 +175,37 @@ func (t GoType) String() string {
}

// IsNumeric reports if the given type is a numeric type.
func (t GoType) IsNumeric() bool {
func (t *GoType) IsNumeric() bool {
return t.Type.IsNumeric()
}

// IsFloat reports if the given type is a float type.
func (t GoType) IsFloat() bool {
func (t *GoType) IsFloat() bool {
return t.Type.IsFloat()
}

// IsInteger reports if the given type is an integral type.
func (t GoType) IsInteger() bool {
func (t *GoType) IsInteger() bool {
return t.Type.IsInteger()
}

// IsBool reports if the given type is an bool type.
func (t GoType) IsBool() bool {
func (t *GoType) IsBool() bool {
return t.Type.IsBool()
}

// IsTime reports if the given type is an time.Time type.
func (t GoType) IsTime() bool {
func (t *GoType) IsTime() bool {
return t.Type.IsTime()
}

// IsValid reports if the given type if known type.
func (t GoType) IsValid() bool {
func (t *GoType) IsValid() bool {
return t.Type.IsValid()
}

// Comparable reports whether values of this type are comparable.
func (t GoType) Comparable() bool {
func (t *GoType) Comparable() bool {
switch t.Type {
case TypeBool, TypeTime, TypeUUID, TypeEnum, TypeString:
return true
Expand All @@ -220,7 +220,10 @@ func (t GoType) Comparable() bool {
}

func NewGoType(t Type, v any) *GoType {
tt := reflect.TypeOf(v)
return newGoType(t, reflect.TypeOf(v))
}

func newGoType(t Type, tt reflect.Type) *GoType {
tv := indirect(tt)
return &GoType{
Type: t,
Expand Down
128 changes: 67 additions & 61 deletions model_parse.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ens

import (
"database/sql"
"database/sql/driver"
"fmt"
"reflect"
"strings"
Expand All @@ -9,6 +11,9 @@ import (
"gorm.io/gorm/schema"
)

var rowScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
var rowValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()

func ParseModel(v any) (MixinEntity, error) {
value := reflect.ValueOf(v)
if value.Kind() == reflect.Pointer && value.IsNil() {
Expand All @@ -32,112 +37,113 @@ func structToFielders(vt reflect.Type) []Fielder {
fields := make([]Fielder, 0, vt.NumField())
for i := 0; i < vt.NumField(); i++ {
fv := vt.Field(i)
if !fv.IsExported() {
if !fv.IsExported() { // ignore unexported field
continue
}
tag := fv.Tag.Get("gorm")
if tag == "-" { // ignore field
continue
}
// an embedded field
if fv.Anonymous {
if fv.Anonymous { // an embedded field
fvt := fv.Type
for fvt.Kind() == reflect.Ptr {
fvt = fv.Type.Elem()
}
if fvt.Kind() != reflect.Struct {
continue
}
fields = append(fields, structToFielders(fvt)...)
fields = append(
fields,
structToFielders(fvt)...,
)
} else {
fields = append(fields, structFieldToFielder(fv))
t, skip := intoGoTypeType(fv.Type, tag)
if skip {
continue
}
fields = append(
fields,
Field(newGoType(t, fv.Type), utils.SnakeCase(fv.Name)),
)
}
}
return fields
}

func structFieldToFielder(fv reflect.StructField) Fielder {
fvt := fv.Type
nullable := false
for fvt.Kind() == reflect.Ptr {
fvt = fv.Type.Elem()
nullable = true
}

fieldName := utils.SnakeCase(fv.Name)
ident := fvt.String()
return Field(
&GoType{
Type: intoGoTypeType(fvt, fv.Tag),
Ident: ident,
PkgPath: fvt.PkgPath(),
PkgQualifier: PkgQualifier(ident),
Nullable: nullable,
},
fieldName,
)
}

func intoGoTypeType(t reflect.Type, tag reflect.StructTag) Type {
ident := t.String()
switch t.Kind() {
func intoGoTypeType(origTyp reflect.Type, tag string) (t Type, skip bool) {
typ := indirect(origTyp)
switch ident := typ.String(); typ.Kind() {
case reflect.Bool:
return TypeBool
t = TypeBool
case reflect.Int:
return TypeInt
t = TypeInt
case reflect.Int8:
return TypeInt8
t = TypeInt8
case reflect.Int16:
return TypeInt16
t = TypeInt16
case reflect.Int32:
return TypeInt32
t = TypeInt32
case reflect.Int64:
return TypeInt64
t = TypeInt64
case reflect.Uint:
return TypeUint
t = TypeUint
case reflect.Uint8:
return TypeUint8
t = TypeUint8
case reflect.Uint16:
return TypeUint16
t = TypeUint16
case reflect.Uint32:
return TypeUint32
t = TypeUint32
case reflect.Uint64:
return TypeUint64
t = TypeUint64
case reflect.Float32:
return TypeFloat32
t = TypeFloat32
case reflect.Float64:
return TypeFloat64
t = TypeFloat64
case reflect.String:
typeValue := schema.ParseTagSetting(tag.Get("gorm"), ";")["TYPE"]
typeValue := schema.ParseTagSetting(tag, ";")["TYPE"]
if v := strings.ToUpper(typeValue); strings.Contains(v, "DECIMAL") || strings.Contains(v, "NUMERIC") {
return TypeDecimal
t = TypeDecimal
} else {
t = TypeString
}
return TypeString
case reflect.Struct:
switch ident {
case "time.Time", "sql.NullTime", "datatypes.Date":
return TypeTime
case "time.Time",
"sql.NullTime",
"datatypes.Date":
t = TypeTime
case "sql.NullBool":
return TypeBool
t = TypeBool
case "sql.NullByte":
return TypeBytes
t = TypeBytes
case "sql.NullString":
return TypeString
t = TypeString
case "sql.NullFloat64":
return TypeFloat64
t = TypeFloat64
case "sql.NullInt16":
return TypeInt16
t = TypeInt16
case "sql.NullInt32":
return TypeInt32
t = TypeInt32
case "sql.NullInt64":
return TypeInt64
t = TypeInt64
default:
return TypeOther
t = TypeOther
skip = !(reflect.PointerTo(typ).Implements(rowScanner) && typ.Implements(rowValuer))
}
case reflect.Slice:
if ident == "json.RawMessage" || ident == "datatypes.JSON" {
return TypeJSON
switch ident {
case "json.RawMessage", "datatypes.JSON":
t = TypeJSON
case "[]uint8", "[]byte":
t = TypeBytes
default:
skip = true
}
return TypeBytes
case reflect.Array:
return TypeBytes
// TODO: ...
t = TypeBytes
default:
return TypeOther
t = TypeOther
}
return t, skip
}
49 changes: 24 additions & 25 deletions model_parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,40 @@ package ens_test

import (
"database/sql"
"encoding/json"
"time"

"gorm.io/plugin/soft_delete"
)

// TestData 公告-面向所有人的消息
type TestData struct {
Id int64 `gorm:"column:id;not null;autoIncrement:true;primaryKey;comment:主键"`
StrVal string `gorm:"column:str_val;type:varchar(255);not null"`
StrNullVal1 sql.NullString `gorm:"column:str_null_val1;type:varchar(2048);null"`
StrNullVal2 *string `gorm:"column:str_null_val2;type:varchar(2048);null"`
Value1 float64 `gorm:"column:value1;type:double;not null;default:'';uniqueIndex:uk_key_value,priority:1"`
Value2 *float64 `gorm:"column:value2;type:double;null;default:'';uniqueIndex:uk_key_value,priority:1"`
Priority uint `gorm:"column:priority;type:unsigned int(10) unsigned;not null;default:255"`
Visible bool `gorm:"column:visible;type:tinyint(1) unsigned;not null;default:0"`
Time1 time.Time `gorm:"column:time1;type:datetime;not null"`
Time2 *time.Time `gorm:"column:time2;type:datetime;null"`
Time3 sql.NullTime `gorm:"column:time3;type:datetime;null"`
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:bigint(20);not null;default:0"`
}

type Model struct {
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt soft_delete.DeletedAt `gorm:"index"`
type Anonymous struct {
AnonymousField int
}

type TestData1 struct {
Model
type TestData struct {
Id int64 `gorm:"column:id;not null;autoIncrement:true;primaryKey;comment:主键"`
StrVal string `gorm:"column:str_val;type:varchar(255);not null"`
StrNullVal1 sql.NullString `gorm:"column:str_null_val1;type:varchar(2048);null"`
StrNullVal2 *string `gorm:"column:str_null_val2;type:varchar(2048);null"`
Value1 float64 `gorm:"column:value1;type:double;not null;default:'';uniqueIndex:uk_key_value,priority:1"`
Value2 *float64 `gorm:"column:value2;type:double;null;default:'';uniqueIndex:uk_key_value,priority:1"`
Priority uint `gorm:"column:priority;type:unsigned int(10) unsigned;not null;default:255"`
Visible bool `gorm:"column:visible;type:tinyint(1) unsigned;not null;default:0"`
Time1 time.Time `gorm:"column:time1;type:datetime;not null"`
Time2 *time.Time `gorm:"column:time2;type:datetime;null"`
Time3 sql.NullTime `gorm:"column:time3;type:datetime;null"`
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:bigint(20);not null;default:0"`
Js json.RawMessage
Bs []byte
unexported int
OmitField int `gorm:"-"`
Unsupported []time.Time
NotImplScanerAndValuer Anonymous
Anonymous
}

// func Test(t *testing.T) {
// v := TestData1{}
// entity, _ := ens.ParseModel(v)
// entity, _ := ens.ParseModel(TestData{})
// des := entity.Build(nil)
// g := codegen.
// New(
Expand Down

0 comments on commit accd556

Please sign in to comment.