Initial commit
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Init initialize mysql config file
|
||||
func Init() error {
|
||||
var cover string
|
||||
if IsExist() {
|
||||
fmt.Println("Your database config is initialized , reinitialized database will cover your database config.")
|
||||
fmt.Println("Did you want to do it ? [Y/N]")
|
||||
fmt.Scanln(&cover)
|
||||
switch strings.ToUpper(cover) {
|
||||
case "Y":
|
||||
case "N":
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
}
|
||||
err := Remove()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = initConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("mysql initialized finished!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func initConfig() error {
|
||||
var dbPath, dbName, dbUsername, dbPwd, dbLogZap, dbLogMod string
|
||||
var maxIdleConns, maxOpenConns int
|
||||
fmt.Println("Please input your database path: ")
|
||||
fmt.Printf("Database path default is '%s'\n", CONFIG.Path)
|
||||
fmt.Scanln(&dbPath)
|
||||
if dbPath != "" {
|
||||
CONFIG.Path = dbPath
|
||||
}
|
||||
|
||||
fmt.Println("Please input your database db-name: ")
|
||||
fmt.Printf("Database db-name default is '%s'\n", CONFIG.DbName)
|
||||
fmt.Scanln(&dbName)
|
||||
if dbName != "" {
|
||||
CONFIG.DbName = dbName
|
||||
}
|
||||
|
||||
fmt.Println("Please input your database username: ")
|
||||
fmt.Printf("Database username default is '%s'\n", CONFIG.Username)
|
||||
fmt.Scanln(&dbUsername)
|
||||
if dbUsername != "" {
|
||||
CONFIG.Username = dbUsername
|
||||
}
|
||||
|
||||
fmt.Println("Please input your database password: ")
|
||||
fmt.Printf("Database password default is '%s'\n", CONFIG.Password)
|
||||
fmt.Scanln(&dbPwd)
|
||||
if dbPwd != "" {
|
||||
CONFIG.Password = dbPwd
|
||||
}
|
||||
|
||||
fmt.Println("Please input your database log zap: ")
|
||||
fmt.Printf("Database log zap default is '%s'\n", CONFIG.LogZap)
|
||||
fmt.Scanln(&dbLogZap)
|
||||
if dbLogZap != "" {
|
||||
CONFIG.LogZap = dbLogZap
|
||||
}
|
||||
|
||||
fmt.Println("Please input your database log mode: [Y/N]")
|
||||
fmt.Println("Database log mode default is N")
|
||||
fmt.Scanln(&dbLogMod)
|
||||
switch strings.ToUpper(dbLogMod) {
|
||||
case "Y":
|
||||
CONFIG.LogMode = true
|
||||
case "N":
|
||||
CONFIG.LogMode = false
|
||||
default:
|
||||
CONFIG.LogMode = false
|
||||
}
|
||||
|
||||
fmt.Println("Please input your database max idle conns: ")
|
||||
fmt.Scanln(&maxIdleConns)
|
||||
if maxIdleConns > 0 {
|
||||
CONFIG.MaxIdleConns = maxIdleConns
|
||||
}
|
||||
|
||||
fmt.Println("Please input your database max open conns: ")
|
||||
fmt.Scanln(&maxOpenConns)
|
||||
if maxOpenConns > 0 {
|
||||
CONFIG.MaxOpenConns = maxOpenConns
|
||||
}
|
||||
|
||||
if Instance() == nil {
|
||||
return ErrDatabaseInit
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/spf13/viper"
|
||||
"pet-house.com/core/g"
|
||||
"pet-house.com/core/server/viper_server"
|
||||
)
|
||||
|
||||
var CONFIG = Mysql{
|
||||
Path: "127.0.0.1:3306",
|
||||
Config: "charset=utf8mb4&parseTime=True&loc=Local",
|
||||
DbName: "iris-admin",
|
||||
Username: "root",
|
||||
Password: "",
|
||||
MaxIdleConns: 0,
|
||||
MaxOpenConns: 0,
|
||||
LogMode: false,
|
||||
LogZap: "error",
|
||||
}
|
||||
|
||||
type Mysql struct {
|
||||
Path string `mapstructure:"path" json:"path" yaml:"path"`
|
||||
Config string `mapstructure:"config" json:"config" yaml:"config"`
|
||||
DbName string `mapstructure:"db-name" json:"db-name" yaml:"db-name"`
|
||||
Username string `mapstructure:"username" json:"username" yaml:"username"`
|
||||
Password string `mapstructure:"password" json:"password" yaml:"password"`
|
||||
MaxIdleConns int `mapstructure:"max-idle-conns" json:"max-idle-conns" yaml:"max-idle-conns"`
|
||||
MaxOpenConns int `mapstructure:"max-open-conns" json:"max-open-conns" yaml:"max-open-conns"`
|
||||
LogMode bool `mapstructure:"log-mode" json:"log-mode" yaml:"log-mode"`
|
||||
LogZap string `mapstructure:"log-zap" json:"log-zap" yaml:"log-zap"` //silent,error,warn,info,zap
|
||||
}
|
||||
|
||||
// Dsn return mysql dsn
|
||||
func (m *Mysql) Dsn() string {
|
||||
return fmt.Sprintf("%s%s?%s", m.BaseDsn(), m.DbName, m.Config)
|
||||
}
|
||||
|
||||
// Dsn return
|
||||
func (m *Mysql) BaseDsn() string {
|
||||
return fmt.Sprintf("%s:%s@tcp(%s)/", m.Username, m.Password, m.Path)
|
||||
}
|
||||
|
||||
// IsExist config file is exist
|
||||
func IsExist() bool {
|
||||
return getViperConfig().IsFileExist()
|
||||
}
|
||||
|
||||
// Remove remove config file
|
||||
func Remove() error {
|
||||
return getViperConfig().Remove()
|
||||
}
|
||||
|
||||
// Recover
|
||||
func Recover() error {
|
||||
b, err := json.Marshal(CONFIG)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return getViperConfig().Recover(b)
|
||||
}
|
||||
|
||||
// getViperConfig get viper config
|
||||
func getViperConfig() viper_server.ViperConfig {
|
||||
configName := "mysql"
|
||||
mxIdleConns := fmt.Sprintf("%d", CONFIG.MaxIdleConns)
|
||||
mxOpenConns := fmt.Sprintf("%d", CONFIG.MaxOpenConns)
|
||||
logMode := fmt.Sprintf("%t", CONFIG.LogMode)
|
||||
return viper_server.ViperConfig{
|
||||
Debug: true,
|
||||
Directory: g.ConfigDir,
|
||||
Name: configName,
|
||||
Type: g.ConfigType,
|
||||
Watch: func(vi *viper.Viper) error {
|
||||
if err := vi.Unmarshal(&CONFIG); err != nil {
|
||||
return fmt.Errorf("get Unarshal error: %v", err)
|
||||
}
|
||||
// watch config file change
|
||||
vi.OnConfigChange(func(e fsnotify.Event) {
|
||||
fmt.Println("Config file changed:", e.Name)
|
||||
})
|
||||
vi.WatchConfig()
|
||||
return nil
|
||||
},
|
||||
//
|
||||
Default: []byte(`
|
||||
{
|
||||
"path": "` + CONFIG.Path + `",
|
||||
"config": "` + CONFIG.Config + `",
|
||||
"db-name": "` + CONFIG.DbName + `",
|
||||
"username": "` + CONFIG.Username + `",
|
||||
"password": "` + CONFIG.Password + `",
|
||||
"max-idle-conns": ` + mxIdleConns + `,
|
||||
"max-open-conns": ` + mxOpenConns + `,
|
||||
"log-mode": ` + logMode + `,
|
||||
"log-zap": "` + CONFIG.LogZap + `"
|
||||
}`),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"config": "charset=utf8mb4\u0026parseTime=True\u0026loc=Local",
|
||||
"db-name": "iris-admin",
|
||||
"log-mode": false,
|
||||
"log-zap": "error",
|
||||
"max-idle-conns": 0,
|
||||
"max-open-conns": 0,
|
||||
"password": "",
|
||||
"path": "127.0.0.1:3306",
|
||||
"username": "root"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"director": "logs",
|
||||
"encode-level": "LowercaseColorLevelEncoder",
|
||||
"format": "console",
|
||||
"level": "debug",
|
||||
"link-name": "latest_log",
|
||||
"log-in-console": false,
|
||||
"prefix": "[IRIS-ADMIN]",
|
||||
"show-line": true,
|
||||
"stacktrace-key": "stacktrace"
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"pet-house.com/core/server/viper_server"
|
||||
"pet-house.com/core/server/zap_server"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
var ErrDatabaseInit = errors.New("database initialize fail")
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
db *gorm.DB
|
||||
)
|
||||
|
||||
// init
|
||||
func init() {
|
||||
viper_server.Init(getViperConfig())
|
||||
}
|
||||
|
||||
// Instance
|
||||
func Instance() *gorm.DB {
|
||||
once.Do(func() {
|
||||
db = gormMysql()
|
||||
})
|
||||
return db
|
||||
}
|
||||
|
||||
// gormMysql get *gorm.DB
|
||||
func gormMysql() *gorm.DB {
|
||||
if CONFIG.DbName == "" {
|
||||
fmt.Println("config dbname is empty")
|
||||
return nil
|
||||
}
|
||||
/*err := createTable(CONFIG.BaseDsn(), "mysql", CONFIG.DbName)
|
||||
if err != nil {
|
||||
fmt.Printf("create database %s is failed %v \n", CONFIG.DbName, err)
|
||||
return nil
|
||||
}*/
|
||||
mysqlConfig := mysql.Config{
|
||||
DSN: CONFIG.Dsn(),
|
||||
DefaultStringSize: 191,
|
||||
DisableDatetimePrecision: true,
|
||||
DontSupportRenameIndex: true,
|
||||
DontSupportRenameColumn: true,
|
||||
SkipInitializeWithVersion: false,
|
||||
}
|
||||
if db, err := gorm.Open(mysql.New(mysqlConfig), gormConfig(CONFIG.LogMode)); err != nil {
|
||||
fmt.Printf("open mysql is failed %v \n", err)
|
||||
return nil
|
||||
} else {
|
||||
sqlDB, _ := db.DB()
|
||||
sqlDB.SetMaxIdleConns(CONFIG.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(CONFIG.MaxOpenConns)
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// gormConfig get gorm config
|
||||
func gormConfig(mod bool) *gorm.Config {
|
||||
var config = &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}
|
||||
switch CONFIG.LogZap {
|
||||
case "silent", "Silent":
|
||||
config.Logger = Default.LogMode(logger.Silent)
|
||||
case "error", "Error":
|
||||
config.Logger = Default.LogMode(logger.Error)
|
||||
case "warn", "Warn":
|
||||
config.Logger = Default.LogMode(logger.Warn)
|
||||
case "info", "Info":
|
||||
config.Logger = Default.LogMode(logger.Info)
|
||||
case "zap", "Zap":
|
||||
config.Logger = Default.LogMode(logger.Info)
|
||||
default:
|
||||
if mod {
|
||||
config.Logger = Default.LogMode(logger.Info)
|
||||
break
|
||||
}
|
||||
config.Logger = Default.LogMode(logger.Silent)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// createTable create database(mysql)
|
||||
func createTable(dsn, driver, dbName string) error {
|
||||
createSql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;", dbName)
|
||||
db, err := sql.Open(driver, dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(db *sql.DB) {
|
||||
_ = db.Close()
|
||||
}(db)
|
||||
if err = db.Ping(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = db.Exec(createSql)
|
||||
return err
|
||||
}
|
||||
|
||||
func DorpDB(dsn, driver, dbName string) error {
|
||||
execSql := fmt.Sprintf("DROP database if exists `%s`;", dbName)
|
||||
db, err := sql.Open(driver, dsn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if db == nil {
|
||||
return errors.New("db is nil")
|
||||
}
|
||||
defer func(db *sql.DB) {
|
||||
_ = db.Close()
|
||||
}(db)
|
||||
if err = db.Ping(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = db.Exec(execSql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
zap_server.ZAPLOG.Debug(execSql)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
func TestInstanceMysql(t *testing.T) {
|
||||
t.Run("test instance mysql", func(t *testing.T) {
|
||||
mysql := Instance()
|
||||
if mysql == nil {
|
||||
t.Error("mysql instance is nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGormMysql(t *testing.T) {
|
||||
t.Run("test gorm mysql", func(t *testing.T) {
|
||||
gormDb := gormMysql()
|
||||
if gormDb == nil {
|
||||
t.Error("gorm db is nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGormConfig(t *testing.T) {
|
||||
t.Run("test gorm config", func(t *testing.T) {
|
||||
gormConfig := gormConfig(false)
|
||||
if !reflect.DeepEqual(gormConfig.Logger, Default.LogMode(logger.Error)) {
|
||||
t.Errorf("gorm config logger want %+v but get %+v", Default.LogMode(logger.Error), gormConfig.Logger)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm/logger"
|
||||
"gorm.io/gorm/utils"
|
||||
"pet-house.com/core/server/zap_server"
|
||||
)
|
||||
|
||||
// writer
|
||||
type writer interface {
|
||||
Printf(string, ...interface{})
|
||||
}
|
||||
|
||||
// config
|
||||
type config struct {
|
||||
SlowThreshold time.Duration
|
||||
Colorful bool
|
||||
LogLevel logger.LogLevel
|
||||
}
|
||||
|
||||
var (
|
||||
Discard = New(log.New(ioutil.Discard, "", log.LstdFlags), config{})
|
||||
Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), config{
|
||||
SlowThreshold: 200 * time.Millisecond,
|
||||
LogLevel: logger.Warn,
|
||||
Colorful: true,
|
||||
})
|
||||
Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()}
|
||||
)
|
||||
|
||||
// New
|
||||
func New(writer writer, config config) logger.Interface {
|
||||
var (
|
||||
infoStr = "%s\n[info] "
|
||||
warnStr = "%s\n[warn] "
|
||||
errStr = "%s\n[error] "
|
||||
traceStr = "%s\n[%.3fms] [rows:%v] %s"
|
||||
traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s"
|
||||
traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s"
|
||||
)
|
||||
|
||||
if config.Colorful {
|
||||
infoStr = logger.Green + "%s\n" + logger.Reset + logger.Green + "[info] " + logger.Reset
|
||||
warnStr = logger.BlueBold + "%s\n" + logger.Reset + logger.Magenta + "[warn] " + logger.Reset
|
||||
errStr = logger.Magenta + "%s\n" + logger.Reset + logger.Red + "[error] " + logger.Reset
|
||||
traceStr = logger.Green + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s"
|
||||
traceWarnStr = logger.Green + "%s " + logger.Yellow + "%s\n" + logger.Reset + logger.RedBold + "[%.3fms] " + logger.Yellow + "[rows:%v]" + logger.Magenta + " %s" + logger.Reset
|
||||
traceErrStr = logger.RedBold + "%s " + logger.MagentaBold + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s"
|
||||
}
|
||||
|
||||
return &customLogger{
|
||||
writer: writer,
|
||||
config: config,
|
||||
infoStr: infoStr,
|
||||
warnStr: warnStr,
|
||||
errStr: errStr,
|
||||
traceStr: traceStr,
|
||||
traceWarnStr: traceWarnStr,
|
||||
traceErrStr: traceErrStr,
|
||||
}
|
||||
}
|
||||
|
||||
// customLogger
|
||||
type customLogger struct {
|
||||
writer
|
||||
config
|
||||
infoStr, warnStr, errStr string
|
||||
traceStr, traceErrStr, traceWarnStr string
|
||||
}
|
||||
|
||||
// LogMode
|
||||
func (c *customLogger) LogMode(level logger.LogLevel) logger.Interface {
|
||||
newLogger := *c
|
||||
newLogger.LogLevel = level
|
||||
return &newLogger
|
||||
}
|
||||
|
||||
// Info print info
|
||||
func (c *customLogger) Info(ctx context.Context, message string, data ...interface{}) {
|
||||
if c.LogLevel >= logger.Info {
|
||||
c.Printf(c.infoStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Warn print warn messages
|
||||
func (c *customLogger) Warn(ctx context.Context, message string, data ...interface{}) {
|
||||
if c.LogLevel >= logger.Warn {
|
||||
c.Printf(c.warnStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Error print error messages
|
||||
func (c *customLogger) Error(ctx context.Context, message string, data ...interface{}) {
|
||||
if c.LogLevel >= logger.Error {
|
||||
c.Printf(c.errStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Trace print sql message
|
||||
func (c *customLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
|
||||
if c.LogLevel > 0 {
|
||||
elapsed := time.Since(begin)
|
||||
switch {
|
||||
case err != nil && c.LogLevel >= logger.Error:
|
||||
sql, rows := fc()
|
||||
if rows == -1 {
|
||||
c.Printf(c.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
|
||||
} else {
|
||||
c.Printf(c.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
|
||||
}
|
||||
case elapsed > c.SlowThreshold && c.SlowThreshold != 0 && c.LogLevel >= logger.Warn:
|
||||
sql, rows := fc()
|
||||
slowLog := fmt.Sprintf("SLOW SQL >= %v", c.SlowThreshold)
|
||||
if rows == -1 {
|
||||
c.Printf(c.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
|
||||
} else {
|
||||
c.Printf(c.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
|
||||
}
|
||||
case c.LogLevel >= logger.Info:
|
||||
sql, rows := fc()
|
||||
if rows == -1 {
|
||||
c.Printf(c.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
|
||||
} else {
|
||||
c.Printf(c.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Printf
|
||||
func (c *customLogger) Printf(message string, data ...interface{}) {
|
||||
if CONFIG.LogZap != "" {
|
||||
switch len(data) {
|
||||
case 0:
|
||||
zap_server.ZAPLOG.Info(message)
|
||||
case 1:
|
||||
zap_server.ZAPLOG.Info("gorm", zap.Any("src", data[0]))
|
||||
case 2:
|
||||
zap_server.ZAPLOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]))
|
||||
case 3:
|
||||
zap_server.ZAPLOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2]))
|
||||
case 4:
|
||||
zap_server.ZAPLOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2]), zap.Any("sql", data[3]))
|
||||
}
|
||||
return
|
||||
}
|
||||
switch len(data) {
|
||||
case 0:
|
||||
c.writer.Printf(message, "")
|
||||
case 1:
|
||||
c.writer.Printf(message, data[0])
|
||||
case 2:
|
||||
c.writer.Printf(message, data[0], data[1])
|
||||
case 3:
|
||||
c.writer.Printf(message, data[0], data[1], data[2])
|
||||
case 4:
|
||||
c.writer.Printf(message, data[0], data[1], data[2], data[3])
|
||||
case 5:
|
||||
c.writer.Printf(message, data[0], data[1], data[2], data[3], data[4])
|
||||
}
|
||||
}
|
||||
|
||||
type traceRecorder struct {
|
||||
logger.Interface
|
||||
BeginAt time.Time
|
||||
SQL string
|
||||
RowsAffected int64
|
||||
Err error
|
||||
}
|
||||
|
||||
func (t traceRecorder) New() *traceRecorder {
|
||||
return &traceRecorder{Interface: t.Interface, BeginAt: time.Now()}
|
||||
}
|
||||
|
||||
func (t *traceRecorder) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
|
||||
t.BeginAt = begin
|
||||
t.SQL, t.RowsAffected = fc()
|
||||
t.Err = err
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"pet-house.com/core/server/database/scope"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type otheraccounts struct {
|
||||
Id int64
|
||||
Accid string
|
||||
Apptypeid string
|
||||
Unionid string
|
||||
Openid string
|
||||
Usertype string
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
CONFIG.DbName = "pikauser"
|
||||
CONFIG.Path = "172.31.65.221:3306"
|
||||
CONFIG.Password = "qC#5Lp%9AF=6BmR5Ny!6aaabbb"
|
||||
CONFIG.Username = "pikauser_dev"
|
||||
|
||||
code := m.Run()
|
||||
|
||||
for i := 1; i <= 10; i++ {
|
||||
var account otheraccounts
|
||||
Instance().Table("otheraccounts").Model(&otheraccounts{}).Scopes(scope.PaginateScope(i, 1, "desc", "createtime")).Where(" apptypeid = ?", "100001").Find(&account)
|
||||
fmt.Println(account.Openid, account.Id)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package orm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"pet-house.com/core/server/database/scope"
|
||||
"pet-house.com/core/server/web/web_iris/validate"
|
||||
"pet-house.com/core/server/zap_server"
|
||||
)
|
||||
|
||||
type ErrMsg struct {
|
||||
Code int64 `json:"code"`
|
||||
Msg string `json:"message"`
|
||||
}
|
||||
|
||||
var (
|
||||
ErrParamValidate = errors.New("参数验证失败")
|
||||
ErrPaginateParam = errors.New("分页查询参数缺失")
|
||||
ErrUnSupportFramework = errors.New("不支持的框架")
|
||||
)
|
||||
|
||||
// Model
|
||||
type Model struct {
|
||||
Id uint `json:"id" uri:"id" form:"id" param:"id"`
|
||||
UpdatedAt string `json:"updatedAt" uri:"updatedAt" form:"updatedAt" param:"updatedAt"`
|
||||
CreatedAt string `json:"createdAt" uri:"createdAt" form:"createdAt" param:"createdAt"`
|
||||
DeletedAt string `json:"deletedAt" uri:"deletedAt" form:"deletedAt" param:"deletedAt"`
|
||||
}
|
||||
|
||||
// ReqId the struct has used to get id form the context of every query
|
||||
type ReqId struct {
|
||||
Id uint `json:"id" uri:"id" form:"id" param:"id"`
|
||||
}
|
||||
|
||||
// Request get id data form the context of every query
|
||||
func (req *ReqId) Request(ctx interface{}) error {
|
||||
if c, ok := ctx.(iris.Context); ok {
|
||||
return req.irisReadParams(c)
|
||||
} else if c, ok := ctx.(*gin.Context); ok {
|
||||
return req.ginShouldBindUri(c)
|
||||
} else {
|
||||
return ErrUnSupportFramework
|
||||
}
|
||||
}
|
||||
|
||||
func (req *ReqId) irisReadParams(ctx iris.Context) error {
|
||||
if err := ctx.ReadParams(req); err != nil {
|
||||
zap_server.ZAPLOG.Error(err.Error())
|
||||
return ErrParamValidate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (req *ReqId) ginShouldBindUri(ctx *gin.Context) error {
|
||||
if err := ctx.ShouldBindUri(req); err != nil {
|
||||
zap_server.ZAPLOG.Error(err.Error())
|
||||
return ErrParamValidate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Paginate param for paginate query
|
||||
type Paginate struct {
|
||||
Page int `json:"page" form:"page"`
|
||||
PageSize int `json:"pageSize" form:"pageSize"`
|
||||
OrderBy string `json:"orderBy" form:"orderBy"`
|
||||
Sort string `json:"sort" form:"sort"`
|
||||
}
|
||||
|
||||
// Request
|
||||
func (req *Paginate) Request(ctx interface{}) error {
|
||||
if c, ok := ctx.(iris.Context); ok {
|
||||
return req.irisReadQuerys(c)
|
||||
} else if c, ok := ctx.(*gin.Context); ok {
|
||||
return req.ginShouldBind(c)
|
||||
} else {
|
||||
return ErrUnSupportFramework
|
||||
}
|
||||
}
|
||||
|
||||
func (req *Paginate) irisReadQuerys(ctx iris.Context) error {
|
||||
if err := ctx.ReadQuery(req); err != nil {
|
||||
errs := validate.ValidRequest(err)
|
||||
if len(errs) > 0 {
|
||||
zap_server.ZAPLOG.Error(strings.Join(errs, ";"))
|
||||
return ErrParamValidate
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (req *Paginate) ginShouldBind(ctx *gin.Context) error {
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
zap_server.ZAPLOG.Error(err.Error())
|
||||
return ErrParamValidate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PaginateScope paginate scope
|
||||
func (req *Paginate) PaginateScope() func(db *gorm.DB) *gorm.DB {
|
||||
return scope.PaginateScope(req.Page, req.PageSize, req.Sort, req.OrderBy)
|
||||
}
|
||||
|
||||
// Response
|
||||
type Response struct {
|
||||
Status int64 `json:"status"`
|
||||
Msg string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package scope
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
// IdScope
|
||||
// - id uint
|
||||
func IdScope(id uint) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("id = ?", id)
|
||||
}
|
||||
}
|
||||
|
||||
// InIdsScope
|
||||
// - ids []uint
|
||||
func InIdsScope(ids []uint) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("id in ?", ids)
|
||||
}
|
||||
}
|
||||
|
||||
// InNamesScope
|
||||
// - names []string
|
||||
func InNamesScope(names []string) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("name in ?", names)
|
||||
}
|
||||
}
|
||||
|
||||
// InUuidsScope
|
||||
// - uuids []string
|
||||
func InUuidsScope(uuids []string) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("uuid in ?", uuids)
|
||||
}
|
||||
}
|
||||
|
||||
// NeIdScope
|
||||
// - id uint
|
||||
func NeIdScope(id uint) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("id != ?", id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package scope
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"pet-house.com/core/helper/str"
|
||||
)
|
||||
|
||||
// PaginateScope return paginate scope for gorm
|
||||
// - page int
|
||||
// - pageSize int
|
||||
// - sort string
|
||||
// - orderBy string
|
||||
func PaginateScope(page, pageSize int, sort, orderBy string) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
pageSize := getPageSize(pageSize)
|
||||
offset := getOffset(page, pageSize)
|
||||
return db.Order(getOrderBy(sort, orderBy)).Offset(offset).Limit(pageSize)
|
||||
}
|
||||
}
|
||||
|
||||
// getOffset
|
||||
func getOffset(page, pageSize int) int {
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
if page < 0 {
|
||||
offset = -1
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
// getPageSize
|
||||
func getPageSize(pageSize int) int {
|
||||
switch {
|
||||
case pageSize > 100:
|
||||
pageSize = 100
|
||||
case pageSize < 0:
|
||||
pageSize = -1
|
||||
case pageSize == 0:
|
||||
pageSize = 10
|
||||
}
|
||||
return pageSize
|
||||
}
|
||||
|
||||
// getOrderBy
|
||||
func getOrderBy(sort, orderBy string) string {
|
||||
if sort == "" {
|
||||
sort = "desc"
|
||||
}
|
||||
if orderBy == "" {
|
||||
orderBy = "created_at"
|
||||
}
|
||||
return str.Join(orderBy, " ", sort)
|
||||
}
|
||||
Reference in New Issue
Block a user