kra/internal/data/data.go

370 lines
8.4 KiB
Go
Raw Permalink 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 data
import (
"context"
"fmt"
"time"
"kra/internal/biz/example"
"kra/internal/conf"
dataexample "kra/internal/data/example"
datasystem "kra/internal/data/system"
pkgcasbin "kra/pkg/casbin"
"github.com/casbin/casbin/v2"
oracle "github.com/dzwvip/gorm-oracle"
"github.com/glebarez/sqlite"
_ "github.com/go-sql-driver/mysql"
"github.com/google/wire"
"github.com/redis/go-redis/v9"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
// ProviderSet is data providers.
var ProviderSet = wire.NewSet(
NewDB,
NewData,
NewRedisClient,
NewCasbinEnforcer,
NewOssUploader,
NewDataAuthorityProvider,
// System
datasystem.NewUserRepo,
datasystem.NewApiRepo,
datasystem.NewAuthorityRepo,
datasystem.NewAuthorityBtnRepo,
datasystem.NewCasbinRepo,
datasystem.NewMenuRepo,
datasystem.NewDictionaryRepo,
datasystem.NewDictionaryDetailRepo,
datasystem.NewJwtBlacklistRepo,
datasystem.NewOperationRecordRepo,
datasystem.NewParamsRepo,
datasystem.NewErrorRepo,
datasystem.NewVersionRepo,
datasystem.NewExportTemplateRepo,
datasystem.NewAutoCodeRepo,
datasystem.NewAutoCodeHistoryRepo,
datasystem.NewAutoCodePackageRepo,
datasystem.NewAutoCodeTemplateRepo,
datasystem.NewAutoCodePluginRepo,
// Example
dataexample.NewFileUploadRepo,
dataexample.NewCustomerRepo,
dataexample.NewAttachmentCategoryRepo,
dataexample.NewBreakpointContinueRepo,
)
// Data 数据层包装器
type Data struct {
db *gorm.DB
redis redis.UniversalClient
}
// NewData 创建数据层包装器
func NewData(db *gorm.DB, redisClient redis.UniversalClient) (*Data, func(), error) {
cleanup := func() {
// 关闭数据库连接
if db != nil {
sqlDB, err := db.DB()
if err == nil {
sqlDB.Close()
}
}
// 关闭Redis连接
if redisClient != nil {
redisClient.Close()
}
}
return &Data{db: db, redis: redisClient}, cleanup, nil
}
// DB 获取数据库连接
func (d *Data) DB() *gorm.DB {
return d.db
}
// Redis 获取Redis客户端
func (d *Data) Redis() redis.UniversalClient {
return d.redis
}
// NewDB 创建数据库连接(根据配置的数据库类型)
func NewDB(system *conf.System, mysqlCfg *conf.Mysql, pgsqlCfg *conf.Pgsql, sqliteCfg *conf.Sqlite, mssqlCfg *conf.Mssql, oracleCfg *conf.Oracle) (*gorm.DB, error) {
dbType := "mysql"
if system != nil && system.DbType != "" {
dbType = system.DbType
}
switch dbType {
case "mysql":
return NewMysqlDB(mysqlCfg)
case "pgsql":
return NewPgsqlDB(pgsqlCfg)
case "sqlite":
return NewSqliteDB(sqliteCfg)
case "mssql":
return NewMssqlDB(mssqlCfg)
case "oracle":
return NewOracleDB(oracleCfg)
default:
return NewMysqlDB(mysqlCfg)
}
}
// NewMysqlDB 创建MySQL数据库连接
func NewMysqlDB(c *conf.Mysql) (*gorm.DB, error) {
if c == nil || c.DbName == "" {
return nil, fmt.Errorf("mysql config is empty")
}
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s",
c.Username, c.Password, c.Path, c.Port, c.DbName, c.Config)
gormConfig := newGormConfig(c.Prefix, c.Singular, c.LogMode)
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: dsn,
DefaultStringSize: 191,
SkipInitializeWithVersion: false,
}), gormConfig)
if err != nil {
return nil, err
}
if c.Engine != "" {
db.InstanceSet("gorm:table_options", "ENGINE="+c.Engine)
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(c.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(c.MaxOpenConns))
return db, nil
}
// NewPgsqlDB 创建PostgreSQL数据库连接
func NewPgsqlDB(c *conf.Pgsql) (*gorm.DB, error) {
if c == nil || c.DbName == "" {
return nil, fmt.Errorf("pgsql config is empty")
}
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s %s",
c.Path, c.Username, c.Password, c.DbName, c.Port, c.Config)
gormConfig := newGormConfig(c.Prefix, c.Singular, c.LogMode)
db, err := gorm.Open(postgres.New(postgres.Config{
DSN: dsn,
PreferSimpleProtocol: false,
}), gormConfig)
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(c.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(c.MaxOpenConns))
return db, nil
}
// NewSqliteDB 创建SQLite数据库连接
func NewSqliteDB(c *conf.Sqlite) (*gorm.DB, error) {
if c == nil || c.DbName == "" {
return nil, fmt.Errorf("sqlite config is empty")
}
dsn := c.DbName
if c.Path != "" {
dsn = fmt.Sprintf("%s/%s", c.Path, c.DbName)
}
gormConfig := newGormConfig(c.Prefix, c.Singular, c.LogMode)
db, err := gorm.Open(sqlite.Open(dsn), gormConfig)
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(c.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(c.MaxOpenConns))
return db, nil
}
// NewMssqlDB 创建MSSQL数据库连接
func NewMssqlDB(c *conf.Mssql) (*gorm.DB, error) {
if c == nil || c.DbName == "" {
return nil, fmt.Errorf("mssql config is empty")
}
dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%s?database=%s&%s",
c.Username, c.Password, c.Path, c.Port, c.DbName, c.Config)
gormConfig := newGormConfig(c.Prefix, c.Singular, c.LogMode)
db, err := gorm.Open(sqlserver.New(sqlserver.Config{
DSN: dsn,
DefaultStringSize: 191,
}), gormConfig)
if err != nil {
return nil, err
}
if c.Engine != "" {
db.InstanceSet("gorm:table_options", "ENGINE="+c.Engine)
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(c.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(c.MaxOpenConns))
return db, nil
}
// NewOracleDB 创建Oracle数据库连接
func NewOracleDB(c *conf.Oracle) (*gorm.DB, error) {
if c == nil || c.DbName == "" {
return nil, fmt.Errorf("oracle config is empty")
}
dsn := fmt.Sprintf("oracle://%s:%s@%s:%s/%s?%s",
c.Username, c.Password, c.Path, c.Port, c.DbName, c.Config)
gormConfig := newGormConfig(c.Prefix, c.Singular, c.LogMode)
db, err := gorm.Open(oracle.Open(dsn), gormConfig)
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(int(c.MaxIdleConns))
sqlDB.SetMaxOpenConns(int(c.MaxOpenConns))
return db, nil
}
// newGormConfig 创建GORM配置
func newGormConfig(prefix string, singular bool, logMode string) *gorm.Config {
return &gorm.Config{
Logger: logger.New(
&gormLogWriter{},
logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: parseLogLevel(logMode),
Colorful: true,
},
),
NamingStrategy: schema.NamingStrategy{
TablePrefix: prefix,
SingularTable: singular,
},
DisableForeignKeyConstraintWhenMigrating: true,
}
}
// gormLogWriter GORM日志写入器
type gormLogWriter struct{}
func (w *gormLogWriter) Printf(format string, args ...interface{}) {
fmt.Printf(format+"\n", args...)
}
// parseLogLevel 解析日志级别
func parseLogLevel(level string) logger.LogLevel {
switch level {
case "silent":
return logger.Silent
case "error":
return logger.Error
case "warn":
return logger.Warn
case "info":
return logger.Info
default:
return logger.Info
}
}
// NewRedisClient 创建Redis客户端
func NewRedisClient(c *conf.Redis, system *conf.System) (redis.UniversalClient, error) {
// 如果不使用Redis返回nil
if system != nil && !system.UseRedis {
return nil, nil
}
if c == nil {
return nil, nil
}
var client redis.UniversalClient
// 使用集群模式
if c.UseCluster {
client = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: c.ClusterAddrs,
Password: c.Password,
})
} else {
// 使用单例模式
client = redis.NewClient(&redis.Options{
Addr: c.Addr,
Password: c.Password,
DB: int(c.Db),
})
}
// 测试连接
_, err := client.Ping(context.Background()).Result()
if err != nil {
return nil, fmt.Errorf("redis connect ping failed: %v", err)
}
return client, nil
}
// NewCasbinEnforcer 创建Casbin Enforcer
func NewCasbinEnforcer(db *gorm.DB) (*casbin.SyncedCachedEnforcer, error) {
return pkgcasbin.InitCasbin(db, "")
}
// NewOssUploader 创建OSS上传器默认使用空实现
func NewOssUploader() example.OssUploader {
// TODO: 根据配置返回实际的OSS实现
return &example.NilOssUploader{}
}
// NewDataAuthorityProvider 创建数据权限提供者(默认使用简单实现)
func NewDataAuthorityProvider() example.DataAuthorityProvider {
// TODO: 根据需要返回实际的数据权限实现
return &example.SimpleDataAuthorityProvider{}
}