301 lines
8.8 KiB
Go
301 lines
8.8 KiB
Go
// Package database ...
|
||
//
|
||
// Author : go_developer@163.com<白茶清欢>
|
||
//
|
||
// Date : 8:04 下午 2021/8/8
|
||
package database
|
||
|
||
import (
|
||
"errors"
|
||
"reflect"
|
||
|
||
"git.zhangdeman.cn/zhangdeman/database/define"
|
||
"gorm.io/gorm"
|
||
"gorm.io/gorm/clause"
|
||
)
|
||
|
||
func NewBaseDao[DatabaseDataType any, DatabaseTableColumns any]() *BaseDao[DatabaseDataType, DatabaseTableColumns] {
|
||
res := &BaseDao[DatabaseDataType, DatabaseTableColumns]{}
|
||
res.tableName = res.TableName()
|
||
res.columns = res.Columns()
|
||
res.isSetColumns = true
|
||
res.columnComment = res.ColumnComment()
|
||
return res
|
||
}
|
||
|
||
// BaseDao 基础dao层
|
||
type BaseDao[DatabaseDataType any, DatabaseTableColumns any] struct {
|
||
tableName string // 继承BaseDao,需要指定表名,后续调用不用传递表名进来,如果分表了,使用SetOption设置表名, 这里的优先级更高
|
||
isSetColumns bool
|
||
columns DatabaseTableColumns
|
||
columnComment map[string]string
|
||
}
|
||
|
||
// Create 创建新的数据
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Create(dbInstance *gorm.DB, data any, optionList ...define.SetOption) error {
|
||
o := &define.Option{}
|
||
for _, itemFunc := range optionList {
|
||
itemFunc(o)
|
||
}
|
||
useTableName := b.tableName
|
||
if len(o.Table) > 0 {
|
||
useTableName = o.Table
|
||
}
|
||
return dbInstance.Table(useTableName).Create(data).Error
|
||
}
|
||
|
||
// Update 更新数据
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Update(dbInstance *gorm.DB, updateData any, optionFuncList ...define.SetOption) (int64, error) {
|
||
dbInstance = b.setTxCondition(dbInstance, optionFuncList...)
|
||
r := dbInstance.Updates(updateData)
|
||
return r.RowsAffected, r.Error
|
||
}
|
||
|
||
// UpdateOne 更新一条数据
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) UpdateOne(dbInstance *gorm.DB, updateData any, optionFuncList ...define.SetOption) (int64, error) {
|
||
optionFuncList = append(optionFuncList, WithLimit(1, 0))
|
||
return b.Update(dbInstance, updateData, optionFuncList...)
|
||
}
|
||
|
||
// List 查询数据列表
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) List(dbInstance *gorm.DB, result *[]DatabaseDataType, optionFuncList ...define.SetOption) error {
|
||
dbInstance = b.setTxCondition(dbInstance, optionFuncList...)
|
||
return dbInstance.Find(result).Error
|
||
}
|
||
|
||
// ListAndTotal 同时查询数据列表和数据总数
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) ListAndTotal(dbInstance *gorm.DB, listRes *[]DatabaseDataType, totalRes *int64, disableTotal bool, optionFuncList ...define.SetOption) error {
|
||
var (
|
||
err error
|
||
)
|
||
|
||
dbInstance = b.setTxCondition(dbInstance, optionFuncList...)
|
||
if err = dbInstance.Find(listRes).Error; nil != err {
|
||
// 列表查询失败
|
||
return err
|
||
}
|
||
if disableTotal {
|
||
// 禁用查询总数
|
||
*totalRes = int64(reflect.ValueOf(listRes).Elem().Len())
|
||
return nil
|
||
}
|
||
optionFuncList = append(optionFuncList, WithClearLimit())
|
||
dbInstance = b.setTxCondition(dbInstance, optionFuncList...)
|
||
if err = dbInstance.Count(totalRes).Error; nil != err {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// Delete 删除数据, 硬删除, 对应 delete语句
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Delete(dbInstance *gorm.DB, dataModel *DatabaseDataType, optionFuncList ...define.SetOption) (int64, error) {
|
||
dbInstance = dbInstance.Model(dataModel)
|
||
dbInstance = b.setTxCondition(dbInstance, optionFuncList...).Delete(dataModel)
|
||
return dbInstance.RowsAffected, dbInstance.Error
|
||
}
|
||
|
||
// Detail 查询详情
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Detail(dbInstance *gorm.DB, result *DatabaseDataType, optionFuncList ...define.SetOption) error {
|
||
dbInstance = b.setTxCondition(dbInstance, optionFuncList...)
|
||
return dbInstance.First(result).Error
|
||
}
|
||
|
||
// DetailByPrimaryID ...
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) DetailByPrimaryID(dbInstance *gorm.DB, result *DatabaseDataType, primaryID any, primaryKey ...string) error {
|
||
primaryKeyField := "id"
|
||
if len(primaryKey) > 0 {
|
||
primaryKeyField = primaryKey[0]
|
||
}
|
||
return b.Detail(dbInstance, result, WithWhere(map[string]any{
|
||
primaryKeyField: primaryID,
|
||
}))
|
||
}
|
||
|
||
// IsNotFound 增加结果是否为数据不存在的判断
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) IsNotFound(err error) bool {
|
||
return errors.Is(err, gorm.ErrRecordNotFound)
|
||
}
|
||
|
||
// Count 查询数量
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Count(dbInstance *gorm.DB, optionFuncList ...define.SetOption) (int64, error) {
|
||
optionFuncList = append(optionFuncList, WithClearLimit())
|
||
dbInstance = b.setTxCondition(dbInstance, optionFuncList...)
|
||
var cnt int64
|
||
return cnt, dbInstance.Count(&cnt).Error
|
||
}
|
||
|
||
// Tx 执行事务
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Tx(dbInstance *gorm.DB, txFunc func(dbInstance *gorm.DB) error) error {
|
||
if nil == dbInstance {
|
||
return errors.New("db instance is null")
|
||
}
|
||
tx := b.Begin(dbInstance)
|
||
if err := txFunc(tx); nil != err {
|
||
_ = b.Rollback(tx)
|
||
return err
|
||
}
|
||
return b.Commit(tx)
|
||
}
|
||
|
||
// Begin 开启事务
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Begin(dbInstance *gorm.DB) *gorm.DB {
|
||
return dbInstance.Begin()
|
||
}
|
||
|
||
// Commit 提交事务
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Commit(db *gorm.DB) error {
|
||
return db.Commit().Error
|
||
}
|
||
|
||
// Rollback 回滚
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Rollback(db *gorm.DB) error {
|
||
return db.Rollback().Error
|
||
}
|
||
|
||
// setTxCondition 设置查询条件
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) setTxCondition(inputTx *gorm.DB, optionFuncList ...define.SetOption) *gorm.DB {
|
||
// 构建查询条件
|
||
o := &define.Option{}
|
||
for _, fn := range optionFuncList {
|
||
fn(o)
|
||
}
|
||
|
||
tx := inputTx.Session(&gorm.Session{
|
||
NewDB: true,
|
||
Initialized: true,
|
||
})
|
||
|
||
// 指定查询的表
|
||
if len(o.Table) > 0 {
|
||
tx = tx.Table(o.Table)
|
||
} else {
|
||
tx = tx.Table(b.tableName)
|
||
}
|
||
|
||
if nil != o.Model {
|
||
tx = tx.Model(o.Model)
|
||
}
|
||
|
||
// 设置 limit offset
|
||
if o.Limit > 0 {
|
||
tx = tx.Limit(o.Limit)
|
||
if o.Offset >= 0 {
|
||
tx = tx.Offset(o.Offset)
|
||
}
|
||
}
|
||
// in 语句
|
||
if nil != o.In {
|
||
tx = tx.Where(o.In)
|
||
}
|
||
|
||
// not in 语句
|
||
if nil != o.NotIn {
|
||
for field, value := range o.NotIn {
|
||
tx = tx.Where(field+" NOT IN ? ", value)
|
||
}
|
||
}
|
||
|
||
// like 语句
|
||
if nil != o.Like {
|
||
for field, value := range o.Like {
|
||
tx = tx.Where(field+" LIKE ? ", "%"+value+"%")
|
||
}
|
||
}
|
||
|
||
// NOT LIKE 语句
|
||
if nil != o.NotLike {
|
||
for field, value := range o.NotLike {
|
||
tx = tx.Where(field+" NOT LIKE ? ", "%"+value+"%")
|
||
}
|
||
}
|
||
|
||
// >=
|
||
if nil != o.Start {
|
||
for field, value := range o.Start {
|
||
tx = tx.Where(field+" >= ?", value)
|
||
}
|
||
}
|
||
|
||
// <
|
||
if nil != o.End {
|
||
for field, value := range o.End {
|
||
tx = tx.Where(field+" < ?", value)
|
||
}
|
||
}
|
||
|
||
if len(o.Where) > 0 {
|
||
tx = tx.Where(o.Where)
|
||
}
|
||
|
||
if o.ForUpdate {
|
||
tx = tx.Clauses(clause.Locking{Strength: "UPDATE"})
|
||
}
|
||
|
||
// between
|
||
for field, betweenVal := range o.Between {
|
||
tx = tx.Where("`"+field+"` BETWEEN ? AND ?", betweenVal[0], betweenVal[1])
|
||
}
|
||
// not between
|
||
for field, notBetweenVal := range o.NotBetween {
|
||
tx = tx.Where("`"+field+"` NOT BETWEEN ? AND ?", notBetweenVal[0], notBetweenVal[1])
|
||
}
|
||
|
||
// 排序
|
||
if len(o.Order) == 2 {
|
||
tx = tx.Order(o.Order[0] + " " + o.Order[1])
|
||
}
|
||
|
||
// or 语句
|
||
if nil != o.OR {
|
||
for _, itemOr := range o.OR {
|
||
orOption := &define.Option{}
|
||
for _, fn := range itemOr {
|
||
fn(orOption)
|
||
}
|
||
orSql, orBindVal := optionToSql(orOption)
|
||
tx.Or(orSql, orBindVal)
|
||
}
|
||
}
|
||
return tx
|
||
}
|
||
|
||
// TableName 获取数据表名
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) TableName() string {
|
||
val := reflect.ValueOf(*new(DatabaseDataType)).MethodByName("TableName").Call(nil)[0]
|
||
return val.Interface().(string)
|
||
}
|
||
|
||
// ColumnComment 表字段注释
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) ColumnComment() map[string]string {
|
||
if len(b.columnComment) > 0 {
|
||
return b.columnComment
|
||
}
|
||
val := reflect.ValueOf(new(DatabaseDataType)).MethodByName("ColumnComment").Call(nil)[0]
|
||
b.columnComment = val.Interface().(map[string]string)
|
||
return b.columnComment
|
||
}
|
||
|
||
// Columns 表字段枚举
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) Columns() DatabaseTableColumns {
|
||
if b.isSetColumns {
|
||
return b.columns
|
||
}
|
||
b.columns = reflect.ValueOf(new(DatabaseDataType)).MethodByName("Columns").Call(nil)[0].Interface().(DatabaseTableColumns)
|
||
b.isSetColumns = true
|
||
return b.columns
|
||
}
|
||
|
||
// DetailForAny 查询任意表数据详情
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) DetailForAny(tx *gorm.DB, tableName string, result any, optionList ...define.SetOption) error {
|
||
optionList = append(optionList, WithTable(tableName))
|
||
tx = b.setTxCondition(tx, optionList...)
|
||
return tx.First(result).Error
|
||
}
|
||
|
||
// ListForAny 查询任意表数据列表
|
||
func (b *BaseDao[DatabaseDataType, DatabaseTableColumns]) ListForAny(tx *gorm.DB, tableName string, data any, optionList ...define.SetOption) error {
|
||
optionList = append(optionList, WithTable(tableName))
|
||
tx = b.setTxCondition(tx, optionList...)
|
||
return tx.Find(data).Error
|
||
}
|