package db import ( "errors" "gorm.io/gorm" "gorm.io/gorm/clause" ) type UpdateBuilder[T any] struct { Expr db *gorm.DB selects []string omits []string onConflict *clause.OnConflict } func NewUpdateBuilder[T any](db *gorm.DB) *UpdateBuilder[T] { return &UpdateBuilder[T]{Expr: Expr{}, db: db} } func (b *UpdateBuilder[T]) Select(columns ...string) *UpdateBuilder[T] { b.selects = append(b.selects, columns...) return b } func (b *UpdateBuilder[T]) Omit(columns ...string) *UpdateBuilder[T] { b.omits = append(b.omits, columns...) return b } func (b *UpdateBuilder[T]) OnConflict(conflict clause.OnConflict) *UpdateBuilder[T] { if b.onConflict == nil { b.onConflict = &conflict } else { b.onConflict.Columns = conflict.Columns b.onConflict.Where = conflict.Where b.onConflict.TargetWhere = conflict.TargetWhere b.onConflict.OnConstraint = conflict.OnConstraint b.onConflict.DoNothing = conflict.DoNothing b.onConflict.DoUpdates = conflict.DoUpdates b.onConflict.UpdateAll = conflict.UpdateAll } return b } func (b *UpdateBuilder[T]) Scopes(tx *gorm.DB) *gorm.DB { if b.selects != nil { tx = tx.Select(b.selects) } if b.omits != nil { tx = tx.Omit(b.omits...) } return b.Expr.Scopes(tx) } func (b *UpdateBuilder[T]) Commit(values map[string]any) (int64, error) { var entity T res := b.db.Model(&entity).Scopes(b.Scopes).Updates(values) if err := res.Error; err != nil { return res.RowsAffected, err } if res.RowsAffected == 0 { return 0, errors.New("no record updated") } return res.RowsAffected, nil }