Skip to content

xiaotushaoxia/gormutils

Repository files navigation

一些gorm的小工具

NewDB

方便快速的New一个gorm.DB来用

package gormutils

import (
	"fmt"
	"testing"
)

func TestNewDB(t *testing.T) {
	a := Address{
		Address:  "127.0.0.1:3306",
		User:     "root",
		Password: "123456",
		DBName:   "testinit",
		//DialTimeout:     30,
		//ReadTimeout:     30,
		//WriteTimeout:    30,
		//MaxIdleConns:    10,
		//MaxOpenConns:    20,
		//MaxLifeTime:     300,
		//ConnMaxIdleTime: 100,
	}

	db, err := NewDB(&a)
	if err != nil {
		panic(err)
	}
	err = db.AutoMigrate(&User{})
	if err != nil {
		panic(err)
	}

	err = db.Create(&User{Name: "tu", Age: 18}).Error
	if err != nil {
		panic(err)
	}

	var us []*User
	err = db.Find(&us).Error
	if err != nil {
		panic(err)
	}
	for _, u := range us {
		fmt.Println(u)
	}
}

type User struct {
	ID   int
	Name string
	Age  int
}

WhereStatementOfDB

db.Where设置后,从db里拿出where语句。用于避免db.Raw的时候需要手动拼接sql

package gormutils

import (
	"fmt"
	"strings"
	"testing"

	"gorm.io/gorm"
)

func TestWhereStatementOfDB(t *testing.T) {
	var db *gorm.DB

	fmt.Println(WhereStatementOfDB(db)) // "", [], <nil>

	db2 := db.Where("id>?", 10).Where("age<20").Where("score>60").Where("score<?", 100)
	fmt.Println(WhereStatementOfDB(db2)) // WHERE id>? AND age<20 AND score>60 AND score<?, [10 100], <nil>
	fmt.Println(WhereStatementOfDB(db))  // "", [], <nil>

	db3 := db.Where("id>?", 1000)
	fmt.Println(WhereStatementOfDB(db3)) // WHERE id>?,[1000],<nil>

	db4 := db.Table("xsdsd")
	fmt.Println(WhereStatementOfDB(db4)) //"", [], <nil>
}

func TestDemo(t *testing.T) {
	// 为什么要写这么个函数? 用于避免db.Raw的时候需要手动拼接sql
	//type Student struct {
	//	ID    int
	//	Score int
	//	Age   int
	//  Sex   int
	//}
	// 如:我有一个student表如上,需要查询每个分数的学生的数量
	// 可按条件查,比如年纪大于10的男学生每个分数的学生的数量。
	// 因为用了Raw所以db.Where没用生效,然后我就**要手动拼sql**了(这里还有好一些的办法吗,感觉我这个做法也憨憨的)
	var db *gorm.DB

	// 查询参数
	age := ""
	sex := ""
	var result = make([]map[string]any, 0) //查询结果

	where := ""
	var conds []string
	if age != "" {
		conds = append(conds, "agv>"+age)
	}
	if sex != "" {
		conds = append(conds, "sex="+sex)
	}
	if len(conds) > 0 {
		where = "where" + strings.Join(conds, " and ")
	}
	sqlStr := "select `score`,count(*) from student %s group by `score`;"
	err := db.Raw(fmt.Sprintf(sqlStr, where)).Scan(&result).Error
	if err != nil {
		panic(err)
	}

	// 有这个方法可能会好一点
	dd := db
	if age != "" {
		dd = dd.Where("age>?", age) // 还可以用这个?,不用手动格式化字符串了
	}
	if sex != "" {
		dd = dd.Where("sex=?", sex)
	}

	where, args, err := WhereStatementOfDB(dd)
	if err != nil {
		panic(err)
	}
	err = db.Raw(fmt.Sprintf(sqlStr, where), args...).Scan(&result).Error
	if err != nil {
		panic(err)
	}
}

MultiTx

多个数据库的事务操作,让代码好看一点点

package gormutils

import (
	"testing"

	"gorm.io/gorm"
)

