forked from mirror/gorm
Add tests model definition and basic fields tests
This commit is contained in:
parent
fd9b688084
commit
14724ddeae
|
@ -22,7 +22,7 @@ var (
|
|||
// gorm.Model
|
||||
// }
|
||||
type Model struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
ID uint `gorm:"primarykey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt *time.Time `gorm:"index"`
|
||||
|
|
|
@ -54,7 +54,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||
Creatable: true,
|
||||
Updatable: true,
|
||||
Tag: fieldStruct.Tag,
|
||||
TagSettings: parseTagSetting(fieldStruct.Tag),
|
||||
TagSettings: ParseTagSetting(fieldStruct.Tag),
|
||||
}
|
||||
|
||||
for field.FieldType.Kind() == reflect.Ptr {
|
||||
|
@ -84,7 +84,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||
}
|
||||
|
||||
// copy tag settings from valuer
|
||||
for key, value := range parseTagSetting(field.FieldType.Field(i).Tag) {
|
||||
for key, value := range ParseTagSetting(field.FieldType.Field(i).Tag) {
|
||||
if _, ok := field.TagSettings[key]; !ok {
|
||||
field.TagSettings[key] = value
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||
field.DBDataType = val
|
||||
}
|
||||
|
||||
switch fieldValue.Kind() {
|
||||
switch fieldValue.Elem().Kind() {
|
||||
case reflect.Bool:
|
||||
field.DataType = Bool
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
|
@ -153,7 +153,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||
case reflect.String:
|
||||
field.DataType = String
|
||||
case reflect.Struct:
|
||||
if _, ok := fieldValue.Interface().(time.Time); ok {
|
||||
if _, ok := fieldValue.Interface().(*time.Time); ok {
|
||||
field.DataType = Time
|
||||
}
|
||||
case reflect.Array, reflect.Slice:
|
||||
|
@ -176,7 +176,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||
}
|
||||
|
||||
if _, ok := field.TagSettings["EMBEDDED"]; ok || fieldStruct.Anonymous {
|
||||
field.EmbeddedSchema, schema.err = Parse(fieldValue, sync.Map{}, schema.namer)
|
||||
field.EmbeddedSchema, schema.err = Parse(fieldValue.Interface(), &sync.Map{}, schema.namer)
|
||||
for _, ef := range field.EmbeddedSchema.Fields {
|
||||
ef.BindNames = append([]string{fieldStruct.Name}, ef.BindNames...)
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/jinzhu/gorm/logger"
|
||||
)
|
||||
|
||||
type Schema struct {
|
||||
|
@ -20,7 +22,7 @@ type Schema struct {
|
|||
Relationships Relationships
|
||||
err error
|
||||
namer Namer
|
||||
cacheStore sync.Map
|
||||
cacheStore *sync.Map
|
||||
}
|
||||
|
||||
func (schema Schema) String() string {
|
||||
|
@ -38,7 +40,7 @@ func (schema Schema) LookUpField(name string) *Field {
|
|||
}
|
||||
|
||||
// get data type from dialector
|
||||
func Parse(dest interface{}, cacheStore sync.Map, namer Namer) (*Schema, error) {
|
||||
func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) {
|
||||
modelType := reflect.ValueOf(dest).Type()
|
||||
for modelType.Kind() == reflect.Slice || modelType.Kind() == reflect.Ptr {
|
||||
modelType = modelType.Elem()
|
||||
|
@ -62,10 +64,12 @@ func Parse(dest interface{}, cacheStore sync.Map, namer Namer) (*Schema, error)
|
|||
FieldsByName: map[string]*Field{},
|
||||
FieldsByDBName: map[string]*Field{},
|
||||
cacheStore: cacheStore,
|
||||
namer: namer,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if schema.err != nil {
|
||||
logger.Default.Error(schema.err.Error())
|
||||
cacheStore.Delete(modelType)
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package schema_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/jinzhu/gorm/schema"
|
||||
"github.com/jinzhu/gorm/tests"
|
||||
)
|
||||
|
||||
func TestParseSchema(t *testing.T) {
|
||||
cacheMap := sync.Map{}
|
||||
user, err := schema.Parse(&tests.User{}, &cacheMap, schema.NamingStrategy{})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse user, got error %v", err)
|
||||
}
|
||||
|
||||
checkSchemaFields(t, user)
|
||||
}
|
||||
|
||||
func checkSchemaFields(t *testing.T, s *schema.Schema) {
|
||||
fields := []schema.Field{
|
||||
schema.Field{
|
||||
Name: "ID", DBName: "id", BindNames: []string{"Model", "ID"}, DataType: schema.Uint,
|
||||
PrimaryKey: true, Tag: `gorm:"primarykey"`, TagSettings: map[string]string{"PRIMARYKEY": "PRIMARYKEY"},
|
||||
},
|
||||
schema.Field{Name: "CreatedAt", DBName: "created_at", BindNames: []string{"Model", "CreatedAt"}, DataType: schema.Time},
|
||||
schema.Field{Name: "UpdatedAt", DBName: "updated_at", BindNames: []string{"Model", "UpdatedAt"}, DataType: schema.Time},
|
||||
schema.Field{Name: "DeletedAt", DBName: "deleted_at", BindNames: []string{"Model", "DeletedAt"}, Tag: `gorm:"index"`, DataType: schema.Time},
|
||||
schema.Field{Name: "Name", DBName: "name", BindNames: []string{"Name"}, DataType: schema.String},
|
||||
schema.Field{Name: "Age", DBName: "age", BindNames: []string{"Age"}, DataType: schema.Uint},
|
||||
schema.Field{Name: "Birthday", DBName: "birthday", BindNames: []string{"Birthday"}, DataType: schema.Time},
|
||||
schema.Field{Name: "CompanyID", DBName: "company_id", BindNames: []string{"CompanyID"}, DataType: schema.Int},
|
||||
schema.Field{Name: "ManagerID", DBName: "manager_id", BindNames: []string{"ManagerID"}, DataType: schema.Uint},
|
||||
}
|
||||
|
||||
for _, f := range fields {
|
||||
f.Creatable = true
|
||||
f.Updatable = true
|
||||
if f.TagSettings == nil {
|
||||
if f.Tag != "" {
|
||||
f.TagSettings = schema.ParseTagSetting(f.Tag)
|
||||
} else {
|
||||
f.TagSettings = map[string]string{}
|
||||
}
|
||||
}
|
||||
|
||||
if foundField, ok := s.FieldsByName[f.Name]; !ok {
|
||||
t.Errorf("schema %v failed to look up field with name %v", s, f.Name)
|
||||
} else {
|
||||
checkSchemaField(t, foundField, f)
|
||||
|
||||
if field, ok := s.FieldsByDBName[f.DBName]; !ok || foundField != field {
|
||||
t.Errorf("schema %v failed to look up field with dbname %v", s, f.DBName)
|
||||
}
|
||||
|
||||
for _, name := range []string{f.DBName, f.Name} {
|
||||
if field := s.LookUpField(name); field == nil || foundField != field {
|
||||
t.Errorf("schema %v failed to look up field with dbname %v", s, f.DBName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkSchemaField(t *testing.T, parsedField *schema.Field, field schema.Field) {
|
||||
equalFieldNames := []string{"Name", "DBName", "BindNames", "DataType", "DBDataType", "PrimaryKey", "AutoIncrement", "Creatable", "Updatable", "HasDefaultValue", "DefaultValue", "NotNull", "Unique", "Comment", "Size", "Precision", "Tag", "TagSettings"}
|
||||
|
||||
for _, name := range equalFieldNames {
|
||||
got := reflect.ValueOf(parsedField).Elem().FieldByName(name).Interface()
|
||||
expects := reflect.ValueOf(field).FieldByName(name).Interface()
|
||||
if !reflect.DeepEqual(got, expects) {
|
||||
t.Errorf("%v is not equal, expects: %v, got %v", name, expects, got)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func parseTagSetting(tags reflect.StructTag) map[string]string {
|
||||
func ParseTagSetting(tags reflect.StructTag) map[string]string {
|
||||
setting := map[string]string{}
|
||||
|
||||
for _, value := range strings.Split(tags.Get("gorm"), ";") {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package gorm_test
|
||||
package tests_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// User has one `Account` (has one), many `Pets` (has many) and `Toys` (has many - polymorphic)
|
||||
// He works in a Company (belongs to), he has a Manager (belongs to - single-table), and also managed a Team (has many - single-table)
|
||||
// He speaks many languages (many to many) and has many friends (many to many - single-table)
|
||||
// His pet also has one Toy (has one - polymorphic)
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
Age uint
|
||||
Birthday *time.Time
|
||||
Account Account
|
||||
Pets []*Pet
|
||||
Toys []Toy `gorm:"polymorphic:Owner"`
|
||||
CompanyID *int
|
||||
Company Company
|
||||
ManagerID uint
|
||||
Manager *User
|
||||
Team []User `foreignkey:ManagerID`
|
||||
Friends []*User `gorm:"many2many:user_friends"`
|
||||
Languages []Language `gorm:"many2many:user_speaks"`
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
gorm.Model
|
||||
UserID sql.NullInt64
|
||||
Number string
|
||||
}
|
||||
|
||||
type Pet struct {
|
||||
gorm.Model
|
||||
UserID uint
|
||||
Name string
|
||||
Toy Toy `gorm:"polymorphic:Owner;"`
|
||||
}
|
||||
|
||||
type Toy struct {
|
||||
gorm.Model
|
||||
OwnerID string
|
||||
OwnerType string
|
||||
}
|
||||
|
||||
type Company struct {
|
||||
ID uint
|
||||
Name string
|
||||
}
|
||||
|
||||
type Language struct {
|
||||
Code string `gorm:primarykey`
|
||||
Name string
|
||||
}
|
Loading…
Reference in New Issue