package pilgrim_conf import ( "log" ) const DefaultMigrationDirectory = "./migrations" const DefaultMigrationTable = "pilgrim_migrations" type MigrationPhase bool const ( MigrationPhase_Up MigrationPhase = true MigrationPhase_Down = false ) type PilgrimConfigurationRetriever interface { UrlParts() UrlParts MigrationDirectory() string MigrationPhase() MigrationPhase MigrationScript() string MigrationStrictOrdering() bool MigrationIsChecksumValidationEnabled() bool MigrationTable() string MigrationSchema() string ValidateChecksums() bool ValidateLatest() bool ValidateMigrationOrder() bool } type pilgrimContext struct { urlParts UrlParts migrationDirectory string migrationPhase MigrationPhase migrationScript string migrationStrictOrdering bool migrationIsChecksumValidationEnabled bool migrationSchema string migrationTable string validateMigrationOrder bool validateLatest bool validateChecksums bool } func NewPilgrimContext(cli CliFlagRetriever, env EnvVarRetriever) *pilgrimContext { cliUrl, _ := cli.Url() cliUrlParts := ParseDatabaseUrl(cliUrl) envUrl, _ := env.Url() envUrlParts := ParseDatabaseUrl(envUrl) urlParts := UrlParts{ Driver: PickFirstAvailable( cli.Driver, func() (DbDriver, bool) { return DbDriver(cliUrlParts.Driver), cliUrlParts.Driver != EmptyString }, env.Driver, func() (DbDriver, bool) { return DbDriver(envUrlParts.Driver), envUrlParts.Driver != EmptyString }, ), Username: PickFirstAvailable( cli.Username, func() (string, bool) { return cliUrlParts.Username, cliUrlParts.Username != EmptyString }, env.Username, func() (string, bool) { return envUrlParts.Username, envUrlParts.Username != EmptyString }, ), Password: PickFirstAvailable( cli.Password, func() (string, bool) { return cliUrlParts.Password, cliUrlParts.Password != EmptyString }, env.Password, func() (string, bool) { return envUrlParts.Password, envUrlParts.Password != EmptyString }, ), Host: PickFirstAvailable( cli.Host, func() (string, bool) { return cliUrlParts.Host, cliUrlParts.Host != EmptyString }, env.Host, func() (string, bool) { return envUrlParts.Host, envUrlParts.Host != EmptyString }, ), Port: PickFirstAvailable( cli.Port, func() (string, bool) { return cliUrlParts.Port, cliUrlParts.Port != EmptyString }, env.Port, func() (string, bool) { return envUrlParts.Port, envUrlParts.Port != EmptyString }, ), Segments: PickFirstAvailable( cli.Segments, func() ([]string, bool) { return cliUrlParts.Segments, cliUrlParts.Segments != nil }, env.Segments, func() ([]string, bool) { return envUrlParts.Segments, envUrlParts.Segments != nil }, ), Arguments: PickFirstAvailable( cli.Args, func() (map[string]string, bool) { return cliUrlParts.Arguments, cliUrlParts.Arguments != nil }, env.Args, func() (map[string]string, bool) { return envUrlParts.Arguments, envUrlParts.Arguments != nil }, ), } isValid, err := urlParts.Validate() if !isValid { log.Fatalln(err) } migrationPhase, migrationScript, _ := determineMigrationPhaseAndScript(cli) migrationDirectory := PickFirstAvailable(cli.Directory, env.Directory, func() (string, bool) { return DefaultMigrationDirectory, true }) migrationSchema := PickFirstAvailable(cli.MigrationTableSchema, env.MigrationTableSchema, pickFirstDefault(EmptyString)) // Default depends on driver, set empty for now migrationTable := PickFirstAvailable(cli.MigrationTable, env.MigrationTable, pickFirstDefault(DefaultMigrationTable)) migrationStrictOrdering, _ := cli.IsStrictOrderingEnabled() migrationIsChecksumValidationEnabled, _ := cli.IsChecksumValidationEnabled() validateMigrationOrder, _ := cli.IsValidatingMigrationOrder() validateLatest, _ := cli.IsValidatingLatest() validateChecksums, _ := cli.IsValidatingLatest() return &pilgrimContext{ urlParts, migrationDirectory, migrationPhase, migrationScript, migrationStrictOrdering, migrationIsChecksumValidationEnabled, migrationSchema, migrationTable, validateMigrationOrder, validateLatest, validateChecksums, } } type MigrationPhaseRetriever interface { Script() (script string, isScriptProvided bool) IsUp() (isUp, isUpProvided bool) IsDown() (isDown, isDownProvided bool) } func determineMigrationPhaseAndScript(cli MigrationPhaseRetriever) (phase MigrationPhase, script string, err error) { script, _ = cli.Script() isUp, isUpProvided := cli.IsUp() _, isDownProvided := cli.IsDown() if (!isUpProvided && !isDownProvided) || (isUpProvided && isDownProvided) { return MigrationPhase_Down, EmptyString, PilgrimInvalidError("Must provide either --up or --down, but not both.") } if isUp { phase = MigrationPhase_Up } else { phase = MigrationPhase_Down } return } func pickFirstDefault[T any](defaultVal T) func() (value T, provided bool) { return func() (value T, provided bool) { return defaultVal, true } } func PickFirstAvailable[T any](valueProviders ...func() (value T, provided bool)) (value T) { for _, getValue := range valueProviders { val, provided := getValue() if provided { return val } } value, _ = valueProviders[len(valueProviders)-1]() return } func (c *pilgrimContext) UrlParts() UrlParts { return c.urlParts } func (c *pilgrimContext) MigrationDirectory() string { return c.migrationDirectory } func (c *pilgrimContext) MigrationPhase() MigrationPhase { return MigrationPhase(c.migrationPhase) } func (c *pilgrimContext) MigrationScript() string { return c.migrationScript } func (c *pilgrimContext) MigrationStrictOrdering() bool { return c.migrationStrictOrdering } func (c *pilgrimContext) MigrationIsChecksumValidationEnabled() bool { return c.migrationIsChecksumValidationEnabled } func (c *pilgrimContext) MigrationSchema() string { return c.migrationSchema } func (c *pilgrimContext) MigrationTable() string { return c.migrationTable } func (c *pilgrimContext) ValidateChecksums() bool { return c.validateChecksums } func (c *pilgrimContext) ValidateMigrationOrder() bool { return c.validateMigrationOrder } func (c *pilgrimContext) ValidateLatest() bool { return c.validateLatest }