github.com/goravel/framework@v1.13.9/testing/docker/database.go (about) 1 package docker 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/ory/dockertest/v3" 8 9 contractsconfig "github.com/goravel/framework/contracts/config" 10 contractsorm "github.com/goravel/framework/contracts/database/orm" 11 "github.com/goravel/framework/contracts/database/seeder" 12 "github.com/goravel/framework/contracts/foundation" 13 "github.com/goravel/framework/contracts/testing" 14 "github.com/goravel/framework/database" 15 "github.com/goravel/framework/database/gorm" 16 "github.com/goravel/framework/support/docker" 17 ) 18 19 type Database struct { 20 app foundation.Application 21 config contractsconfig.Config 22 connection string 23 driver testing.DatabaseDriver 24 gormInitialize gorm.Initialize 25 image *testing.Image 26 pool *dockertest.Pool 27 resource *dockertest.Resource 28 } 29 30 func NewDatabase(app foundation.Application, connection string, gormInitialize gorm.Initialize) (*Database, error) { 31 config := app.MakeConfig() 32 33 if connection == "" { 34 connection = config.GetString("database.default") 35 } 36 driver := config.GetString(fmt.Sprintf("database.connections.%s.driver", connection)) 37 38 var databaseDriver testing.DatabaseDriver 39 switch contractsorm.Driver(driver) { 40 case contractsorm.DriverMysql: 41 databaseDriver = NewMysql(config, connection) 42 case contractsorm.DriverPostgresql: 43 databaseDriver = NewPostgresql(config, connection) 44 case contractsorm.DriverSqlserver: 45 databaseDriver = NewSqlserver(config, connection) 46 case contractsorm.DriverSqlite: 47 databaseDriver = NewSqlite(config, connection) 48 default: 49 return nil, fmt.Errorf("not found database connection: %s", connection) 50 } 51 52 return &Database{ 53 app: app, 54 config: config, 55 connection: connection, 56 driver: databaseDriver, 57 gormInitialize: gormInitialize, 58 }, nil 59 } 60 61 func (receiver *Database) Build() error { 62 pool, err := docker.Pool() 63 if err != nil { 64 return err 65 } 66 receiver.pool = pool 67 68 var opts *dockertest.RunOptions 69 if receiver.image != nil { 70 opts = &dockertest.RunOptions{ 71 Repository: receiver.image.Repository, 72 Tag: receiver.image.Tag, 73 Env: receiver.image.Env, 74 } 75 } else { 76 opts = receiver.driver.Image() 77 } 78 resource, err := docker.Resource(pool, opts) 79 if err != nil { 80 return err 81 } 82 receiver.resource = resource 83 84 if receiver.image != nil && receiver.image.Timeout > 0 { 85 _ = resource.Expire(receiver.image.Timeout) 86 } else { 87 _ = resource.Expire(3600) 88 } 89 90 dbConfig := receiver.driver.Config(resource) 91 receiver.config.Add(fmt.Sprintf("database.connections.%s.host", receiver.connection), dbConfig.Host) 92 receiver.config.Add(fmt.Sprintf("database.connections.%s.port", receiver.connection), dbConfig.Port) 93 receiver.config.Add(fmt.Sprintf("database.connections.%s.database", receiver.connection), dbConfig.Database) 94 receiver.config.Add(fmt.Sprintf("database.connections.%s.username", receiver.connection), dbConfig.Username) 95 receiver.config.Add(fmt.Sprintf("database.connections.%s.password", receiver.connection), dbConfig.Password) 96 97 if err := pool.Retry(func() error { 98 _, err := receiver.gormInitialize.InitializeQuery(context.Background(), receiver.config, receiver.driver.Name().String()) 99 if err != nil { 100 return err 101 } 102 103 receiver.app.MakeArtisan().Call("migrate") 104 105 return nil 106 }); err != nil { 107 return err 108 } 109 110 receiver.app.Singleton(database.BindingOrm, func(app foundation.Application) (any, error) { 111 config := app.MakeConfig() 112 defaultConnection := config.GetString("database.default") 113 114 orm, err := database.InitializeOrm(context.Background(), config, defaultConnection) 115 if err != nil { 116 return nil, fmt.Errorf("[Orm] Init %s connection error: %v", defaultConnection, err) 117 } 118 119 return orm, nil 120 }) 121 122 return nil 123 } 124 125 func (receiver *Database) Config() testing.Config { 126 return receiver.driver.Config(receiver.resource) 127 } 128 129 func (receiver *Database) Clear() error { 130 return receiver.driver.Clear(receiver.pool, receiver.resource) 131 } 132 133 func (receiver *Database) Image(image testing.Image) { 134 receiver.image = &image 135 } 136 137 func (receiver *Database) Seed(seeds ...seeder.Seeder) { 138 command := "db:seed" 139 if len(seeds) > 0 { 140 command += " --seeder" 141 for _, seed := range seeds { 142 command += fmt.Sprintf(" %s", seed.Signature()) 143 } 144 } 145 146 receiver.app.MakeArtisan().Call(command) 147 }