Files
database/base.go
2025-10-18 19:28:26 +08:00

301 lines
8.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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
}