diff --git a/contrib/drivers/mysql/mysql_z_unit_issue_test.go b/contrib/drivers/mysql/mysql_z_unit_issue_test.go index 072fe1b9386..e30bc1733c5 100644 --- a/contrib/drivers/mysql/mysql_z_unit_issue_test.go +++ b/contrib/drivers/mysql/mysql_z_unit_issue_test.go @@ -431,6 +431,45 @@ func Test_Issue1733(t *testing.T) { }) } +// https://github.com/gogf/gf/issues/2012 +func Test_Issue2012(t *testing.T) { + table := "time_only_" + guid.S() + if _, err := db.Exec(ctx, fmt.Sprintf(` + CREATE TABLE %s( + id int(8) unsigned zerofill NOT NULL AUTO_INCREMENT, + time_only time, + PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + `, table, + )); err != nil { + gtest.AssertNil(err) + } + defer dropTable(table) + + type TimeOnly struct { + Id int `json:"id"` + TimeOnly *gtime.Time `json:"timeOnly"` + } + + gtest.C(t, func(t *gtest.T) { + timeOnly := gtime.New("15:04:05") + m := db.Model(table) + + _, err := m.Insert(TimeOnly{ + TimeOnly: gtime.New(timeOnly), + }) + t.AssertNil(err) + + _, err = m.Insert(g.Map{ + "time_only": timeOnly, + }) + t.AssertNil(err) + + _, err = m.Insert("time_only", timeOnly) + t.AssertNil(err) + }) +} + // https://github.com/gogf/gf/issues/2105 func Test_Issue2105(t *testing.T) { table := "issue2105" @@ -1160,3 +1199,20 @@ func Test_Issue3238(t *testing.T) { } }) } + +// https://github.com/gogf/gf/issues/3649 +func Test_Issue3649(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + sql, err := gdb.CatchSQL(context.Background(), func(ctx context.Context) (err error) { + user := db.Model(table).Ctx(ctx) + _, err = user.Where("create_time = ?", gdb.Raw("now()")).WhereLT("create_time", gdb.Raw("now()")).Count() + return + }) + t.AssertNil(err) + sqlStr := fmt.Sprintf("SELECT COUNT(1) FROM `%s` WHERE (create_time = now()) AND (`create_time` < now())", table) + t.Assert(sql[0], sqlStr) + }) +} diff --git a/contrib/registry/file/file_discovery.go b/contrib/registry/file/file_discovery.go index 36065cc118e..5fd21a7418e 100644 --- a/contrib/registry/file/file_discovery.go +++ b/contrib/registry/file/file_discovery.go @@ -10,6 +10,7 @@ import ( "context" "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gtype" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/gsvc" "github.com/gogf/gf/v2/os/gfile" @@ -55,8 +56,12 @@ func (r *Registry) Watch(ctx context.Context, key string) (watcher gsvc.Watcher, prefix: key, discovery: r, ch: make(chan gsvc.Service, 100), + closed: gtype.NewBool(false), } _, err = gfsnotify.Add(r.path, func(event *gfsnotify.Event) { + if fileWatcher.closed.Val() { + return + } if event.IsChmod() { return } diff --git a/contrib/registry/file/file_watcher.go b/contrib/registry/file/file_watcher.go index fa060ef0a0b..b10e74304a2 100644 --- a/contrib/registry/file/file_watcher.go +++ b/contrib/registry/file/file_watcher.go @@ -9,6 +9,8 @@ package file import ( "context" + "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/net/gsvc" ) @@ -17,11 +19,15 @@ type Watcher struct { prefix string // Watched prefix key, not file name prefix. discovery gsvc.Discovery // Service discovery. ch chan gsvc.Service // Changes that caused by inotify. + closed *gtype.Bool // Whether the channel has been closed } // Proceed proceeds watch in blocking way. // It returns all complete services that watched by `key` if any change. func (w *Watcher) Proceed() (services []gsvc.Service, err error) { + if w.closed.Val() { + return nil, gerror.New("discovery service was closed") + } <-w.ch return w.discovery.Search(context.Background(), gsvc.SearchInput{ Prefix: w.prefix, @@ -30,6 +36,8 @@ func (w *Watcher) Proceed() (services []gsvc.Service, err error) { // Close closes the watcher. func (w *Watcher) Close() error { - close(w.ch) + if w.closed.Cas(false, true) { + close(w.ch) + } return nil } diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index 38e0d5b4c9f..9064f4a2ed9 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -777,11 +777,7 @@ func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) { } else { in.Buffer.WriteString(quotedKey) } - if s, ok := in.Value.(Raw); ok { - in.Buffer.WriteString(gconv.String(s)) - } else { - in.Args = append(in.Args, in.Value) - } + in.Args = append(in.Args, in.Value) } } return in.Args diff --git a/os/gtime/gtime_sql.go b/os/gtime/gtime_sql.go index e3c79a81b1b..4fdd4902b12 100644 --- a/os/gtime/gtime_sql.go +++ b/os/gtime/gtime_sql.go @@ -24,5 +24,11 @@ func (t *Time) Value() (driver.Value, error) { if t.IsZero() { return nil, nil } + + if t.Year() == 0 { + // Only time. + return t.Format("15:04:05"), nil + } + return t.Time, nil } diff --git a/os/gtime/gtime_z_example_time_test.go b/os/gtime/gtime_z_example_time_test.go index 84a42dda721..439b8ff3536 100644 --- a/os/gtime/gtime_z_example_time_test.go +++ b/os/gtime/gtime_z_example_time_test.go @@ -23,12 +23,14 @@ func ExampleNew_Basic() { t3 := gtime.New(curTime, "Y-m-d H:i:s") t4 := gtime.New(curTime) t5 := gtime.New(1533686888) + t6 := gtime.New("08:08:08") fmt.Println(t1) fmt.Println(t2) fmt.Println(t3) fmt.Println(t4) fmt.Println(t5) + fmt.Println(t6) // Output: // 2018-08-08 08:08:08 @@ -36,6 +38,7 @@ func ExampleNew_Basic() { // 2018-08-08 08:08:08 // 2018-08-08 08:08:08 // 2018-08-08 08:08:08 + // 08:08:08 } func ExampleNew_WithFormat() { @@ -68,12 +71,15 @@ func ExampleNewFromTime() { // NewFromStr creates and returns a Time object with given string. // Note that it returns nil if there's error occurs. func ExampleNewFromStr() { - t := gtime.NewFromStr("2018-08-08 08:08:08") + t1 := gtime.NewFromStr("2018-08-08 08:08:08") + t2 := gtime.NewFromStr("08:08:08") - fmt.Println(t) + fmt.Println(t1) + fmt.Println(t2) // Output: // 2018-08-08 08:08:08 + // 08:08:08 } // NewFromStrFormat creates and returns a Time object with given string and @@ -189,26 +195,38 @@ func ExampleTime_Second() { // String returns current time object as string. func ExampleTime_String() { - gt := gtime.New("2018-08-08 08:08:08") - t1 := gt.String() + gt1 := gtime.New("2018-08-08 08:08:08") + t1 := gt1.String() + gt2 := gtime.New("08:08:08") fmt.Println(t1) fmt.Println(reflect.TypeOf(t1)) + fmt.Println(gt2) // Output: // 2018-08-08 08:08:08 // string + // 08:08:08 } // IsZero reports whether t represents the zero time instant, // January 1, year 1, 00:00:00 UTC. func ExampleTime_IsZero() { - gt := gtime.New("2018-08-08 08:08:08") + gt1 := gtime.New("2018-08-08 08:08:08") + gt2 := gtime.New("00:00:00") + timer, _ := time.Parse("15:04:05", "00:00:00") + gt3 := gtime.NewFromTime(timer) - fmt.Println(gt.IsZero()) + fmt.Println(gt1.IsZero()) + fmt.Println(gt2.IsZero()) + fmt.Println(timer.IsZero()) // stdlib is also false + fmt.Println(gt3.IsZero()) // Output: // false + // false + // false + // false } // Add adds the duration to current time.