diff --git a/contracts/database/orm/constants.go b/contracts/database/orm/constants.go index 29b9fe684..371f144f6 100644 --- a/contracts/database/orm/constants.go +++ b/contracts/database/orm/constants.go @@ -1,8 +1,10 @@ package orm const ( - DriverMysql Driver = "mysql" + DriverMysql Driver = "mysql" + // DriverPostgresql DEPRECATED, use DriverPostgres instead. DriverPostgresql Driver = "postgresql" + DriverPostgres Driver = "postgres" DriverSqlite Driver = "sqlite" DriverSqlserver Driver = "sqlserver" ) diff --git a/contracts/database/orm/orm.go b/contracts/database/orm/orm.go index 12e580a44..19364f9a2 100644 --- a/contracts/database/orm/orm.go +++ b/contracts/database/orm/orm.go @@ -74,6 +74,8 @@ type Query interface { Group(name string) Query // Having specifying HAVING conditions for the query. Having(query any, args ...any) Query + // InRandomOrder specifies the order randomly. + InRandomOrder() Query // Join specifying JOIN conditions for the query. Join(query string, args ...any) Query // Limit the number of records returned. diff --git a/database/gorm/query.go b/database/gorm/query.go index 2596909c3..659b22736 100644 --- a/database/gorm/query.go +++ b/database/gorm/query.go @@ -465,6 +465,21 @@ func (r *QueryImpl) OrderByDesc(column string) ormcontract.Query { return r.Order(fmt.Sprintf("%s DESC", column)) } +func (r *QueryImpl) InRandomOrder() ormcontract.Query { + order := "" + switch r.Driver() { + case ormcontract.DriverMysql: + order = "RAND()" + case ormcontract.DriverSqlserver: + order = "NEWID()" + case ormcontract.DriverPostgres: + order = "RANDOM()" + case ormcontract.DriverSqlite: + order = "RANDOM()" + } + return r.Order(order) +} + func (r *QueryImpl) OrWhere(query any, args ...any) ormcontract.Query { tx := r.instance.Or(query, args...) diff --git a/database/gorm/query_test.go b/database/gorm/query_test.go index 58347393e..835a1420a 100644 --- a/database/gorm/query_test.go +++ b/database/gorm/query_test.go @@ -1997,6 +1997,28 @@ func (s *QueryTestSuite) TestOrderByDesc() { } } +func (s *QueryTestSuite) TestInRandomOrder() { + for driver, query := range s.queries { + s.Run(driver.String(), func() { + for i := 0; i < 30; i++ { + user := User{Name: "random_order_user", Avatar: "random_order_avatar"} + s.Nil(query.Create(&user)) + s.True(user.ID > 0) + } + + var users1 []User + s.Nil(query.Where("name = ?", "random_order_user").InRandomOrder().Find(&users1)) + s.True(len(users1) == 30) + + var users2 []User + s.Nil(query.Where("name = ?", "random_order_user").InRandomOrder().Find(&users2)) + s.True(len(users2) == 30) + + s.True(users1[0].ID != users2[0].ID || users1[14].ID != users2[14].ID || users1[29].ID != users2[29].ID) + }) + } +} + func (s *QueryTestSuite) TestPaginate() { for driver, query := range s.queries { s.Run(driver.String(), func() { diff --git a/mocks/database/orm/Query.go b/mocks/database/orm/Query.go index fae5f08d4..15f5d378d 100644 --- a/mocks/database/orm/Query.go +++ b/mocks/database/orm/Query.go @@ -386,6 +386,22 @@ func (_m *Query) Having(query interface{}, args ...interface{}) orm.Query { return r0 } +// InRandomOrder provides a mock function with given fields: +func (_m *Query) InRandomOrder() orm.Query { + ret := _m.Called() + + var r0 orm.Query + if rf, ok := ret.Get(0).(func() orm.Query); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(orm.Query) + } + } + + return r0 +} + // Join provides a mock function with given fields: query, args func (_m *Query) Join(query string, args ...interface{}) orm.Query { var _ca []interface{} diff --git a/mocks/database/orm/Transaction.go b/mocks/database/orm/Transaction.go index 548411f5e..a62c64e8a 100644 --- a/mocks/database/orm/Transaction.go +++ b/mocks/database/orm/Transaction.go @@ -400,6 +400,22 @@ func (_m *Transaction) Having(query interface{}, args ...interface{}) orm.Query return r0 } +// InRandomOrder provides a mock function with given fields: +func (_m *Transaction) InRandomOrder() orm.Query { + ret := _m.Called() + + var r0 orm.Query + if rf, ok := ret.Get(0).(func() orm.Query); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(orm.Query) + } + } + + return r0 +} + // Join provides a mock function with given fields: query, args func (_m *Transaction) Join(query string, args ...interface{}) orm.Query { var _ca []interface{}