Skip to main content

update_organization.go

013_update_organization.go - Overview

  1. 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.

  2. 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 creates SQLMigration 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 created updateOrganization 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