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  }