func TestNewMultiTx(t *testing.T) {
	var db1, db2 *gorm.DB
	// 当在多个数据库上的操作要保持事务时,我之前写的代码比较丑,所以写了这个MultiTx,让程序稍微好看一点
	// 旧
	err := db1.Transaction(func(tx1 *gorm.DB) error {
		return db2.Transaction(func(tx2 *gorm.DB) error {
			er := tx1.Updates(nil).Error
			if er != nil {
				return er
			}
			er = tx2.Updates(nil).Error
			if er != nil {
				return er
			}
			return nil
		})
	})
	if err != nil {
		panic(err)
	}

	// MultiTx
	mtx := NewMultiTx(db1, db2)
	err = mtx.TransactionN(func(txs ...*gorm.DB) error {
		tx1, tx2 := txs[0], txs[1]
		er := tx1.Updates(nil).Error
		if er != nil {
			return er
		}
		er = tx2.Updates(nil).Error
		if er != nil {
			return er
		}
		return nil
	})
	if err != nil {
		panic(err)
	}
}

WithCondition

用结构体构建gorm的查询条件。减少查询接口的工作量

更新记录

  1. 20230724 考虑到有些字段在很多查询中共用。新增了嵌入结构的支持

有人有更好的办法 谢谢分享

package gormutils

import (
	"fmt"
	"testing"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type areaQueryBody struct {
	nameIDQueryBody `cond:"embedded"`
	//Name  string `cond:"colum:name;opr:like;pattern:%%?%%"`
	//ID    []int  `cond:"colum:id;opr:in"`
	Type  string `cond:"colum:type;opr:in;split:int;sep:,"`
	Start string `cond:"colum:created_at;opr:>"`
	Desc  string `cond:"colum:desc;opr:in"` // split默认值string,sep默认值,
}

type locationQueryBody struct {
	nameIDQueryBody `cond:"embedded"`
	//Name  string `cond:"colum:name;opr:like;pattern:%%?%%"`
	//ID    []int  `cond:"colum:id;opr:in"`
	Type  string `cond:"colum:type;opr:in;split:int;sep:,"`
	Start string `cond:"colum:created_at;opr:>"`
	Desc  string `cond:"colum:desc;opr:in"` // split默认值string,sep默认值,
}

type nameIDQueryBody struct {
	Name string `cond:"colum:name;opr:like;pattern:%%?%%"`
	ID   []int  `cond:"colum:id;opr:in"`
}

func TestWithConditionUsage(t *testing.T) {
	withConditionUsage()
}

func withConditionUsage() {
	aa := areaQueryBody{
		Name:  "区",
		ID:    []int{1, 2, 3},
		Start: "2023-05-08 11:03:23",
		Type:  "1,3,4",
		Desc:  "缓存区1,缓存区2",
	}
	// SELECT * FROM `area`
	// WHERE `name` like '%%区%%' AND `id` in (1,2,3) AND `type` in (1,3,4) AND `created_at` > '2023-05-08 11:03:23' AND `desc` in ('缓存区1','缓存区2')
	db := getDB().Debug()

	db = db.Table("area")

	// 或者  db = db.Scopes(WithCondition(aa)),
	// Scopes是惰性的,到最后find的时候才会执行。因为我这里想打印一下where语句,所以用了db = WithCondition(aa)(db)
	db = WithCondition(aa)(db)
	fmt.Println(WhereStatementOfDB(db))
	//db = db.Scopes(WithCondition(aa))

	var result []map[string]any
	err := db.Find(&result).Error
	if err != nil {
		panic(err)
	}
	fmt.Println("xxx")

	for _, m := range result {
		fmt.Println(m)
	}

	// 旧的方式可能需要 有人有更好的办法 谢谢分享
	//if aa.Name != "" {
	//	db = db.Where("name", aa.Name)
	//}
	//if len(aa.ID) > 0 {
	//	db = db.Where("id in ?", aa.ID)
	//}
	//if aa.Type != "" {
	//	db = db.Where("type in ?", trySplitInString(aa.Type, _queryConditionInt, ","))
	//}
	//...
}

func getDB() *gorm.DB {
	dsn := "root:123456@tcp(127.0.0.1:3306)/testquery?charset=utf8mb4&parseTime=True&loc=Local"
	vv, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}
	return vv
}

About

gormutils工具函数集,只在mysql中测试

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages