From 075773330ddc30c8def5a09cab88b3f223cd1285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 09:35:28 +0800 Subject: [PATCH 01/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- go.mod | 2 + go.sum | 3 ++ gorm/scope/funcs.go | 10 +++++ gorm/scope/scope.go | 91 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 gorm/scope/funcs.go create mode 100644 gorm/scope/scope.go diff --git a/go.mod b/go.mod index 0e052bcd..c4dc4db7 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,8 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/gorilla/mux v1.8.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/go.sum b/go.sum index dc7c25fc..e44c9dca 100644 --- a/go.sum +++ b/go.sum @@ -57,7 +57,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= diff --git a/gorm/scope/funcs.go b/gorm/scope/funcs.go new file mode 100644 index 00000000..2d16e72c --- /dev/null +++ b/gorm/scope/funcs.go @@ -0,0 +1,10 @@ +package scope + +// +// func When(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { +// return New().When(condition, f) +// } +// +// func Unless(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { +// return New().Unless(condition, f) +// } diff --git a/gorm/scope/scope.go b/gorm/scope/scope.go new file mode 100644 index 00000000..7136e5e4 --- /dev/null +++ b/gorm/scope/scope.go @@ -0,0 +1,91 @@ +package scope + +import "gorm.io/gorm" + +type Scopes []func(*gorm.DB) *gorm.DB + +func New() *Scopes { + return &Scopes{} +} + +func When(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { + return New().When(condition, f) +} + +func Unless(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { + return New().Unless(condition, f) +} + +func Between(field string, start, end interface{}) *Scopes { + return New().Between(field, start, end) +} + +func NotBetween(field string, start, end interface{}) *Scopes { + return New().NotBetween(field, start, end) +} + +func (s *Scopes) Apply(db *gorm.DB) *gorm.DB { + return db.Scopes(*s...) +} + +func (s *Scopes) Scope() func(*gorm.DB) *gorm.DB { + return func(db *gorm.DB) *gorm.DB { + return s.Apply(db) + } +} + +func (s *Scopes) Scopes() []func(*gorm.DB) *gorm.DB { + return *s +} + +func (s *Scopes) Add(scopes ...func(*gorm.DB) *gorm.DB) *Scopes { + *s = append(*s, scopes...) + return s +} + +func (s *Scopes) When(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { + if condition { + return s.Add(fc) + } + return s +} + +func (s *Scopes) Unless(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { + return s.When(!condition, fc) +} + +func (s *Scopes) Between(field string, start, end interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? BETWEEN ? AND ?", field, start, end) + }) +} + +func (s *Scopes) NotBetween(field string, start, end interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? NOT BETWEEN ? AND ?", field, start, end) + }) +} + +func (s *Scopes) In(field string, values ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? IN (?)", field, values) + }) +} + +func (s *Scopes) NotIn(field string, values ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? NOT IN (?)", field, values) + }) +} + +func (s *Scopes) Like(field string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? LIKE ?", field, value) + }) +} + +func (s *Scopes) NotLike(field string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? NOT LIKE ?", field, value) + }) +} From 47f63b90732baa771e19a8914410460e2156b0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 12:57:55 +0800 Subject: [PATCH 02/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scope/funcs.go | 10 ------ gorm/scope/order.go | 35 +++++++++++++++++++ gorm/scope/pagination.go | 29 ++++++++++++++++ gorm/scope/scope.go | 55 +++-------------------------- gorm/scope/traits.go | 14 ++++++++ gorm/scope/where.go | 39 +++++++++++++++++++++ pagination/paginator.go | 75 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 196 insertions(+), 61 deletions(-) delete mode 100644 gorm/scope/funcs.go create mode 100644 gorm/scope/order.go create mode 100644 gorm/scope/pagination.go create mode 100644 gorm/scope/traits.go create mode 100644 gorm/scope/where.go create mode 100644 pagination/paginator.go diff --git a/gorm/scope/funcs.go b/gorm/scope/funcs.go deleted file mode 100644 index 2d16e72c..00000000 --- a/gorm/scope/funcs.go +++ /dev/null @@ -1,10 +0,0 @@ -package scope - -// -// func When(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { -// return New().When(condition, f) -// } -// -// func Unless(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { -// return New().Unless(condition, f) -// } diff --git a/gorm/scope/order.go b/gorm/scope/order.go new file mode 100644 index 00000000..44d95b6e --- /dev/null +++ b/gorm/scope/order.go @@ -0,0 +1,35 @@ +package scope + +import ( + "fmt" + "strings" + + "gorm.io/gorm" +) + +func (s *Scopes) OrderBy(column string, reorder ...string) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Order(fmt.Sprintf("%s %s", column, s.buildReorder(reorder...))) + }) +} + +func (s *Scopes) OrderByDesc(column string) *Scopes { + return s.OrderBy(column, "desc") +} + +func (s *Scopes) OrderByAsc(column string) *Scopes { + return s.OrderBy(column, "asc") +} + +func (s *Scopes) OrderByRaw(sql string, values ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Order(fmt.Sprintf(sql, values...)) // TODO: 语法待定? + }) +} + +func (s *Scopes) buildReorder(reorder ...string) string { + if len(reorder) > 0 && strings.ToUpper(reorder[0]) == "DESC" { + return "DESC" + } + return "ASC" +} diff --git a/gorm/scope/pagination.go b/gorm/scope/pagination.go new file mode 100644 index 00000000..43f54e0d --- /dev/null +++ b/gorm/scope/pagination.go @@ -0,0 +1,29 @@ +package scope + +import ( + "gorm.io/gorm" + + "github.com/go-kratos-ecosystem/components/v2/pagination" +) + +func (s *Scopes) Page(page, pageSize int) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Offset((page - 1) * pageSize).Limit(pageSize) + }) +} + +// Paginate TODO: 未实现 +func (s *Scopes) Paginate(page, pageSize int, dest interface{}) *Scopes { + var total int64 + + dest = pagination.Paginator{ + Page: page, + PageSize: pageSize, + Total: int(total), + } + + return s.Add(func(db *gorm.DB) *gorm.DB { + db.Count(&total) + return db.Offset((page - 1) * pageSize).Limit(pageSize).Find(dest) + }) +} diff --git a/gorm/scope/scope.go b/gorm/scope/scope.go index 7136e5e4..0e802300 100644 --- a/gorm/scope/scope.go +++ b/gorm/scope/scope.go @@ -16,12 +16,12 @@ func Unless(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { return New().Unless(condition, f) } -func Between(field string, start, end interface{}) *Scopes { - return New().Between(field, start, end) +func WhereBetween(field string, start, end interface{}) *Scopes { + return New().WhereBetween(field, start, end) } -func NotBetween(field string, start, end interface{}) *Scopes { - return New().NotBetween(field, start, end) +func WhereNotBetween(field string, start, end interface{}) *Scopes { + return New().WhereNotBetween(field, start, end) } func (s *Scopes) Apply(db *gorm.DB) *gorm.DB { @@ -42,50 +42,3 @@ func (s *Scopes) Add(scopes ...func(*gorm.DB) *gorm.DB) *Scopes { *s = append(*s, scopes...) return s } - -func (s *Scopes) When(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { - if condition { - return s.Add(fc) - } - return s -} - -func (s *Scopes) Unless(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { - return s.When(!condition, fc) -} - -func (s *Scopes) Between(field string, start, end interface{}) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? BETWEEN ? AND ?", field, start, end) - }) -} - -func (s *Scopes) NotBetween(field string, start, end interface{}) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? NOT BETWEEN ? AND ?", field, start, end) - }) -} - -func (s *Scopes) In(field string, values ...interface{}) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? IN (?)", field, values) - }) -} - -func (s *Scopes) NotIn(field string, values ...interface{}) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? NOT IN (?)", field, values) - }) -} - -func (s *Scopes) Like(field string, value interface{}) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? LIKE ?", field, value) - }) -} - -func (s *Scopes) NotLike(field string, value interface{}) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? NOT LIKE ?", field, value) - }) -} diff --git a/gorm/scope/traits.go b/gorm/scope/traits.go new file mode 100644 index 00000000..e70cf877 --- /dev/null +++ b/gorm/scope/traits.go @@ -0,0 +1,14 @@ +package scope + +import "gorm.io/gorm" + +func (s *Scopes) When(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { + if condition { + return s.Add(fc) + } + return s +} + +func (s *Scopes) Unless(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { + return s.When(!condition, fc) +} diff --git a/gorm/scope/where.go b/gorm/scope/where.go new file mode 100644 index 00000000..b753ea7b --- /dev/null +++ b/gorm/scope/where.go @@ -0,0 +1,39 @@ +package scope + +import "gorm.io/gorm" + +func (s *Scopes) WhereBetween(column string, start, end interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? BETWEEN ? AND ?", column, start, end) + }) +} + +func (s *Scopes) WhereNotBetween(column string, start, end interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? NOT BETWEEN ? AND ?", column, start, end) + }) +} + +func (s *Scopes) WhereIn(column string, values ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? IN (?)", column, values) + }) +} + +func (s *Scopes) WhereNotIn(column string, values ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? NOT IN (?)", column, values) + }) +} + +func (s *Scopes) WhereLike(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? LIKE ?", column, value) + }) +} + +func (s *Scopes) WhereNotLike(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? NOT LIKE ?", column, value) + }) +} diff --git a/pagination/paginator.go b/pagination/paginator.go new file mode 100644 index 00000000..866e0fe1 --- /dev/null +++ b/pagination/paginator.go @@ -0,0 +1,75 @@ +package pagination + +import "encoding/json" + +type Paginator struct { + Page int `json:"page"` + PageSize int `json:"page_size"` + Total int `json:"total"` +} + +func NewPaginator(page, pageSize, total int) *Paginator { + return &Paginator{ + Page: page, + PageSize: pageSize, + Total: total, + } +} + +func (p *Paginator) GetPage() int { + return p.Page +} + +func (p *Paginator) GetPerPage() int { + return p.PageSize +} + +func (p *Paginator) GetTotal() int { + return p.Total +} + +func (p *Paginator) GetLastPage() int { + return (p.Total + p.PageSize - 1) / p.PageSize +} + +func (p *Paginator) GetOffset() int { + return (p.Page - 1) * p.PageSize +} + +func (p *Paginator) GetLimit() int { + return p.PageSize +} + +func (p *Paginator) HasMore() bool { + return p.Page*p.PageSize < p.Total +} + +func (p *Paginator) GetNextPage() int { + if p.HasMore() { + return p.Page + 1 + } + return p.Page +} + +func (p *Paginator) GetPrevPage() int { + if p.Page > 1 { + return p.Page - 1 + } + return p.Page +} + +func (p *Paginator) ToMap() map[string]interface{} { + return map[string]interface{}{ + "page": p.Page, + "page_size": p.PageSize, + "total": p.Total, + "next_page": p.GetNextPage(), + "prev_page": p.GetPrevPage(), + "last_page": p.GetLastPage(), + "has_more": p.HasMore(), + } +} + +func (p *Paginator) ToJSON() ([]byte, error) { + return json.Marshal(p.ToMap()) +} From 7d86d822e76710d52e4a1624d84222c324ccd755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 13:55:21 +0800 Subject: [PATCH 03/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/{scope => scopes}/order.go | 18 ++++++++++++++++- gorm/{scope => scopes}/pagination.go | 10 +++++----- gorm/{scope/scope.go => scopes/scopes.go} | 18 +---------------- gorm/{scope/traits.go => scopes/trait.go} | 10 +++++++++- gorm/{scope => scopes}/where.go | 10 +++++++++- pagination/paginator.go | 24 +++++++++++------------ 6 files changed, 53 insertions(+), 37 deletions(-) rename gorm/{scope => scopes}/order.go (67%) rename gorm/{scope => scopes}/pagination.go (76%) rename gorm/{scope/scope.go => scopes/scopes.go} (50%) rename gorm/{scope/traits.go => scopes/trait.go} (54%) rename gorm/{scope => scopes}/where.go (81%) diff --git a/gorm/scope/order.go b/gorm/scopes/order.go similarity index 67% rename from gorm/scope/order.go rename to gorm/scopes/order.go index 44d95b6e..d4bb001d 100644 --- a/gorm/scope/order.go +++ b/gorm/scopes/order.go @@ -1,4 +1,4 @@ -package scope +package scopes import ( "fmt" @@ -7,6 +7,22 @@ import ( "gorm.io/gorm" ) +func OrderBy(column string, reorder ...string) *Scopes { + return New().OrderBy(column, reorder...) +} + +func OrderByDesc(column string) *Scopes { + return New().OrderByDesc(column) +} + +func OrderByAsc(column string) *Scopes { + return New().OrderByAsc(column) +} + +func OrderByRaw(sql string, values ...interface{}) *Scopes { + return New().OrderByRaw(sql, values...) +} + func (s *Scopes) OrderBy(column string, reorder ...string) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Order(fmt.Sprintf("%s %s", column, s.buildReorder(reorder...))) diff --git a/gorm/scope/pagination.go b/gorm/scopes/pagination.go similarity index 76% rename from gorm/scope/pagination.go rename to gorm/scopes/pagination.go index 43f54e0d..74c43348 100644 --- a/gorm/scope/pagination.go +++ b/gorm/scopes/pagination.go @@ -1,4 +1,4 @@ -package scope +package scopes import ( "gorm.io/gorm" @@ -17,13 +17,13 @@ func (s *Scopes) Paginate(page, pageSize int, dest interface{}) *Scopes { var total int64 dest = pagination.Paginator{ - Page: page, - PageSize: pageSize, - Total: int(total), + Page: page, + PrePage: pageSize, + Total: int(total), } return s.Add(func(db *gorm.DB) *gorm.DB { db.Count(&total) - return db.Offset((page - 1) * pageSize).Limit(pageSize).Find(dest) + return db.Offset((page - 1) * pageSize).Limit(pageSize) }) } diff --git a/gorm/scope/scope.go b/gorm/scopes/scopes.go similarity index 50% rename from gorm/scope/scope.go rename to gorm/scopes/scopes.go index 0e802300..d2887827 100644 --- a/gorm/scope/scope.go +++ b/gorm/scopes/scopes.go @@ -1,4 +1,4 @@ -package scope +package scopes import "gorm.io/gorm" @@ -8,22 +8,6 @@ func New() *Scopes { return &Scopes{} } -func When(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { - return New().When(condition, f) -} - -func Unless(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { - return New().Unless(condition, f) -} - -func WhereBetween(field string, start, end interface{}) *Scopes { - return New().WhereBetween(field, start, end) -} - -func WhereNotBetween(field string, start, end interface{}) *Scopes { - return New().WhereNotBetween(field, start, end) -} - func (s *Scopes) Apply(db *gorm.DB) *gorm.DB { return db.Scopes(*s...) } diff --git a/gorm/scope/traits.go b/gorm/scopes/trait.go similarity index 54% rename from gorm/scope/traits.go rename to gorm/scopes/trait.go index e70cf877..f829ed6c 100644 --- a/gorm/scope/traits.go +++ b/gorm/scopes/trait.go @@ -1,7 +1,15 @@ -package scope +package scopes import "gorm.io/gorm" +func When(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { + return New().When(condition, f) +} + +func Unless(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { + return New().Unless(condition, f) +} + func (s *Scopes) When(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { if condition { return s.Add(fc) diff --git a/gorm/scope/where.go b/gorm/scopes/where.go similarity index 81% rename from gorm/scope/where.go rename to gorm/scopes/where.go index b753ea7b..d17ecab0 100644 --- a/gorm/scope/where.go +++ b/gorm/scopes/where.go @@ -1,7 +1,15 @@ -package scope +package scopes import "gorm.io/gorm" +func WhereBetween(field string, start, end interface{}) *Scopes { + return New().WhereBetween(field, start, end) +} + +func WhereNotBetween(field string, start, end interface{}) *Scopes { + return New().WhereNotBetween(field, start, end) +} + func (s *Scopes) WhereBetween(column string, start, end interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Where("? BETWEEN ? AND ?", column, start, end) diff --git a/pagination/paginator.go b/pagination/paginator.go index 866e0fe1..39b671bc 100644 --- a/pagination/paginator.go +++ b/pagination/paginator.go @@ -3,16 +3,16 @@ package pagination import "encoding/json" type Paginator struct { - Page int `json:"page"` - PageSize int `json:"page_size"` - Total int `json:"total"` + Page int `json:"page"` + PrePage int `json:"pre_page"` + Total int `json:"total"` } func NewPaginator(page, pageSize, total int) *Paginator { return &Paginator{ - Page: page, - PageSize: pageSize, - Total: total, + Page: page, + PrePage: pageSize, + Total: total, } } @@ -21,7 +21,7 @@ func (p *Paginator) GetPage() int { } func (p *Paginator) GetPerPage() int { - return p.PageSize + return p.PrePage } func (p *Paginator) GetTotal() int { @@ -29,19 +29,19 @@ func (p *Paginator) GetTotal() int { } func (p *Paginator) GetLastPage() int { - return (p.Total + p.PageSize - 1) / p.PageSize + return (p.Total + p.PrePage - 1) / p.PrePage } func (p *Paginator) GetOffset() int { - return (p.Page - 1) * p.PageSize + return (p.Page - 1) * p.PrePage } func (p *Paginator) GetLimit() int { - return p.PageSize + return p.PrePage } func (p *Paginator) HasMore() bool { - return p.Page*p.PageSize < p.Total + return p.Page*p.PrePage < p.Total } func (p *Paginator) GetNextPage() int { @@ -61,7 +61,7 @@ func (p *Paginator) GetPrevPage() int { func (p *Paginator) ToMap() map[string]interface{} { return map[string]interface{}{ "page": p.Page, - "page_size": p.PageSize, + "pre_page": p.PrePage, "total": p.Total, "next_page": p.GetNextPage(), "prev_page": p.GetPrevPage(), From 397e47423ff287692dea6ecfdef239d8e3de1b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 22:54:51 +0800 Subject: [PATCH 04/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- go.mod | 2 + go.sum | 5 +++ gorm/scopes/init_test.go | 82 +++++++++++++++++++++++++++++++++++++++ gorm/scopes/where.go | 58 +++++++++++++++++++++++++++ gorm/scopes/where_test.go | 28 +++++++++++++ 5 files changed, 175 insertions(+) create mode 100644 gorm/scopes/init_test.go create mode 100644 gorm/scopes/where_test.go diff --git a/go.mod b/go.mod index c4dc4db7..e917bb12 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/stretchr/testify v1.8.4 golang.org/x/term v0.17.0 golang.org/x/text v0.14.0 + gorm.io/driver/mysql v1.5.4 gorm.io/gorm v1.25.7 ) @@ -31,6 +32,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.18.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/gorilla/mux v1.8.1 // indirect diff --git a/go.sum b/go.sum index e44c9dca..133ab269 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U= github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -144,6 +146,9 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.5.4 h1:igQmHfKcbaTVyAIHNhhB888vvxh8EdQ2uSUT0LPcBso= +gorm.io/driver/mysql v1.5.4/go.mod h1:9rYxJph/u9SWkWc9yY4XJ1F/+xO0S/ChOmbk3+Z5Tvs= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/gorm/scopes/init_test.go b/gorm/scopes/init_test.go new file mode 100644 index 00000000..969ea8f2 --- /dev/null +++ b/gorm/scopes/init_test.go @@ -0,0 +1,82 @@ +package scopes + +import ( + "log" + "os" + "time" + + "gorm.io/driver/mysql" + "gorm.io/gorm" +) + +var ( + DB *gorm.DB + dsn = "gorm:gorm@tcp(localhost:3306)/gorm?charset=utf8&parseTime=True&loc=Local" +) + +type User struct { + gorm.Model + Name string + Age uint + Sex string + Birthday *time.Time +} + +func init() { + var err error + DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + log.Println("failed to connect database, got error", err) + os.Exit(1) + } + + runMigrations() +} + +func runMigrations() { + var err error + models := []interface{}{&User{}} + + if err = DB.Migrator().DropTable(models...); err != nil { + log.Printf("Didn't drop table, got error %v\n", err) + os.Exit(1) + } + + if err = DB.AutoMigrate(models...); err != nil { + log.Printf("Failed to auto migrate, but got error %v\n", err) + os.Exit(1) + } + + for _, m := range models { + if !DB.Migrator().HasTable(m) { + log.Printf("Didn't create table for %#v\n", m) + os.Exit(1) + } + } +} + +type GetUserOptions struct { + Age int + Birthday *time.Time +} + +func GetUser(name string, opts GetUserOptions) *User { + var ( + birthday = time.Now().Round(time.Second) + user = User{ + Name: name, + Age: 18, + Birthday: &birthday, + } + ) + + if opts.Age > 0 { + user.Age = uint(opts.Age) + } + + if opts.Birthday != nil { + user.Birthday = opts.Birthday + } + + return &user +} diff --git a/gorm/scopes/where.go b/gorm/scopes/where.go index d17ecab0..73713437 100644 --- a/gorm/scopes/where.go +++ b/gorm/scopes/where.go @@ -2,6 +2,10 @@ package scopes import "gorm.io/gorm" +func Where(query interface{}, args ...interface{}) *Scopes { + return New().Where(query, args...) +} + func WhereBetween(field string, start, end interface{}) *Scopes { return New().WhereBetween(field, start, end) } @@ -10,6 +14,12 @@ func WhereNotBetween(field string, start, end interface{}) *Scopes { return New().WhereNotBetween(field, start, end) } +func (s *Scopes) Where(query interface{}, args ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where(query, args...) + }) +} + func (s *Scopes) WhereBetween(column string, start, end interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Where("? BETWEEN ? AND ?", column, start, end) @@ -45,3 +55,51 @@ func (s *Scopes) WhereNotLike(column string, value interface{}) *Scopes { return db.Where("? NOT LIKE ?", column, value) }) } + +func (s *Scopes) WhereEq(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? = ?", column, value) + }) +} + +func (s *Scopes) WhereEgt(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? >= ?", column, value) + }) +} + +func (s *Scopes) WhereGt(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? > ?", column, value) + }) +} + +func (s *Scopes) WhereElt(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? <= ?", column, value) + }) +} + +func (s *Scopes) WhereLt(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? < ?", column, value) + }) +} + +func (s *Scopes) WhereNe(column string, value interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? <> ?", column, value) + }) +} + +func (s *Scopes) WhereNull(column string) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? IS NULL", column) + }) +} + +func (s *Scopes) WhereNotNull(column string) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Where("? IS NOT NULL", column) + }) +} diff --git a/gorm/scopes/where_test.go b/gorm/scopes/where_test.go new file mode 100644 index 00000000..1866b287 --- /dev/null +++ b/gorm/scopes/where_test.go @@ -0,0 +1,28 @@ +package scopes + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWhere_Where(t *testing.T) { + users := []*User{ + GetUser("WhereUser1", GetUserOptions{}), + GetUser("WhereUser2", GetUserOptions{}), + GetUser("WhereUser3", GetUserOptions{}), + } + + DB.Create(&users) + + var users1, users2, users3 []User + DB.Scopes(Where("name in (?)", []string{"WhereUser1", "WhereUser2"}).Scope()).Find(&users1) + assert.Len(t, users1, 2) + + DB.Scopes(Where("name in (?)", []string{"WhereUser1", "WhereUser4"}).Scope()).Find(&users2) + assert.Len(t, users2, 1) + + DB.Scopes(Where("name = ?", "WhereUser3").Scope()).Find(&users3) + assert.Len(t, users3, 1) + assert.Equal(t, "WhereUser3", users3[0].Name) +} From a21ae2b4fae0a540380939c41040b42572446e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 22:56:53 +0800 Subject: [PATCH 05/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- .github/workflows/test.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c51bb0df..8cb4d306 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,7 @@ jobs: matrix: go-version: [ 1.18.x, 1.19.x, 1.20.x, 1.21.x, 1.22.x ] platform: [ ubuntu-latest ] + mysql-version: ['mysql:latest', 'mysql:5.7'] runs-on: ${{ matrix.platform }} services: @@ -23,6 +24,22 @@ jobs: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 6379:6379 + - + mysql: + image: ${{ matrix.mysql-version }} + env: + MYSQL_DATABASE: gorm + MYSQL_USER: gorm + MYSQL_PASSWORD: gorm + MYSQL_RANDOM_ROOT_PASSWORD: "yes" + ports: + - 9910:3306 + options: >- + --health-cmd "mysqladmin ping -ugorm -pgorm" + --health-interval 10s + --health-start-period 10s + --health-timeout 5s + --health-retries 10 steps: - name: Checkout code From 96411fe750401ad6d00bbb836296148e167f53a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 22:57:39 +0800 Subject: [PATCH 06/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8cb4d306..00315506 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,6 @@ jobs: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 6379:6379 - - mysql: image: ${{ matrix.mysql-version }} env: From 71199277547ca64de95bd7fe16168aa7bca66b77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 22:57:49 +0800 Subject: [PATCH 07/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 00315506..eb206ac2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: MYSQL_PASSWORD: gorm MYSQL_RANDOM_ROOT_PASSWORD: "yes" ports: - - 9910:3306 + - 3306:3306 options: >- --health-cmd "mysqladmin ping -ugorm -pgorm" --health-interval 10s From b727f25c36aa474b6f03d95770cc3254eed2fe6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 23:31:30 +0800 Subject: [PATCH 08/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/init_test.go | 8 ++--- gorm/scopes/pagination.go | 30 ++++++++-------- gorm/scopes/where.go | 76 ++++++++++++++++++++++++++++++++++++--- gorm/scopes/where_test.go | 67 ++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 25 deletions(-) diff --git a/gorm/scopes/init_test.go b/gorm/scopes/init_test.go index 969ea8f2..4f592b38 100644 --- a/gorm/scopes/init_test.go +++ b/gorm/scopes/init_test.go @@ -16,10 +16,10 @@ var ( type User struct { gorm.Model - Name string - Age uint - Sex string - Birthday *time.Time + Name string `gorm:"column:name"` + Age uint `gorm:"column:age"` + Sex string `gorm:"column:sex"` + Birthday *time.Time `gorm:"column:birthday"` } func init() { diff --git a/gorm/scopes/pagination.go b/gorm/scopes/pagination.go index 74c43348..e0af4c5c 100644 --- a/gorm/scopes/pagination.go +++ b/gorm/scopes/pagination.go @@ -2,8 +2,6 @@ package scopes import ( "gorm.io/gorm" - - "github.com/go-kratos-ecosystem/components/v2/pagination" ) func (s *Scopes) Page(page, pageSize int) *Scopes { @@ -13,17 +11,17 @@ func (s *Scopes) Page(page, pageSize int) *Scopes { } // Paginate TODO: 未实现 -func (s *Scopes) Paginate(page, pageSize int, dest interface{}) *Scopes { - var total int64 - - dest = pagination.Paginator{ - Page: page, - PrePage: pageSize, - Total: int(total), - } - - return s.Add(func(db *gorm.DB) *gorm.DB { - db.Count(&total) - return db.Offset((page - 1) * pageSize).Limit(pageSize) - }) -} +// func (s *Scopes) Paginate(page, pageSize int, dest interface{}) *Scopes { +// var total int64 +// +// dest = pagination.Paginator{ +// Page: page, +// PrePage: pageSize, +// Total: int(total), +// } +// +// return s.Add(func(db *gorm.DB) *gorm.DB { +// db.Count(&total) +// return db.Offset((page - 1) * pageSize).Limit(pageSize) +// }) +// } diff --git a/gorm/scopes/where.go b/gorm/scopes/where.go index 73713437..33a534f1 100644 --- a/gorm/scopes/where.go +++ b/gorm/scopes/where.go @@ -1,6 +1,10 @@ package scopes -import "gorm.io/gorm" +import ( + "fmt" + + "gorm.io/gorm" +) func Where(query interface{}, args ...interface{}) *Scopes { return New().Where(query, args...) @@ -14,6 +18,52 @@ func WhereNotBetween(field string, start, end interface{}) *Scopes { return New().WhereNotBetween(field, start, end) } +// WhereIn add where in condition +// +// WhereIn("name", []string{"WhereInUser1", "WhereInUser2"}) +// WhereIn("age", []int{18, 20}) +// WhereIn("name", "WhereInUser1", "WhereInUser2") +func WhereIn(field string, values ...interface{}) *Scopes { + return New().WhereIn(field, values...) +} + +// WhereNotIn add where not in condition +// +// WhereNotIn("name", []string{"WhereInUser1", "WhereInUser2"}) +// WhereNotIn("age", []int{18, 20}) +// WhereNotIn("name", "WhereInUser1", "WhereInUser2") +func WhereNotIn(field string, values ...interface{}) *Scopes { + return New().WhereNotIn(field, values...) +} + +func WhereLike(field string, value interface{}) *Scopes { + return New().WhereLike(field, value) +} + +func WhereNotLike(field string, value interface{}) *Scopes { + return New().WhereNotLike(field, value) +} + +func WhereEq(field string, value interface{}) *Scopes { + return New().WhereEq(field, value) +} + +func WhereEgt(field string, value interface{}) *Scopes { + return New().WhereEgt(field, value) +} + +func WhereGt(field string, value interface{}) *Scopes { + return New().WhereGt(field, value) +} + +func WhereElt(field string, value interface{}) *Scopes { + return New().WhereElt(field, value) +} + +func WhereLt(field string, value interface{}) *Scopes { + return New().WhereLt(field, value) +} + func (s *Scopes) Where(query interface{}, args ...interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Where(query, args...) @@ -22,25 +72,41 @@ func (s *Scopes) Where(query interface{}, args ...interface{}) *Scopes { func (s *Scopes) WhereBetween(column string, start, end interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? BETWEEN ? AND ?", column, start, end) + return db.Where(fmt.Sprintf("%s BETWEEN ? AND ?", column), start, end) }) } func (s *Scopes) WhereNotBetween(column string, start, end interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? NOT BETWEEN ? AND ?", column, start, end) + return db.Where(fmt.Sprintf("%s NOT BETWEEN ? AND ?", column), start, end) }) } +// WhereIn add where in condition +// +// WhereIn("name", []string{"WhereInUser1", "WhereInUser2"}) +// WhereIn("age", []int{18, 20}) +// WhereIn("name", "WhereInUser1", "WhereInUser2") func (s *Scopes) WhereIn(column string, values ...interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? IN (?)", column, values) + if len(values) > 1 { + return db.Where(fmt.Sprintf("%s IN (?)", column), values) + } + return db.Where(fmt.Sprintf("%s IN ?", column), values...) }) } +// WhereNotIn add where not in condition +// +// WhereNotIn("name", []string{"WhereInUser1", "WhereInUser2"}) +// WhereNotIn("age", []int{18, 20}) +// WhereNotIn("name", "WhereInUser1", "WhereInUser2") func (s *Scopes) WhereNotIn(column string, values ...interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? NOT IN (?)", column, values) + if len(values) > 1 { + return db.Where(fmt.Sprintf("%s NOT IN (?)", column), values) + } + return db.Where(fmt.Sprintf("%s NOT IN ?", column), values...) }) } diff --git a/gorm/scopes/where_test.go b/gorm/scopes/where_test.go index 1866b287..ad999833 100644 --- a/gorm/scopes/where_test.go +++ b/gorm/scopes/where_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "gorm.io/gorm" ) func TestWhere_Where(t *testing.T) { @@ -26,3 +27,69 @@ func TestWhere_Where(t *testing.T) { assert.Len(t, users3, 1) assert.Equal(t, "WhereUser3", users3[0].Name) } + +func TestWhere_Between(t *testing.T) { + users := []*User{ + GetUser("WhereBetweenUser1", GetUserOptions{Age: 18}), + GetUser("WhereBetweenUser2", GetUserOptions{Age: 20}), + GetUser("WhereBetweenUser3", GetUserOptions{Age: 22}), + } + + DB.Create(&users) + + var users1, users2, users3 []User + DB.Debug().Scopes(WhereBetween("age", 18, 20).Scope()).Find(&users1) + assert.Len(t, users1, 2) + + DB.Scopes(WhereBetween("age", 18, 19).Scope()).Find(&users2) + assert.Len(t, users2, 1) + assert.Equal(t, "WhereBetweenUser1", users2[0].Name) + + DB.Scopes(WhereBetween("age", 12, 16).Scope()).Find(&users3) + assert.Len(t, users3, 0) + + var users4, users5, users6 []User + DB.Scopes(WhereNotBetween("age", 18, 20).Scope()).Find(&users4) + assert.Len(t, users4, 1) + assert.Equal(t, "WhereBetweenUser3", users4[0].Name) + + DB.Scopes(WhereNotBetween("age", 18, 19).Scope()).Find(&users5) + assert.Len(t, users5, 2) + + DB.Scopes(WhereNotBetween("age", 12, 16).Scope()).Find(&users6) + assert.Len(t, users6, 3) +} + +func TestWhere_In(t *testing.T) { + users := []*User{ + GetUser("WhereInUser1", GetUserOptions{Age: 18}), + GetUser("WhereInUser2", GetUserOptions{Age: 20}), + GetUser("WhereInUser3", GetUserOptions{Age: 22}), + } + + DB.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{}) + DB.Create(&users) + + var users1, users2, users3 []User + DB.Scopes(WhereIn("name", "WhereInUser1", "WhereInUser2").Scope()).Find(&users1) + assert.Len(t, users1, 2) + + DB.Scopes(WhereIn("age", []int{18, 20}).Scope()).Find(&users2) + assert.Len(t, users2, 2) + + DB.Scopes(WhereIn("name", []string{"WhereInUser1", "WhereInUser2"}).Scope()).Find(&users3) + assert.Len(t, users3, 2) + + var users4, users5, users6 []User + DB.Scopes(WhereNotIn("name", "WhereInUser1", "WhereInUser2").Scope()).Find(&users4) + assert.Len(t, users4, 1) + assert.Equal(t, "WhereInUser3", users4[0].Name) + + DB.Scopes(WhereNotIn("age", []int{18, 20}).Scope()).Find(&users5) + assert.Len(t, users5, 1) + assert.Equal(t, "WhereInUser3", users5[0].Name) + + DB.Scopes(WhereNotIn("name", []string{"WhereInUser1", "WhereInUser2"}).Scope()).Find(&users6) + assert.Len(t, users6, 1) + assert.Equal(t, "WhereInUser3", users6[0].Name) +} From eb972e0611d3d0856d68def45a22e7d9e522348a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 23:34:02 +0800 Subject: [PATCH 09/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/where_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gorm/scopes/where_test.go b/gorm/scopes/where_test.go index ad999833..1903edf9 100644 --- a/gorm/scopes/where_test.go +++ b/gorm/scopes/where_test.go @@ -35,10 +35,11 @@ func TestWhere_Between(t *testing.T) { GetUser("WhereBetweenUser3", GetUserOptions{Age: 22}), } + DB.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{}) DB.Create(&users) var users1, users2, users3 []User - DB.Debug().Scopes(WhereBetween("age", 18, 20).Scope()).Find(&users1) + DB.Scopes(WhereBetween("age", 18, 20).Scope()).Find(&users1) assert.Len(t, users1, 2) DB.Scopes(WhereBetween("age", 18, 19).Scope()).Find(&users2) From f5b258f6f059ef991dc46682323f34539db5f0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Fri, 23 Feb 2024 23:51:35 +0800 Subject: [PATCH 10/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/init_test.go | 4 ++++ gorm/scopes/where.go | 48 +++++++++++++++++++++++++++++++++++++-- gorm/scopes/where_test.go | 45 +++++++++++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/gorm/scopes/init_test.go b/gorm/scopes/init_test.go index 4f592b38..731c6fa0 100644 --- a/gorm/scopes/init_test.go +++ b/gorm/scopes/init_test.go @@ -80,3 +80,7 @@ func GetUser(name string, opts GetUserOptions) *User { return &user } + +func CleanUsers() { + DB.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{}) +} diff --git a/gorm/scopes/where.go b/gorm/scopes/where.go index 33a534f1..e960369e 100644 --- a/gorm/scopes/where.go +++ b/gorm/scopes/where.go @@ -6,14 +6,24 @@ import ( "gorm.io/gorm" ) +// Where add where condition +// +// Where("name = ?", "Flc") +// Where("name = ? AND age = ?", "Flc", 20) func Where(query interface{}, args ...interface{}) *Scopes { return New().Where(query, args...) } +// WhereBetween add where between condition +// +// WhereBetween("age", 18, 20) func WhereBetween(field string, start, end interface{}) *Scopes { return New().WhereBetween(field, start, end) } +// WhereNotBetween add where not between condition +// +// WhereNotBetween("age", 18, 20) func WhereNotBetween(field string, start, end interface{}) *Scopes { return New().WhereNotBetween(field, start, end) } @@ -36,10 +46,22 @@ func WhereNotIn(field string, values ...interface{}) *Scopes { return New().WhereNotIn(field, values...) } +// WhereLike add where like condition +// +// WhereLike("name", "Flc") +// WhereLike("name", "Flc%") +// WhereLike("name", "%Flc") +// WhereLike("name", "%Flc%") func WhereLike(field string, value interface{}) *Scopes { return New().WhereLike(field, value) } +// WhereNotLike add where not like condition +// +// WhereNotLike("name", "Flc") +// WhereNotLike("name", "Flc%") +// WhereNotLike("name", "%Flc") +// WhereNotLike("name", "%Flc%") func WhereNotLike(field string, value interface{}) *Scopes { return New().WhereNotLike(field, value) } @@ -64,18 +86,28 @@ func WhereLt(field string, value interface{}) *Scopes { return New().WhereLt(field, value) } +// Where add where condition +// +// Where("name = ?", "Flc") +// Where("name = ? AND age = ?", "Flc", 20) func (s *Scopes) Where(query interface{}, args ...interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Where(query, args...) }) } +// WhereBetween add where between condition +// +// WhereBetween("age", 18, 20) func (s *Scopes) WhereBetween(column string, start, end interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Where(fmt.Sprintf("%s BETWEEN ? AND ?", column), start, end) }) } +// WhereNotBetween add where not between condition +// +// WhereNotBetween("age", 18, 20) func (s *Scopes) WhereNotBetween(column string, start, end interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Where(fmt.Sprintf("%s NOT BETWEEN ? AND ?", column), start, end) @@ -110,15 +142,27 @@ func (s *Scopes) WhereNotIn(column string, values ...interface{}) *Scopes { }) } +// WhereLike add where like condition +// +// WhereLike("name", "Flc") +// WhereLike("name", "Flc%") +// WhereLike("name", "%Flc") +// WhereLike("name", "%Flc%") func (s *Scopes) WhereLike(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? LIKE ?", column, value) + return db.Where(fmt.Sprintf("%s LIKE ?", column), value) }) } +// WhereNotLike add where not like condition +// +// WhereNotLike("name", "Flc") +// WhereNotLike("name", "Flc%") +// WhereNotLike("name", "%Flc") +// WhereNotLike("name", "%Flc%") func (s *Scopes) WhereNotLike(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? NOT LIKE ?", column, value) + return db.Where(fmt.Sprintf("%s NOT LIKE ?", column), value) }) } diff --git a/gorm/scopes/where_test.go b/gorm/scopes/where_test.go index 1903edf9..4fb06115 100644 --- a/gorm/scopes/where_test.go +++ b/gorm/scopes/where_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "gorm.io/gorm" ) func TestWhere_Where(t *testing.T) { @@ -14,6 +13,7 @@ func TestWhere_Where(t *testing.T) { GetUser("WhereUser3", GetUserOptions{}), } + CleanUsers() DB.Create(&users) var users1, users2, users3 []User @@ -35,7 +35,7 @@ func TestWhere_Between(t *testing.T) { GetUser("WhereBetweenUser3", GetUserOptions{Age: 22}), } - DB.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{}) + CleanUsers() DB.Create(&users) var users1, users2, users3 []User @@ -68,7 +68,7 @@ func TestWhere_In(t *testing.T) { GetUser("WhereInUser3", GetUserOptions{Age: 22}), } - DB.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{}) + CleanUsers() DB.Create(&users) var users1, users2, users3 []User @@ -94,3 +94,42 @@ func TestWhere_In(t *testing.T) { assert.Len(t, users6, 1) assert.Equal(t, "WhereInUser3", users6[0].Name) } + +func TestWhere_Like(t *testing.T) { + users := []*User{ + GetUser("WhereLikeUser1", GetUserOptions{Age: 18}), + GetUser("WhereLikeUser2", GetUserOptions{Age: 20}), + GetUser("WhereLikeUser3", GetUserOptions{Age: 22}), + } + + CleanUsers() + DB.Create(&users) + + var users1, users2, users3, users4 []User + DB.Scopes(WhereLike("name", "WhereLikeUser1").Scope()).Find(&users1) + assert.Len(t, users1, 1) + assert.Equal(t, "WhereLikeUser1", users1[0].Name) + + DB.Scopes(WhereLike("name", "WhereLike%").Scope()).Find(&users2) + assert.Len(t, users2, 3) + + DB.Scopes(WhereLike("name", "%LikeUser3").Scope()).Find(&users3) + assert.Len(t, users3, 1) + assert.Equal(t, "WhereLikeUser3", users3[0].Name) + + DB.Scopes(WhereLike("name", "%Like%").Scope()).Find(&users4) + assert.Len(t, users4, 3) + + var users5, users6, users7, users8 []User + DB.Scopes(WhereNotLike("name", "WhereLikeUser1").Scope()).Find(&users5) + assert.Len(t, users5, 2) + + DB.Scopes(WhereNotLike("name", "WhereLike%").Scope()).Find(&users6) + assert.Len(t, users6, 0) + + DB.Scopes(WhereNotLike("name", "%LikeUser3").Scope()).Find(&users7) + assert.Len(t, users7, 2) + + DB.Scopes(WhereNotLike("name", "%Like%").Scope()).Find(&users8) + assert.Len(t, users8, 0) +} From b95a89900abc4ce9f6e67f6b436e8d1e5e2d5ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Sat, 24 Feb 2024 00:10:18 +0800 Subject: [PATCH 11/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/where.go | 62 +++++++++++++++++++++++++++--- gorm/scopes/where_test.go | 80 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 6 deletions(-) diff --git a/gorm/scopes/where.go b/gorm/scopes/where.go index e960369e..0b857663 100644 --- a/gorm/scopes/where.go +++ b/gorm/scopes/where.go @@ -66,26 +66,50 @@ func WhereNotLike(field string, value interface{}) *Scopes { return New().WhereNotLike(field, value) } +// WhereEq add where eq condition +// +// WhereEq("name", "Flc") +// WhereEq("age", 18) func WhereEq(field string, value interface{}) *Scopes { return New().WhereEq(field, value) } +// WhereEgt add where egt condition +// +// WhereEgt("age", 18) func WhereEgt(field string, value interface{}) *Scopes { return New().WhereEgt(field, value) } +// WhereGt add where gt condition +// +// WhereGt("age", 18) func WhereGt(field string, value interface{}) *Scopes { return New().WhereGt(field, value) } +// WhereElt add where elt condition +// +// WhereElt("age", 18) func WhereElt(field string, value interface{}) *Scopes { return New().WhereElt(field, value) } +// WhereLt add where lt condition +// +// WhereLt("age", 18) func WhereLt(field string, value interface{}) *Scopes { return New().WhereLt(field, value) } +// WhereNe add where ne condition +// +// WhereNe("name", "Flc") +// WhereNe("age", 18) +func WhereNe(field string, value interface{}) *Scopes { + return New().WhereNe(field, value) +} + // Where add where condition // // Where("name = ?", "Flc") @@ -166,39 +190,65 @@ func (s *Scopes) WhereNotLike(column string, value interface{}) *Scopes { }) } +// WhereEq add where eq condition +// +// WhereEq("name", "Flc") +// WhereEq("age", 18) func (s *Scopes) WhereEq(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? = ?", column, value) + return db.Where(fmt.Sprintf("%s = ?", column), value) }) } +// WhereEgt add where egt condition +// +// WhereEgt("age", 18) func (s *Scopes) WhereEgt(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? >= ?", column, value) + return db.Where(fmt.Sprintf("%s >= ?", column), value) }) } +// WhereGt add where gt condition +// +// WhereGt("age", 18) func (s *Scopes) WhereGt(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? > ?", column, value) + return db.Where(fmt.Sprintf("%s > ?", column), value) }) } +// WhereElt add where elt condition +// +// WhereElt("age", 18) func (s *Scopes) WhereElt(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? <= ?", column, value) + return db.Where(fmt.Sprintf("%s <= ?", column), value) }) } +// WhereLt add where lt condition +// +// WhereLt("age", 18) func (s *Scopes) WhereLt(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? < ?", column, value) + return db.Where(fmt.Sprintf("%s < ?", column), value) }) } +// WhereNe add where ne condition +// +// WhereNe("name", "Flc") +// WhereNe("age", 18) func (s *Scopes) WhereNe(column string, value interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? <> ?", column, value) + return db.Where(fmt.Sprintf("%s <> ?", column), value) + }) +} + +func (s *Scopes) WhereNot(query interface{}, args ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Not(query, args...) }) } diff --git a/gorm/scopes/where_test.go b/gorm/scopes/where_test.go index 4fb06115..0deb2e44 100644 --- a/gorm/scopes/where_test.go +++ b/gorm/scopes/where_test.go @@ -133,3 +133,83 @@ func TestWhere_Like(t *testing.T) { DB.Scopes(WhereNotLike("name", "%Like%").Scope()).Find(&users8) assert.Len(t, users8, 0) } + +func TestWhere_OP(t *testing.T) { + users := []*User{ + GetUser("WhereLikeUser1", GetUserOptions{Age: 18}), + GetUser("WhereLikeUser2", GetUserOptions{Age: 20}), + GetUser("WhereLikeUser3", GetUserOptions{Age: 22}), + GetUser("WhereLikeUser4", GetUserOptions{Age: 22}), + } + + CleanUsers() + DB.Create(&users) + + // Eq + var users1, users2, users3 []User + DB.Scopes(WhereEq("name", "WhereLikeUser1").Scope()).Find(&users1) + assert.Len(t, users1, 1) + assert.Equal(t, "WhereLikeUser1", users1[0].Name) + + DB.Scopes(WhereEq("age", 18).Scope()).Find(&users2) + assert.Len(t, users2, 1) + assert.Equal(t, "WhereLikeUser1", users2[0].Name) + + DB.Scopes(WhereEq("age", 22).Scope()).Find(&users3) + assert.Len(t, users3, 2) + + // Egt + var users4, users5, users6 []User + DB.Scopes(WhereEgt("age", 20).Scope()).Find(&users4) + assert.Len(t, users4, 3) + + DB.Scopes(WhereEgt("age", 22).Scope()).Find(&users5) + assert.Len(t, users5, 2) + + DB.Scopes(WhereEgt("age", 23).Scope()).Find(&users6) + assert.Len(t, users6, 0) + + // Elt + var users7, users8, users9 []User + DB.Scopes(WhereElt("age", 20).Scope()).Find(&users7) + assert.Len(t, users7, 2) + + DB.Scopes(WhereElt("age", 22).Scope()).Find(&users8) + assert.Len(t, users8, 4) + + DB.Scopes(WhereElt("age", 18).Scope()).Find(&users9) + assert.Len(t, users9, 1) + + // Gt + var users10, users11, users12 []User + DB.Scopes(WhereGt("age", 20).Scope()).Find(&users10) + assert.Len(t, users10, 2) + + DB.Scopes(WhereGt("age", 22).Scope()).Find(&users11) + assert.Len(t, users11, 0) + + DB.Scopes(WhereGt("age", 18).Scope()).Find(&users12) + assert.Len(t, users12, 3) + + // Lt + var users13, users14, users15 []User + DB.Scopes(WhereLt("age", 20).Scope()).Find(&users13) + assert.Len(t, users13, 1) + + DB.Scopes(WhereLt("age", 22).Scope()).Find(&users14) + assert.Len(t, users14, 2) + + DB.Scopes(WhereLt("age", 18).Scope()).Find(&users15) + assert.Len(t, users15, 0) + + // Ne + var users16, users17, users18 []User + DB.Scopes(WhereNe("age", 20).Scope()).Find(&users16) + assert.Len(t, users16, 3) + + DB.Scopes(WhereNe("age", 22).Scope()).Find(&users17) + assert.Len(t, users17, 2) + + DB.Scopes(WhereNe("age", 18).Scope()).Find(&users18) + assert.Len(t, users18, 3) +} From 84458c2aaef08518912f298769d4fc38f8661378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Sat, 24 Feb 2024 15:24:01 +0800 Subject: [PATCH 12/16] feat(gorm/scope): Added `OrderBy` scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/order.go | 42 +++++++++++++++++++--- gorm/scopes/order_test.go | 74 +++++++++++++++++++++++++++++++++++++++ gorm/scopes/pagination.go | 20 +++++++++++ gorm/scopes/where.go | 4 +++ gorm/scopes/where_test.go | 2 +- 5 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 gorm/scopes/order_test.go diff --git a/gorm/scopes/order.go b/gorm/scopes/order.go index d4bb001d..23a9a24f 100644 --- a/gorm/scopes/order.go +++ b/gorm/scopes/order.go @@ -7,39 +7,73 @@ import ( "gorm.io/gorm" ) +// OrderBy add order by condition +// +// OrderBy("name") +// OrderBy("name", "desc") +// OrderBy("name", "asc") func OrderBy(column string, reorder ...string) *Scopes { return New().OrderBy(column, reorder...) } +// OrderByDesc add order by desc condition +// +// OrderByDesc("name") func OrderByDesc(column string) *Scopes { return New().OrderByDesc(column) } +// OrderByAsc add order by asc condition +// +// OrderByAsc("name") func OrderByAsc(column string) *Scopes { return New().OrderByAsc(column) } -func OrderByRaw(sql string, values ...interface{}) *Scopes { - return New().OrderByRaw(sql, values...) +// OrderByRaw add order by raw condition +// +// OrderByRaw("name desc") +// OrderByRaw("name asc") +// OrderByRaw("name desc, age asc") +// OrderByRaw("FIELD(id, 3, 1, 2)") +func OrderByRaw(sql interface{}) *Scopes { + return New().OrderByRaw(sql) } +// OrderBy add order by condition +// +// OrderBy("name") +// OrderBy("name", "desc") +// OrderBy("name", "asc") func (s *Scopes) OrderBy(column string, reorder ...string) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Order(fmt.Sprintf("%s %s", column, s.buildReorder(reorder...))) }) } +// OrderByDesc add order by desc condition +// +// OrderByDesc("name") func (s *Scopes) OrderByDesc(column string) *Scopes { return s.OrderBy(column, "desc") } +// OrderByAsc add order by asc condition +// +// OrderByAsc("name") func (s *Scopes) OrderByAsc(column string) *Scopes { return s.OrderBy(column, "asc") } -func (s *Scopes) OrderByRaw(sql string, values ...interface{}) *Scopes { +// OrderByRaw add order by raw condition +// +// OrderByRaw("name desc") +// OrderByRaw("name asc") +// OrderByRaw("name desc, age asc") +// OrderByRaw("FIELD(id, 3, 1, 2)") +func (s *Scopes) OrderByRaw(sql interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Order(fmt.Sprintf(sql, values...)) // TODO: 语法待定? + return db.Order(sql) }) } diff --git a/gorm/scopes/order_test.go b/gorm/scopes/order_test.go new file mode 100644 index 00000000..ea57bc7a --- /dev/null +++ b/gorm/scopes/order_test.go @@ -0,0 +1,74 @@ +package scopes + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestOrderBy(t *testing.T) { + birthday1 := time.Now() + birthday2 := time.Now() + birthday3 := time.Now().Add(2 * time.Hour) + birthday4 := time.Now().Add(3 * time.Hour) + users := []*User{ + GetUser("OrderUser1", GetUserOptions{Age: 17, Birthday: &birthday1}), + GetUser("OrderUser2", GetUserOptions{Age: 20, Birthday: &birthday2}), + GetUser("OrderUser3", GetUserOptions{Age: 21, Birthday: &birthday3}), + GetUser("OrderUser4", GetUserOptions{Age: 22, Birthday: &birthday4}), + } + + CleanUsers() + DB.Create(&users) + + // OrderBy + var users1, users2, users3, users4 []User + DB.Scopes(OrderBy("age").Scope()).Limit(2).Find(&users1) + assert.Len(t, users1, 2) + assert.Equal(t, "OrderUser1", users1[0].Name) + assert.Equal(t, "OrderUser2", users1[1].Name) + + DB.Scopes(OrderBy("age", "asc").Scope()).Limit(2).Find(&users2) + assert.Len(t, users2, 2) + assert.Equal(t, "OrderUser1", users2[0].Name) + assert.Equal(t, "OrderUser2", users2[1].Name) + + DB.Scopes(OrderBy("age", "desc").Scope()).Limit(2).Find(&users3) + assert.Len(t, users3, 2) + assert.Equal(t, "OrderUser4", users3[0].Name) + assert.Equal(t, "OrderUser3", users3[1].Name) + + DB.Scopes(OrderBy("age", "unknown").Scope()).Limit(2).Find(&users4) + assert.Len(t, users4, 2) + assert.Equal(t, "OrderUser1", users4[0].Name) + assert.Equal(t, "OrderUser2", users4[1].Name) + + // OrderByAsc + var users5 []User + DB.Scopes(OrderByAsc("age").Scope()).Limit(2).Find(&users5) + assert.Len(t, users5, 2) + assert.Equal(t, "OrderUser1", users5[0].Name) + assert.Equal(t, "OrderUser2", users5[1].Name) + + // OrderByDesc + var users6 []User + DB.Scopes(OrderByDesc("age").Scope()).Limit(2).Find(&users6) + assert.Len(t, users6, 2) + assert.Equal(t, "OrderUser4", users6[0].Name) + assert.Equal(t, "OrderUser3", users6[1].Name) + + // OrderByRaw + var users7 []User + DB.Scopes(OrderByRaw("age % 2 asc").Scope()).Limit(2).Find(&users7) + assert.Len(t, users7, 2) + assert.Equal(t, "OrderUser2", users7[0].Name) + assert.Equal(t, "OrderUser4", users7[1].Name) + + // multiple OrderBy + var users8 []User + DB.Scopes(OrderBy("birthday", "asc").OrderBy("age", "desc").Scope()).Limit(2).Find(&users8) + assert.Len(t, users8, 2) + assert.Equal(t, "OrderUser2", users8[0].Name) + assert.Equal(t, "OrderUser1", users8[1].Name) +} diff --git a/gorm/scopes/pagination.go b/gorm/scopes/pagination.go index e0af4c5c..e1e7f9d3 100644 --- a/gorm/scopes/pagination.go +++ b/gorm/scopes/pagination.go @@ -4,6 +4,26 @@ import ( "gorm.io/gorm" ) +func (s *Scopes) Skip(offset int) *Scopes { + return s.Offset(offset) +} + +func (s *Scopes) Offset(offset int) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Offset(offset) + }) +} + +func (s *Scopes) Limit(limit int) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Limit(limit) + }) +} + +func (s *Scopes) Take(limit int) *Scopes { + return s.Limit(limit) +} + func (s *Scopes) Page(page, pageSize int) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Offset((page - 1) * pageSize).Limit(pageSize) diff --git a/gorm/scopes/where.go b/gorm/scopes/where.go index 0b857663..33fef7b0 100644 --- a/gorm/scopes/where.go +++ b/gorm/scopes/where.go @@ -110,6 +110,10 @@ func WhereNe(field string, value interface{}) *Scopes { return New().WhereNe(field, value) } +func WhereNot(query interface{}, args ...interface{}) *Scopes { + return New().WhereNot(query, args...) +} + // Where add where condition // // Where("name = ?", "Flc") diff --git a/gorm/scopes/where_test.go b/gorm/scopes/where_test.go index 0deb2e44..d8957c97 100644 --- a/gorm/scopes/where_test.go +++ b/gorm/scopes/where_test.go @@ -72,7 +72,7 @@ func TestWhere_In(t *testing.T) { DB.Create(&users) var users1, users2, users3 []User - DB.Scopes(WhereIn("name", "WhereInUser1", "WhereInUser2").Scope()).Find(&users1) + DB.Debug().Scopes(WhereIn("name", "WhereInUser1", "WhereInUser2").Scope()).Find(&users1) assert.Len(t, users1, 2) DB.Scopes(WhereIn("age", []int{18, 20}).Scope()).Find(&users2) From ecc6624d66c5c4f1b8798d26637814352c3eeda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Sat, 24 Feb 2024 15:39:36 +0800 Subject: [PATCH 13/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/basic.go | 9 +++++++ gorm/scopes/trait.go | 16 +++++++++++ gorm/scopes/trait_test.go | 57 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 gorm/scopes/basic.go create mode 100644 gorm/scopes/trait_test.go diff --git a/gorm/scopes/basic.go b/gorm/scopes/basic.go new file mode 100644 index 00000000..5c56fbac --- /dev/null +++ b/gorm/scopes/basic.go @@ -0,0 +1,9 @@ +package scopes + +import "gorm.io/gorm" + +func (s *Scopes) Select(query interface{}, args ...interface{}) *Scopes { + return s.Add(func(db *gorm.DB) *gorm.DB { + return db.Select(query, args...) + }) +} diff --git a/gorm/scopes/trait.go b/gorm/scopes/trait.go index f829ed6c..b78ffb8d 100644 --- a/gorm/scopes/trait.go +++ b/gorm/scopes/trait.go @@ -2,14 +2,26 @@ package scopes import "gorm.io/gorm" +// When if condition is true, apply the scopes +// +// When(true, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) +// When(false, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) func When(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { return New().When(condition, f) } +// Unless if condition is false, apply the scopes +// +// Unless(false, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) +// Unless(true, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) func Unless(condition bool, f func(db *gorm.DB) *gorm.DB) *Scopes { return New().Unless(condition, f) } +// When if condition is true, apply the scopes +// +// When(true, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) +// When(false, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) func (s *Scopes) When(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { if condition { return s.Add(fc) @@ -17,6 +29,10 @@ func (s *Scopes) When(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { return s } +// Unless if condition is false, apply the scopes +// +// Unless(false, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) +// Unless(true, func(db *gorm.DB) *gorm.DB { return db.Where("name = ?", "Flc") }) func (s *Scopes) Unless(condition bool, fc func(*gorm.DB) *gorm.DB) *Scopes { return s.When(!condition, fc) } diff --git a/gorm/scopes/trait_test.go b/gorm/scopes/trait_test.go new file mode 100644 index 00000000..2dcea6ab --- /dev/null +++ b/gorm/scopes/trait_test.go @@ -0,0 +1,57 @@ +package scopes + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +func TestTrait(t *testing.T) { + users := []*User{ + GetUser("TraitWhenUser1", GetUserOptions{Age: 18}), + GetUser("TraitWhenUser2", GetUserOptions{Age: 20}), + GetUser("TraitWhenUser3", GetUserOptions{Age: 22}), + } + + CleanUsers() + DB.Create(&users) + + // When + var users1, users2 []User + DB.Scopes(When(true, func(db *gorm.DB) *gorm.DB { + return db.Where("age > ?", 18) + }).Scope()).Find(&users1) + assert.Len(t, users1, 2) + assert.Equal(t, "TraitWhenUser2", users1[0].Name) + assert.Equal(t, "TraitWhenUser3", users1[1].Name) + + DB.Scopes(When(false, func(db *gorm.DB) *gorm.DB { + return db.Where("age > ?", 18) + }).Scope()).Find(&users2) + assert.Len(t, users2, 3) + + // Unless + var users3, users4 []User + DB.Scopes(Unless(true, func(db *gorm.DB) *gorm.DB { + return db.Where("age > ?", 18) + }).Scope()).Find(&users3) + assert.Len(t, users3, 3) + + DB.Scopes(Unless(false, func(db *gorm.DB) *gorm.DB { + return db.Where("age > ?", 18) + }).Scope()).Find(&users4) + assert.Len(t, users4, 2) + assert.Equal(t, "TraitWhenUser2", users4[0].Name) + assert.Equal(t, "TraitWhenUser3", users4[1].Name) + + // multiple When and Unless + var users5 []User + DB.Scopes(When(true, func(db *gorm.DB) *gorm.DB { + return db.Where("age > ?", 18) + }).Unless(false, func(db *gorm.DB) *gorm.DB { + return db.Where("age < ?", 22) + }).Scope()).Find(&users5) + assert.Len(t, users5, 1) + assert.Equal(t, "TraitWhenUser2", users5[0].Name) +} From 9fa06fd29f2b79d0c5e5df61815c27b6313d3262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Sat, 24 Feb 2024 15:46:11 +0800 Subject: [PATCH 14/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/scopes_test.go | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 gorm/scopes/scopes_test.go diff --git a/gorm/scopes/scopes_test.go b/gorm/scopes/scopes_test.go new file mode 100644 index 00000000..d90d094c --- /dev/null +++ b/gorm/scopes/scopes_test.go @@ -0,0 +1,42 @@ +package scopes + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +func TestScopes(t *testing.T) { + users := []*User{ + GetUser("ScopeUser1", GetUserOptions{}), + GetUser("ScopeUser2", GetUserOptions{}), + GetUser("ScopeUser3", GetUserOptions{}), + } + + scopes := New().Add(func(db *gorm.DB) *gorm.DB { + return db.Where("name in (?)", []string{"ScopeUser1", "ScopeUser2"}) + }) + + CleanUsers() + DB.Create(&users) + + var users1, users2, users3, users4 []User + + // Scope/Add + DB.Scopes(scopes.Scope()).Find(&users1) + assert.Len(t, users1, 2) + assert.Equal(t, "ScopeUser1", users1[0].Name) + assert.Equal(t, "ScopeUser2", users1[1].Name) + + // Apply + scopes.Apply(DB).Find(&users2) + assert.Len(t, users2, 2) + + DB.Scopes(scopes.Apply).Find(&users3) + assert.Len(t, users3, 2) + + // Scopes + DB.Scopes(scopes.Scopes()...).Find(&users4) + assert.Len(t, users4, 2) +} From 6afd2d98f6a654a68c745e989f38c57f950a9f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Sat, 24 Feb 2024 16:06:58 +0800 Subject: [PATCH 15/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/README.md | 66 +++++++++++++++++++++++++++++++++++++++ gorm/scopes/pagination.go | 4 +-- 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 gorm/scopes/README.md diff --git a/gorm/scopes/README.md b/gorm/scopes/README.md new file mode 100644 index 00000000..42298182 --- /dev/null +++ b/gorm/scopes/README.md @@ -0,0 +1,66 @@ +# Gorm/Scopes + +## Example + +```go +package main + +import ( + "time" + + "gorm.io/gorm" + + "github.com/go-kratos-ecosystem/components/v2/gorm/scopes" +) + +func main() { + var db *gorm.DB + + db.Scopes(scopes. + // trait + When(true, func(db *gorm.DB) *gorm.DB { + return db.Where("deleted_at IS NULL") + }). + Unless(true, func(db *gorm.DB) *gorm.DB { + return db.Where("deleted_at IS NOT NULL") + }). + + // Where + Where("name = ?", "Flc"). + WhereBetween("created_at", time.Now(), time.Now()). + WhereNotBetween("created_at", time.Now(), time.Now()). + WhereIn("name", "Flc", "Flc 2"). + WhereNotIn("name", "Flc", "Flc 2"). + WhereLike("name", "Flc%"). + WhereNotLike("name", "Flc%"). + WhereEq("name", "Flc"). + WhereNe("name", "Flc"). + WhereGt("age", 18). + WhereEgt("age", 18). + WhereLt("age", 18). + WhereElt("age", 18). + + // Order + OrderBy("id"). + OrderBy("id", "desc"). + OrderBy("id", "asc"). + OrderByDesc("id"). + OrderByAsc("id"). + OrderByRaw("id desc"). + + // Limit + Limit(10). + Take(10). + + // Offset + Offset(10). + Skip(10). + + // Page + Page(1, 20). + + // To Scope() + Scope()). + Find(&[]struct{}{}) +} +``` \ No newline at end of file diff --git a/gorm/scopes/pagination.go b/gorm/scopes/pagination.go index e1e7f9d3..699b9d8f 100644 --- a/gorm/scopes/pagination.go +++ b/gorm/scopes/pagination.go @@ -24,9 +24,9 @@ func (s *Scopes) Take(limit int) *Scopes { return s.Limit(limit) } -func (s *Scopes) Page(page, pageSize int) *Scopes { +func (s *Scopes) Page(page, prePage int) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Offset((page - 1) * pageSize).Limit(pageSize) + return db.Offset((page - 1) * prePage).Limit(prePage) }) } From 8c812252f39e8fe21d76f8d1be40caf6cd8b7ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Flc=E3=82=9B?= Date: Sat, 24 Feb 2024 18:17:39 +0800 Subject: [PATCH 16/16] feat(gorm/scope): Added scope method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Flc゛ --- gorm/scopes/basic.go | 9 ------ gorm/scopes/init_test.go | 6 ++++ gorm/scopes/pagination.go | 58 +++++++++++++++++++++++++++++++--- gorm/scopes/pagination_test.go | 51 ++++++++++++++++++++++++++++++ gorm/scopes/where.go | 32 +++++++++++++++++-- gorm/scopes/where_test.go | 43 +++++++++++++++++++++++++ 6 files changed, 183 insertions(+), 16 deletions(-) delete mode 100644 gorm/scopes/basic.go create mode 100644 gorm/scopes/pagination_test.go diff --git a/gorm/scopes/basic.go b/gorm/scopes/basic.go deleted file mode 100644 index 5c56fbac..00000000 --- a/gorm/scopes/basic.go +++ /dev/null @@ -1,9 +0,0 @@ -package scopes - -import "gorm.io/gorm" - -func (s *Scopes) Select(query interface{}, args ...interface{}) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Select(query, args...) - }) -} diff --git a/gorm/scopes/init_test.go b/gorm/scopes/init_test.go index 731c6fa0..60e4dd71 100644 --- a/gorm/scopes/init_test.go +++ b/gorm/scopes/init_test.go @@ -20,6 +20,7 @@ type User struct { Age uint `gorm:"column:age"` Sex string `gorm:"column:sex"` Birthday *time.Time `gorm:"column:birthday"` + Address *string `gorm:"column:address"` } func init() { @@ -58,6 +59,7 @@ func runMigrations() { type GetUserOptions struct { Age int Birthday *time.Time + Address *string } func GetUser(name string, opts GetUserOptions) *User { @@ -78,6 +80,10 @@ func GetUser(name string, opts GetUserOptions) *User { user.Birthday = opts.Birthday } + if opts.Address != nil { + user.Address = opts.Address + } + return &user } diff --git a/gorm/scopes/pagination.go b/gorm/scopes/pagination.go index 699b9d8f..d29650f2 100644 --- a/gorm/scopes/pagination.go +++ b/gorm/scopes/pagination.go @@ -4,30 +4,78 @@ import ( "gorm.io/gorm" ) -func (s *Scopes) Skip(offset int) *Scopes { - return s.Offset(offset) +// Offset add offset condition +// +// Offset(3) +func Offset(offset int) *Scopes { + return New().Offset(offset) +} + +// Skip add offset condition +// +// Skip(3) +func Skip(offset int) *Scopes { + return New().Skip(offset) +} + +// Limit add limit condition +// +// Limit(3) +func Limit(limit int) *Scopes { + return New().Limit(limit) +} + +// Take add limit condition +// +// Take(3) +func Take(limit int) *Scopes { + return New().Take(limit) +} + +// Page add page condition +// +// Page(2, 10) +func Page(page, prePage int) *Scopes { + return New().Page(page, prePage) } +// Offset add offset condition +// +// Offset(3) func (s *Scopes) Offset(offset int) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Offset(offset) }) } +// Skip add offset condition +// +// Skip(3) +func (s *Scopes) Skip(offset int) *Scopes { + return s.Offset(offset) +} + +// Limit add limit condition +// +// Limit(3) func (s *Scopes) Limit(limit int) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Limit(limit) }) } +// Take add limit condition +// +// Take(3) func (s *Scopes) Take(limit int) *Scopes { return s.Limit(limit) } +// Page add page condition +// +// Page(2, 10) func (s *Scopes) Page(page, prePage int) *Scopes { - return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Offset((page - 1) * prePage).Limit(prePage) - }) + return s.Limit(prePage).Offset((page - 1) * prePage) } // Paginate TODO: 未实现 diff --git a/gorm/scopes/pagination_test.go b/gorm/scopes/pagination_test.go new file mode 100644 index 00000000..d8547d7b --- /dev/null +++ b/gorm/scopes/pagination_test.go @@ -0,0 +1,51 @@ +package scopes + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPagination(t *testing.T) { + users := []*User{ + GetUser("PaginationUser1", GetUserOptions{}), + GetUser("PaginationUser2", GetUserOptions{}), + GetUser("PaginationUser3", GetUserOptions{}), + GetUser("PaginationUser4", GetUserOptions{}), + GetUser("PaginationUser5", GetUserOptions{}), + } + + CleanUsers() + DB.Create(&users) + + var users1, users2, users3, users4, users5, users6 []User + + // Offset&Limit + DB.Scopes(Offset(2).Limit(2).Scope()).Find(&users1) + assert.Len(t, users1, 2) + assert.Equal(t, "PaginationUser3", users1[0].Name) + assert.Equal(t, "PaginationUser4", users1[1].Name) + + DB.Scopes(Limit(2).Skip(4).Scope()).Find(&users2) + assert.Len(t, users2, 1) + assert.Equal(t, "PaginationUser5", users2[0].Name) + + // Skip&Take + DB.Scopes(Skip(2).Take(2).Scope()).Find(&users3) + assert.Len(t, users3, 2) + assert.Equal(t, "PaginationUser3", users3[0].Name) + assert.Equal(t, "PaginationUser4", users3[1].Name) + + DB.Scopes(Take(2).Skip(4).Scope()).Find(&users4) + assert.Len(t, users4, 1) + assert.Equal(t, "PaginationUser5", users4[0].Name) + + // Page + DB.Scopes(Page(2, 2).Scope()).Find(&users5) + assert.Len(t, users5, 2) + assert.Equal(t, "PaginationUser3", users5[0].Name) + + DB.Scopes(Page(3, 2).Scope()).Find(&users6) + assert.Len(t, users6, 1) + assert.Equal(t, "PaginationUser5", users6[0].Name) +} diff --git a/gorm/scopes/where.go b/gorm/scopes/where.go index 33fef7b0..c8152eed 100644 --- a/gorm/scopes/where.go +++ b/gorm/scopes/where.go @@ -110,10 +110,28 @@ func WhereNe(field string, value interface{}) *Scopes { return New().WhereNe(field, value) } +// WhereNot add where not condition +// +// WhereNot("name = ?", "Flc") +// WhereNot("name = ? AND age = ?", "Flc", 20) func WhereNot(query interface{}, args ...interface{}) *Scopes { return New().WhereNot(query, args...) } +// WhereNull add where null condition +// +// WhereNull("name") +func WhereNull(field string) *Scopes { + return New().WhereNull(field) +} + +// WhereNotNull add where not null condition +// +// WhereNotNull("name") +func WhereNotNull(field string) *Scopes { + return New().WhereNotNull(field) +} + // Where add where condition // // Where("name = ?", "Flc") @@ -250,20 +268,30 @@ func (s *Scopes) WhereNe(column string, value interface{}) *Scopes { }) } +// WhereNot add where not condition +// +// WhereNot("name = ?", "Flc") +// WhereNot("name = ? AND age = ?", "Flc", 20) func (s *Scopes) WhereNot(query interface{}, args ...interface{}) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { return db.Not(query, args...) }) } +// WhereNull add where null condition +// +// WhereNull("name") func (s *Scopes) WhereNull(column string) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? IS NULL", column) + return db.Where(fmt.Sprintf("%s IS NULL", column)) }) } +// WhereNotNull add where not null condition +// +// WhereNotNull("name") func (s *Scopes) WhereNotNull(column string) *Scopes { return s.Add(func(db *gorm.DB) *gorm.DB { - return db.Where("? IS NOT NULL", column) + return db.Where(fmt.Sprintf("%s IS NOT NULL", column)) }) } diff --git a/gorm/scopes/where_test.go b/gorm/scopes/where_test.go index d8957c97..90fcebf7 100644 --- a/gorm/scopes/where_test.go +++ b/gorm/scopes/where_test.go @@ -213,3 +213,46 @@ func TestWhere_OP(t *testing.T) { DB.Scopes(WhereNe("age", 18).Scope()).Find(&users18) assert.Len(t, users18, 3) } + +func TestWhere_WhereNot(t *testing.T) { + users := []*User{ + GetUser("WhereLikeUser1", GetUserOptions{Age: 18}), + GetUser("WhereLikeUser2", GetUserOptions{Age: 20}), + GetUser("WhereLikeUser3", GetUserOptions{Age: 22}), + } + + CleanUsers() + DB.Create(&users) + + var users1 []User + DB.Scopes(WhereNot("name = ?", "WhereLikeUser1").Scope()).Find(&users1) + assert.Len(t, users1, 2) + assert.Equal(t, "WhereLikeUser2", users1[0].Name) + assert.Equal(t, "WhereLikeUser3", users1[1].Name) +} + +func TestWhere_Null(t *testing.T) { + address2 := "WhereNullAddress2" + address3 := "WhereNullAddress3" + users := []*User{ + GetUser("WhereNullUser1", GetUserOptions{Age: 18, Address: nil}), + GetUser("WhereNullUser2", GetUserOptions{Age: 20, Address: &address2}), + GetUser("WhereNullUser3", GetUserOptions{Age: 22, Address: &address3}), + } + + CleanUsers() + DB.Create(&users) + + // Null + var users1 []User + DB.Scopes(WhereNull("address").Scope()).Find(&users1) + assert.Len(t, users1, 1) + assert.Equal(t, "WhereNullUser1", users1[0].Name) + + // NotNull + var users2 []User + DB.Scopes(WhereNotNull("address").Scope()).Find(&users2) + assert.Len(t, users2, 2) + assert.Equal(t, "WhereNullUser2", users2[0].Name) + assert.Equal(t, "WhereNullUser3", users2[1].Name) +}