update_organization.go
013_update_organization.go - Overview
-
Overview This file defines a SQL migration to update the database schema related to organizations, users, and groups. It includes adding new columns, migrating data types, and updating the apdex settings table.
-
Detailed Documentation
updateOrganization
- Purpose: This struct holds the SQLStore instance and is used to perform database migrations.
- Parameters: None
- Returns: None
type updateOrganization struct {
store sqlstore.SQLStore
}
NewUpdateOrganizationFactory
- Purpose: Creates a new factory for creating
updateOrganization
instances. This is part of the factory pattern used for managing SQL migrations. - Parameters:
sqlstore
(sqlstore.SQLStore): The SQLStore instance to be used by the migration.
- Returns:
factory.ProviderFactory[SQLMigration, Config]
: A factory that createsSQLMigration
instances.
func NewUpdateOrganizationFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("update_organization"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
return newUpdateOrganization(ctx, ps, c, sqlstore)
})
}
newUpdateOrganization
- Purpose: Creates a new
updateOrganization
instance. - Parameters:
_
(context.Context): Context (not used)._
(factory.ProviderSettings): Provider settings (not used)._
(Config): Configuration (not used).store
(sqlstore.SQLStore): The SQLStore instance to be used by the migration.
- Returns:
SQLMigration
: The createdupdateOrganization
instance.error
: An error, if any.
func newUpdateOrganization(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
return &updateOrganization{
store: store,
}, nil
}
Register
- Purpose: Registers the Up and Down migration functions with the migrate.Migrations.
- Parameters:
migrations
(*migrate.Migrations): The migrate.Migrations instance to register the migrations with.
- Returns:
error
: An error if registration fails.
func (migration *updateOrganization) Register(migrations *migrate.Migrations) error {
if err := migrations.Register(migration.Up, migration.Down); err != nil {
return err
}
return nil
}
Up
- Purpose: Performs the database schema updates, including adding columns, migrating data types, and updating the apdex settings table.
- Parameters:
ctx
(context.Context): The context for the operation.db
(*bun.DB): The bun database instance.
- Returns:
error
: An error if any of the migration steps fail.
func (migration *updateOrganization) Up(ctx context.Context, db *bun.DB) error {
// begin transaction
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback() //nolint:errcheck
// update apdex settings table
if err := updateApdexSettings(ctx, tx); err != nil {
return err
}
// drop user_flags table
if _, err := tx.NewDropTable().IfExists().Table("user_flags").Exec(ctx); err != nil {
return err
}
// add org id to groups table
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "groups", "org_id"); err != nil {
return err
} else if !exists {
if _, err := tx.NewAddColumn().Table("groups").ColumnExpr("org_id TEXT").Exec(ctx); err != nil {
return err
}
}
// add created_at to groups table
for _, table := range []string{"groups"} {
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, table, "created_at"); err != nil {
return err
} else if !exists {
if _, err := tx.NewAddColumn().Table(table).ColumnExpr("created_at TIMESTAMP").Exec(ctx); err != nil {
return err
}
}
}
// add updated_at to organizations, users, groups table
for _, table := range []string{"organizations", "users", "groups"} {
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, table, "updated_at"); err != nil {
return err
} else if !exists {
if _, err := tx.NewAddColumn().Table(table).ColumnExpr("updated_at TIMESTAMP").Exec(ctx); err != nil {
return err
}
}
}
// since organizations, users has created_at as integer instead of timestamp
for _, table := range []string{"organizations", "users", "invites"} {
if err := migration.store.Dialect().MigrateIntToTimestamp(ctx, tx, table, "created_at"); err != nil {
return err
}
}
// migrate is_anonymous and has_opted_updates to boolean from int
for _, column := range []string{"is_anonymous", "has_opted_updates"} {
if err := migration.store.Dialect().MigrateIntToBoolean(ctx, tx, "organizations", column); err != nil {
return err
}
}
if err := tx.Commit(); err != nil {
return err
}
return nil
}
Down
- Purpose: This function is intended to revert the "Up" migration, but currently it does nothing.
- Parameters:
ctx
(context.Context): The context for the operation.db
(*bun.DB): The bun database instance.
- Returns:
error
: Always returns nil.
func (migration *updateOrganization) Down(ctx context.Context, db *bun.DB) error {
return nil
}
updateApdexSettings
- Purpose: Updates the apdex settings table by creating a new table, copying data from the old table, dropping the old table, and renaming the new table.
- Parameters:
ctx
(context.Context): The context for the operation.tx
(bun.Tx): The bun transaction.
- Returns:
error
: An error if any of the steps fail.
func updateApdexSettings(ctx context.Context, tx bun.Tx) error {
if _, err := tx.NewCreateTable().
Model(&struct {
bun.BaseModel `bun:"table:apdex_settings_new"`
OrgID string `bun:"org_id,pk,type:text"`
ServiceName string `bun:"service_name,pk,type:text"`
Threshold float64 `bun:"threshold,type:float,notnull"`
ExcludeStatusCodes string `bun:"exclude_status_codes,type:text,notnull"`
}{}).
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
IfNotExists().
Exec(ctx); err != nil {
return err
}
// get org id from organizations table
var orgID string
if err := tx.QueryRowContext(ctx, `SELECT id FROM organizations LIMIT 1`).Scan(&orgID); err != nil && !errors.Is(err, sql.ErrNoRows) {
return err
}
if orgID != "" {
// copy old data
if _, err := tx.ExecContext(ctx, `INSERT INTO apdex_settings_new (org_id, service_name, threshold, exclude_status_codes) SELECT ?, service_name, threshold, exclude_status_codes FROM apdex_settings`, orgID); err != nil {
return err
}
}
// drop old table
if _, err := tx.NewDropTable().IfExists().Table("apdex_settings").Exec(ctx); err != nil {
return err
}
// rename new table to old table
if _, err := tx.ExecContext(ctx, `ALTER TABLE apdex_settings_new RENAME TO apdex_settings`); err != nil {
return err
}
return nil
}
Include in Getting Started: NO