github.com/goravel/framework@v1.13.9/database/gorm/gorm.go (about) 1 package gorm 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "os" 8 "time" 9 10 "github.com/google/wire" 11 gormio "gorm.io/gorm" 12 gormlogger "gorm.io/gorm/logger" 13 "gorm.io/gorm/schema" 14 "gorm.io/plugin/dbresolver" 15 16 "github.com/goravel/framework/contracts/config" 17 databasecontract "github.com/goravel/framework/contracts/database" 18 "github.com/goravel/framework/database/db" 19 "github.com/goravel/framework/support/carbon" 20 ) 21 22 var GormSet = wire.NewSet(NewGormImpl, wire.Bind(new(Gorm), new(*GormImpl))) 23 var _ Gorm = &GormImpl{} 24 25 type Gorm interface { 26 Make() (*gormio.DB, error) 27 } 28 29 type GormImpl struct { 30 config config.Config 31 connection string 32 dbConfig db.Config 33 dialector Dialector 34 instance *gormio.DB 35 } 36 37 func NewGormImpl(config config.Config, connection string, dbConfig db.Config, dialector Dialector) *GormImpl { 38 return &GormImpl{ 39 config: config, 40 connection: connection, 41 dbConfig: dbConfig, 42 dialector: dialector, 43 } 44 } 45 46 func (r *GormImpl) Make() (*gormio.DB, error) { 47 readConfigs := r.dbConfig.Reads() 48 writeConfigs := r.dbConfig.Writes() 49 if len(writeConfigs) == 0 { 50 return nil, errors.New("not found database configuration") 51 } 52 53 writeDialectors, err := r.dialector.Make([]databasecontract.Config{writeConfigs[0]}) 54 if err != nil { 55 return nil, fmt.Errorf("init gorm dialector error: %v", err) 56 } 57 58 if err := r.init(writeDialectors[0]); err != nil { 59 return nil, err 60 } 61 62 if err := r.configurePool(); err != nil { 63 return nil, err 64 } 65 66 if err := r.configureReadWriteSeparate(readConfigs, writeConfigs); err != nil { 67 return nil, err 68 } 69 70 return r.instance, nil 71 } 72 73 func (r *GormImpl) configurePool() error { 74 sqlDB, err := r.instance.DB() 75 if err != nil { 76 return err 77 } 78 79 sqlDB.SetMaxIdleConns(r.config.GetInt("database.pool.max_idle_conns", 10)) 80 sqlDB.SetMaxOpenConns(r.config.GetInt("database.pool.max_open_conns", 100)) 81 sqlDB.SetConnMaxIdleTime(time.Duration(r.config.GetInt("database.pool.conn_max_idletime", 3600)) * time.Second) 82 sqlDB.SetConnMaxLifetime(time.Duration(r.config.GetInt("database.pool.conn_max_lifetime", 3600)) * time.Second) 83 84 return nil 85 } 86 87 func (r *GormImpl) configureReadWriteSeparate(readConfigs, writeConfigs []databasecontract.Config) error { 88 if len(readConfigs) == 0 || len(writeConfigs) == 0 { 89 return nil 90 } 91 92 readDialectors, err := r.dialector.Make(readConfigs) 93 if err != nil { 94 return err 95 } 96 97 writeDialectors, err := r.dialector.Make(writeConfigs) 98 if err != nil { 99 return err 100 } 101 102 return r.instance.Use(dbresolver.Register(dbresolver.Config{ 103 Sources: writeDialectors, 104 Replicas: readDialectors, 105 Policy: dbresolver.RandomPolicy{}, 106 TraceResolverMode: true, 107 })) 108 } 109 110 func (r *GormImpl) init(dialector gormio.Dialector) error { 111 var logLevel gormlogger.LogLevel 112 if r.config.GetBool("app.debug") { 113 logLevel = gormlogger.Info 114 } else { 115 logLevel = gormlogger.Error 116 } 117 118 logger := NewLogger(log.New(os.Stdout, "\r\n", log.LstdFlags), gormlogger.Config{ 119 SlowThreshold: 200 * time.Millisecond, 120 LogLevel: gormlogger.Info, 121 IgnoreRecordNotFoundError: true, 122 Colorful: true, 123 }) 124 instance, err := gormio.Open(dialector, &gormio.Config{ 125 DisableForeignKeyConstraintWhenMigrating: true, 126 SkipDefaultTransaction: true, 127 Logger: logger.LogMode(logLevel), 128 NowFunc: func() time.Time { 129 return carbon.Now().ToStdTime() 130 }, 131 NamingStrategy: schema.NamingStrategy{ 132 TablePrefix: r.config.GetString(fmt.Sprintf("database.connections.%s.prefix", r.connection)), 133 SingularTable: r.config.GetBool(fmt.Sprintf("database.connections.%s.singular", r.connection)), 134 }, 135 }) 136 if err != nil { 137 return err 138 } 139 140 r.instance = instance 141 142 return nil 143 }