feat(db): 将 Expr 上的方法扩展到不同的构造器上面

main
熊二 1 year ago
parent e18ec70269
commit 1b27c50a90
  1. 104
      pkg/db/delete_builder.go
  2. 4
      pkg/db/expr.go
  3. 96
      pkg/db/query_builder.go
  4. 16
      pkg/db/repository.go
  5. 144
      pkg/db/update_builder.go

@ -1,18 +1,110 @@
package db package db
import "gorm.io/gorm" import (
"gorm.io/gorm"
)
type DeleteBuilder[T any] struct { type DeleteBuilder[T any] struct {
Expr db *gorm.DB
db *gorm.DB expr *Expr
} }
func NewDeleteBuilder[T any](db *gorm.DB) *DeleteBuilder[T] { func NewDeleteBuilder[T any](db *gorm.DB) *DeleteBuilder[T] {
return &DeleteBuilder[T]{Expr{}, db} return &DeleteBuilder[T]{db: db, expr: &Expr{}}
} }
func (b *DeleteBuilder[T]) Commit() (int64, error) { func (d *DeleteBuilder[T]) Eq(col string, val any) *DeleteBuilder[T] {
d.expr.Eq(col, val)
return d
}
func (d *DeleteBuilder[T]) Neq(col string, val any) *DeleteBuilder[T] {
d.expr.Neq(col, val)
return d
}
func (d *DeleteBuilder[T]) Lt(col string, val any) *DeleteBuilder[T] {
d.expr.Lt(col, val)
return d
}
func (d *DeleteBuilder[T]) Lte(col string, val any) *DeleteBuilder[T] {
d.expr.Lte(col, val)
return d
}
func (d *DeleteBuilder[T]) Gt(col string, val any) *DeleteBuilder[T] {
d.expr.Gt(col, val)
return d
}
func (d *DeleteBuilder[T]) Gte(col string, val any) *DeleteBuilder[T] {
d.expr.Gte(col, val)
return d
}
func (d *DeleteBuilder[T]) Between(col string, less, more any) *DeleteBuilder[T] {
d.expr.Between(col, less, more)
return d
}
func (d *DeleteBuilder[T]) NotBetween(col string, less, more any) *DeleteBuilder[T] {
d.expr.NotBetween(col, less, more)
return d
}
func (d *DeleteBuilder[T]) IsNull(col string) *DeleteBuilder[T] {
d.expr.IsNull(col)
return d
}
func (d *DeleteBuilder[T]) NotNull(col string) *DeleteBuilder[T] {
d.expr.NotNull(col)
return d
}
func (d *DeleteBuilder[T]) Like(col, tpl string) *DeleteBuilder[T] {
d.expr.Like(col, tpl)
return d
}
func (d *DeleteBuilder[T]) NotLike(col, tpl string) *DeleteBuilder[T] {
d.expr.NotLike(col, tpl)
return d
}
func (d *DeleteBuilder[T]) In(col string, values ...any) *DeleteBuilder[T] {
d.expr.In(col, values...)
return d
}
func (d *DeleteBuilder[T]) NotIn(col string, values ...any) *DeleteBuilder[T] {
d.expr.NotIn(col, values...)
return d
}
func (d *DeleteBuilder[T]) When(condition bool, then func(ex *Expr), elses ...func(ex *Expr)) *DeleteBuilder[T] {
d.expr.When(condition, then, elses...)
return d
}
func (d *DeleteBuilder[T]) Or(or func(ex *Expr)) *DeleteBuilder[T] {
d.expr.Or(or)
return d
}
func (d *DeleteBuilder[T]) And(and func(ex *Expr)) *DeleteBuilder[T] {
d.expr.And(and)
return d
}
func (d *DeleteBuilder[T]) Not(not func(ex *Expr)) *DeleteBuilder[T] {
d.expr.Not(not)
return d
}
func (d *DeleteBuilder[T]) Commit() (int64, error) {
var t T var t T
res := b.db.Scopes(b.Scopes).Delete(&t) res := d.db.Scopes(d.expr.Scopes).Delete(&t)
return res.RowsAffected, res.Error return res.RowsAffected, res.Error
} }

