uptrace/bun

Go migrations collide with new struct fields

開放

#1,156 建立於 2025年3月26日

 (1 則留言) (0 個反應) (0 位負責人)Go (279 個分叉)user submission
help wanted

倉庫指標

星標
 (4,826 顆星)
PR 合併指標
 (平均合併 76天 17小時) (30 天內合併 1 個 PR)

描述

Hey folks,

I've been trying very hard to read the migration docs without success.

When I've tried to write go migrations to create the tables, they've not been particularly successful due to trying to reuse the Model for creating the initial table. There are a couple of problems I've faced.

  • For local development:
    • If I add the new field via the struct first then add the migration to add the column, a new fresh db migration breaks due to the fact that the new column already exists.
    • If I only add the struct field, it would not be updated in existing setups. The same would hold true for only adding the migration that adds the column and not adding the struct field.
  • using bun:"-" always omits the struct field for both creation and querying

Any help with sorting out the below would be appreciated. I'd like to avoid having to iteratively build .sql migrations to handle these sorts of cases.

Here are the example migrations and struct:

model definition

package models

import (
	"github.com/google/uuid"
	"github.com/uptrace/bun"
)

type TestRun struct {
	bun.BaseModel `json:"-"`
	ID uuid.UUID `bun:"type:uuid,notnull"`
	FileName string `bun:",nullzero,notnull"`
	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
        // NewColumn map[string]interface{} `bun:"type:jsonb"` breaks this chain
}

migration 1

package migrations

import (
	"context"
	"fmt"

	"github.com/uptrace/bun"
)

func init() {
	Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
		_, err := db.NewCreateTable().IfNotExists().Model(&models.TestRun{}).Exec(ctx)
		if err != nil {
			return err
		}
		fmt.Print(" [up migration] ")
		return nil
	}, func(ctx context.Context, db *bun.DB) error {
		_, err := db.NewDropTable().Model(&models.TestRun{}).Exec(ctx)
		if err != nil {
			return err
		}
		fmt.Print(" [down migration] ")
		return nil
	})
}

migration 2

package migrations

import (
	"context"
	"fmt"

	"github.com/uptrace/bun"
)

func init() {
	Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
		_, err := db.NewAddColumn().Table("test_runs").ColumnExpr("new_column jsonb NULL").Exec(ctx)
		if err != nil {
			return err
		}
		fmt.Print(" [up migration] ")
		return nil
	}, func(ctx context.Context, db *bun.DB) error {
		_, err := db.NewDropColumn().Table("test_runs").ColumnExpr("new_column").Exec(ctx)
		if err != nil {
			return err
		}
		fmt.Print(" [down migration] ")
		return nil
	})
}

貢獻者指南