Skip to content
Open
12 changes: 12 additions & 0 deletions contrib/drivers/mysql/mysql_z_unit_feature_model_struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,17 @@ type User struct {
Password string
Nickname string
CreateTime *gtime.Time
CreateDate *gtime.Time
}

type DoUser struct {
g.Meta `orm:"table:user, do:true"`
Id any
Passport any
Password any
Nickname any
CreateTime *gtime.Time
CreateDate *gtime.Time
}

func (user *User) UnmarshalValue(value any) error {
Expand All @@ -406,6 +417,7 @@ func (user *User) UnmarshalValue(value any) error {
Password: "",
Nickname: record["nickname"].String(),
CreateTime: record["create_time"].GTime(),
CreateDate: record["create_date"].GTime(),
}
return nil
}
Expand Down
4 changes: 3 additions & 1 deletion contrib/drivers/mysql/mysql_z_unit_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
TestDbUser = "root"
TestDbPass = "12345678"
CreateTime = "2018-10-24 10:00:00"
CreateDate = "2018-10-24"
)

var (
Expand Down Expand Up @@ -154,7 +155,8 @@ func createInitTableWithDb(db gdb.DB, table ...string) (name string) {
"passport": fmt.Sprintf(`user_%d`, i),
"password": fmt.Sprintf(`pass_%d`, i),
"nickname": fmt.Sprintf(`name_%d`, i),
"create_time": gtime.NewFromStr(CreateTime).String(),
"create_time": CreateTime,
"create_date": CreateDate,
})
}

Expand Down
45 changes: 45 additions & 0 deletions contrib/drivers/mysql/mysql_z_unit_pr_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). 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 mysql_test

import (
"testing"
"time"

"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/test/gtest"
)

// PR #4360 WhereCondDateType
func Test_WhereCondDateType_PR4360(t *testing.T) {
tableName := "WhereCondDateType_tables"
createInitTable(tableName)
defer dropTable(tableName)
gtest.C(t, func(t *gtest.T) {
var user *User
var err error
err = db.Model(tableName).Where(DoUser{CreateDate: gtime.New(CreateDate).Add(time.Hour*11 + time.Minute*22 + time.Second*33)}).Scan(&user)
t.AssertNil(err)
t.AssertNQ(user, nil)
user = nil
err = db.Model(tableName).Where(DoUser{CreateDate: gtime.New(CreateDate)}).Scan(&user)
t.AssertNil(err)
t.AssertNQ(user, nil)
t.AssertNQ(user.CreateDate, nil)
y1, m1, d1 := gtime.New(CreateDate).Date()
y2, m2, d2 := user.CreateDate.Date()
t.AssertEQ(y1, y2)
t.AssertEQ(m1, m2)
t.AssertEQ(d1, d2)
h := user.CreateDate.Hour()
m := user.CreateDate.Minute()
s := user.CreateDate.Second()
t.AssertEQ(h, 0)
t.AssertEQ(m, 0)
t.AssertEQ(s, 0)
})
}
61 changes: 37 additions & 24 deletions database/gdb/gdb_core_structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,43 @@ import (

// GetFieldTypeStr retrieves and returns the field type string for certain field by name.
func (c *Core) GetFieldTypeStr(ctx context.Context, fieldName, table, schema string) string {
field := c.GetFieldType(ctx, fieldName, table, schema)
if field != nil {
// Kinds of data type examples:
// year(4)
// datetime
// varchar(64)
// bigint(20)
// int(10) unsigned
typeName := gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int
if typeName != "" {
typeName = gstr.Trim(typeName)
} else {
typeName = field.Type
}
return typeName
}
return ""
fieldStrMap := c.GetFieldTypeStrMap(ctx, table, schema)
return fieldStrMap[fieldName]
}

// GetFieldType retrieves and returns the field type object for certain field by name.
func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string) *TableField {
fieldsMap := c.GetFieldTypeMap(ctx, table, schema)
return fieldsMap[fieldName]
}

// GetFieldTypeStrMap retrieves and returns the field type string map.
func (c *Core) GetFieldTypeStrMap(ctx context.Context, table, schema string) map[string]string {
fieldMap := c.GetFieldTypeMap(ctx, table, schema)
fieldStrMap := make(map[string]string, len(fieldMap))
for fieldName, field := range fieldMap {
typeName := ""
if field != nil {
// Kinds of data type examples:
// year(4)
// datetime
// varchar(64)
// bigint(20)
// int(10) unsigned
typeName = gstr.StrTillEx(field.Type, "(") // int(10) unsigned -> int
if typeName != "" {
typeName = gstr.Trim(typeName)
} else {
typeName = field.Type
}
}
fieldStrMap[fieldName] = typeName
}
return fieldStrMap
}

// GetFieldTypeMap retrieves and returns the field type object map.
func (c *Core) GetFieldTypeMap(ctx context.Context, table, schema string) map[string]*TableField {
fieldsMap, err := c.db.TableFields(ctx, table, schema)
if err != nil {
intlog.Errorf(
Expand All @@ -57,12 +73,7 @@ func (c *Core) GetFieldType(ctx context.Context, fieldName, table, schema string
)
return nil
}
for tableFieldName, tableField := range fieldsMap {
if tableFieldName == fieldName {
return tableField
}
}
return nil
return fieldsMap
}

// ConvertDataForRecord is a very important function, which does converting for any data that
Expand All @@ -75,8 +86,10 @@ func (c *Core) ConvertDataForRecord(ctx context.Context, value any, table string
err error
data = MapOrStructToMapDeep(value, true)
)

fieldTypeMap := c.GetFieldTypeStrMap(ctx, table, c.GetSchema())
for fieldName, fieldValue := range data {
var fieldType = c.GetFieldTypeStr(ctx, fieldName, table, c.GetSchema())
fieldType := fieldTypeMap[fieldName]
data[fieldName], err = c.db.ConvertValueForField(
ctx,
fieldType,
Expand Down
19 changes: 19 additions & 0 deletions database/gdb/gdb_func.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,25 @@ func formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (n
// Mapping and filtering fields if `Table` is given.
if in.Table != "" {
data, _ = db.GetCore().mappingAndFilterData(ctx, in.Schema, in.Table, data, true)
// Convert field values to types supported by table records (e.g., time to string)
fieldTypeMap := db.GetCore().GetFieldTypeStrMap(ctx, in.Table, in.Schema)
for fieldName, fieldValue := range data {
switch fieldValue.(type) {
case time.Time, *time.Time, gtime.Time, *gtime.Time:
fieldType := fieldTypeMap[fieldName]
convFieldValue, err := db.GetCore().ConvertValueForField(
ctx,
fieldType,
fieldValue,
)
if err != nil || convFieldValue == nil {
continue
}
data[fieldName] = convFieldValue
default:
continue
}
}
}
// Put the struct attributes in sequence in Where statement.
var ormTagValue string
Expand Down
Loading