@ -9,6 +9,10 @@ type Expr struct {
clauses []clause.Expression clauses []clause.Expression
} }
func NewExpr() *Expr {
return &Expr{}
}
func (e *Expr) add(expr clause.Expression) *Expr { func (e *Expr) add(expr clause.Expression) *Expr {
e.clauses = append(e.clauses, expr) e.clauses = append(e.clauses, expr)
return e return e

@ -9,10 +9,10 @@ import (
// QueryBuilder 查询构造器 // QueryBuilder 查询构造器
// TODO(hupeh):实现 joins 和表别名 // TODO(hupeh):实现 joins 和表别名
type QueryBuilder[T any] struct { type QueryBuilder[T any] struct {
Expr
db *gorm.DB db *gorm.DB
selects []string selects []string
omits []string omits []string
expr *Expr
orders []string orders []string
limit int limit int
offset int offset int
@ -21,7 +21,7 @@ type QueryBuilder[T any] struct {
} }
func NewQueryBuilder[T any](db *gorm.DB) *QueryBuilder[T] { func NewQueryBuilder[T any](db *gorm.DB) *QueryBuilder[T] {
return &QueryBuilder[T]{Expr: Expr{}, db: db} return &QueryBuilder[T]{expr: &Expr{}, db: db}
} }
type preload struct { type preload struct {
@ -46,6 +46,96 @@ func (q *QueryBuilder[T]) Omit(columns ...string) *QueryBuilder[T] {
return q return q
} }
func (q *QueryBuilder[T]) Eq(col string, val any) *QueryBuilder[T] {
q.expr.Eq(col, val)
return q
}
func (q *QueryBuilder[T]) Neq(col string, val any) *QueryBuilder[T] {
q.expr.Neq(col, val)
return q
}
func (q *QueryBuilder[T]) Lt(col string, val any) *QueryBuilder[T] {
q.expr.Lt(col, val)
return q
}
func (q *QueryBuilder[T]) Lte(col string, val any) *QueryBuilder[T] {
q.expr.Lte(col, val)
return q
}
func (q *QueryBuilder[T]) Gt(col string, val any) *QueryBuilder[T] {
q.expr.Gt(col, val)
return q
}
func (q *QueryBuilder[T]) Gte(col string, val any) *QueryBuilder[T] {
q.expr.Gte(col, val)
return q
}
func (q *QueryBuilder[T]) Between(col string, less, more any) *QueryBuilder[T] {
q.expr.Between(col, less, more)
return q
}
func (q *QueryBuilder[T]) NotBetween(col string, less, more any) *QueryBuilder[T] {
q.expr.NotBetween(col, less, more)
return q
}
func (q *QueryBuilder[T]) IsNull(col string) *QueryBuilder[T] {
q.expr.IsNull(col)
return q
}
func (q *QueryBuilder[T]) NotNull(col string) *QueryBuilder[T] {
q.expr.NotNull(col)
return q
}
func (q *QueryBuilder[T]) Like(col, tpl string) *QueryBuilder[T] {
q.expr.Like(col, tpl)
return q
}
func (q *QueryBuilder[T]) NotLike(col, tpl string) *QueryBuilder[T] {
q.expr.NotLike(col, tpl)
return q
}
func (q *QueryBuilder[T]) In(col string, values ...any) *QueryBuilder[T] {
q.expr.In(col, values...)
return q
}
func (q *QueryBuilder[T]) NotIn(col string, values ...any) *QueryBuilder[T] {
q.expr.NotIn(col, values...)
return q
}
func (q *QueryBuilder[T]) When(condition bool, then func(ex *Expr), elses ...func(ex *Expr)) *QueryBuilder[T] {
q.expr.When(condition, then, elses...)
return q
}
func (q *QueryBuilder[T]) Or(or func(ex *Expr)) *QueryBuilder[T] {
q.expr.Or(or)
return q
}
func (q *QueryBuilder[T]) And(and func(ex *Expr)) *QueryBuilder[T] {
q.expr.And(and)
return q
}
func (q *QueryBuilder[T]) Not(not func(ex *Expr)) *QueryBuilder[T] {
q.expr.Not(not)
return q
}
func (q *QueryBuilder[T]) DescentBy(columns ...string) *QueryBuilder[T] { func (q *QueryBuilder[T]) DescentBy(columns ...string) *QueryBuilder[T] {
for _, col := range columns { for _, col := range columns {
q.orders = append(q.orders, col+" DESC") q.orders = append(q.orders, col+" DESC")
@ -113,7 +203,7 @@ func (q *QueryBuilder[T]) scopesWithoutEffect(tx *gorm.DB) *gorm.DB {
if len(q.distinct) > 0 { if len(q.distinct) > 0 {
tx = tx.Distinct(q.distinct...) tx = tx.Distinct(q.distinct...)
} }
return q.Expr.Scopes(tx) return q.expr.Scopes(tx)
} }
func (q *QueryBuilder[T]) Count() (int64, error) { func (q *QueryBuilder[T]) Count() (int64, error) {

@ -70,6 +70,20 @@ func (r *Repository[T]) GetByID(ctx context.Context, id any) (*T, error) {
return &entity, nil return &entity, nil
} }
func (r *Repository[T]) GetBy(ctx context.Context, expr ...*Expr) (*T, error) {
var entity T
err := r.DB(ctx).Model(&entity).Scopes(func(tx *gorm.DB) *gorm.DB {
for _, e := range expr {
tx = e.Scopes(tx)
}
return tx
}).First(&entity).Error
if err != nil {
return nil, err
}
return &entity, nil
}
func (r *Repository[T]) Find(ctx context.Context, expr ...*Expr) ([]*T, error) { func (r *Repository[T]) Find(ctx context.Context, expr ...*Expr) ([]*T, error) {
var entity T var entity T
var items []*T var items []*T
@ -88,7 +102,7 @@ func (r *Repository[T]) Find(ctx context.Context, expr ...*Expr) ([]*T, error) {
func (r *Repository[T]) Paginate(ctx context.Context, expr ...*Expr) (*Pager[T], error) { func (r *Repository[T]) Paginate(ctx context.Context, expr ...*Expr) (*Pager[T], error) {
qb := NewQueryBuilder[T](r.DB(ctx)) qb := NewQueryBuilder[T](r.DB(ctx))
for _, e := range expr { for _, e := range expr {
qb.Expr = *e qb.expr = e
} }
return qb.Paginate() return qb.Paginate()
} }

@ -7,55 +7,145 @@ import (
) )
type UpdateBuilder[T any] struct { type UpdateBuilder[T any] struct {
Expr
db *gorm.DB db *gorm.DB
selects []string selects []string
omits []string omits []string
onConflict *clause.OnConflict onConflict *clause.OnConflict
expr *Expr
} }
func NewUpdateBuilder[T any](db *gorm.DB) *UpdateBuilder[T] { func NewUpdateBuilder[T any](db *gorm.DB) *UpdateBuilder[T] {
return &UpdateBuilder[T]{Expr: Expr{}, db: db} return &UpdateBuilder[T]{expr: &Expr{}, db: db}
} }
func (b *UpdateBuilder[T]) Select(columns ...string) *UpdateBuilder[T] { func (u *UpdateBuilder[T]) Select(columns ...string) *UpdateBuilder[T] {
b.selects = append(b.selects, columns...) u.selects = append(u.selects, columns...)
return b return u
} }
func (b *UpdateBuilder[T]) Omit(columns ...string) *UpdateBuilder[T] { func (u *UpdateBuilder[T]) Omit(columns ...string) *UpdateBuilder[T] {
b.omits = append(b.omits, columns...) u.omits = append(u.omits, columns...)
return b return u
} }
func (b *UpdateBuilder[T]) OnConflict(conflict clause.OnConflict) *UpdateBuilder[T] { func (u *UpdateBuilder[T]) Eq(col string, val any) *UpdateBuilder[T] {
if b.onConflict == nil { u.expr.Eq(col, val)
b.onConflict = &conflict return u
}
func (u *UpdateBuilder[T]) Neq(col string, val any) *UpdateBuilder[T] {
u.expr.Neq(col, val)
return u
}
func (u *UpdateBuilder[T]) Lt(col string, val any) *UpdateBuilder[T] {
u.expr.Lt(col, val)
return u
}
func (u *UpdateBuilder[T]) Lte(col string, val any) *UpdateBuilder[T] {
u.expr.Lte(col, val)
return u
}
func (u *UpdateBuilder[T]) Gt(col string, val any) *UpdateBuilder[T] {
u.expr.Gt(col, val)
return u
}
func (u *UpdateBuilder[T]) Gte(col string, val any) *UpdateBuilder[T] {
u.expr.Gte(col, val)
return u
}
func (u *UpdateBuilder[T]) Between(col string, less, more any) *UpdateBuilder[T] {
u.expr.Between(col, less, more)
return u
}
func (u *UpdateBuilder[T]) NotBetween(col string, less, more any) *UpdateBuilder[T] {
u.expr.NotBetween(col, less, more)
return u
}
func (u *UpdateBuilder[T]) IsNull(col string) *UpdateBuilder[T] {
u.expr.IsNull(col)
return u
}
func (u *UpdateBuilder[T]) NotNull(col string) *UpdateBuilder[T] {
u.expr.NotNull(col)
return u
}
func (u *UpdateBuilder[T]) Like(col, tpl string) *UpdateBuilder[T] {
u.expr.Like(col, tpl)
return u
}
func (u *UpdateBuilder[T]) NotLike(col, tpl string) *UpdateBuilder[T] {
u.expr.NotLike(col, tpl)
return u
}
func (u *UpdateBuilder[T]) In(col string, values ...any) *UpdateBuilder[T] {
u.expr.In(col, values...)
return u
}
func (u *UpdateBuilder[T]) NotIn(col string, values ...any) *UpdateBuilder[T] {
u.expr.NotIn(col, values...)
return u
}
func (u *UpdateBuilder[T]) When(condition bool, then func(ex *Expr), elses ...func(ex *Expr)) *UpdateBuilder[T] {
u.expr.When(condition, then, elses...)
return u
}
func (u *UpdateBuilder[T]) Or(or func(ex *Expr)) *UpdateBuilder[T] {
u.expr.Or(or)
return u
}
func (u *UpdateBuilder[T]) And(and func(ex *Expr)) *UpdateBuilder[T] {
u.expr.And(and)
return u
}
func (u *UpdateBuilder[T]) Not(not func(ex *Expr)) *UpdateBuilder[T] {
u.expr.Not(not)
return u
}
func (u *UpdateBuilder[T]) OnConflict(conflict clause.OnConflict) *UpdateBuilder[T] {
if u.onConflict == nil {
u.onConflict = &conflict
} else { } else {
b.onConflict.Columns = conflict.Columns u.onConflict.Columns = conflict.Columns
b.onConflict.Where = conflict.Where u.onConflict.Where = conflict.Where
b.onConflict.TargetWhere = conflict.TargetWhere u.onConflict.TargetWhere = conflict.TargetWhere
b.onConflict.OnConstraint = conflict.OnConstraint u.onConflict.OnConstraint = conflict.OnConstraint
b.onConflict.DoNothing = conflict.DoNothing u.onConflict.DoNothing = conflict.DoNothing
b.onConflict.DoUpdates = conflict.DoUpdates u.onConflict.DoUpdates = conflict.DoUpdates
b.onConflict.UpdateAll = conflict.UpdateAll u.onConflict.UpdateAll = conflict.UpdateAll
} }
return b return u
} }
func (b *UpdateBuilder[T]) Scopes(tx *gorm.DB) *gorm.DB { func (u *UpdateBuilder[T]) Scopes(tx *gorm.DB) *gorm.DB {
if b.selects != nil { if u.selects != nil {
tx = tx.Select(b.selects) tx = tx.Select(u.selects)
} }
if b.omits != nil { if u.omits != nil {
tx = tx.Omit(b.omits...) tx = tx.Omit(u.omits...)
} }
return b.Expr.Scopes(tx) return u.expr.Scopes(tx)
} }
func (b *UpdateBuilder[T]) Commit(values map[string]any) (int64, error) { func (u *UpdateBuilder[T]) Commit(values map[string]any) (int64, error) {
var entity T var entity T
res := b.db.Model(&entity).Scopes(b.Scopes).Updates(values) res := u.db.Model(&entity).Scopes(u.Scopes).Updates(values)
if err := res.Error; err != nil { if err := res.Error; err != nil {
return res.RowsAffected, err return res.RowsAffected, err
} }

Loading…
Cancel
Save