Describe the feature

The migration should happen in two steps

  1. create all the tables without associations
  2. after table creation is done add the constraints defined in the model structs

Motivation

I have complex struct with lot of one to many & many to many relationships between tables

like this

type Organization struct {
    ID             uuid.UUID  `json:"id" gorm:"primary_key; unique; type:uuid; column:id; default:uuid_generate_v4();"`
    OrganizationID uuid.UUID  `json:"organization_id" gorm:"type:uuid;default:uuid_generate_v4();"`
    Locations      []Location `json:"locations"`
    Name           string     `json:"name"`
    TimeZone       string     `json:"time_zone"`
    Language       string     `json:"language"`
    IsLatest       bool       `json:"is_latest" gorm:"default:true;index;"`
    CreatedAt      time.Time  `json:"created_at" gorm:"autoCreateTime"`
    Users          []User     `json:"users"`
}

type User struct {
    ID             uuid.UUID    `json:"id" gorm:"primary_key; unique; type:uuid; column:id; default:uuid_generate_v4();"`
    OrganizationID uuid.UUID    `json:"organization_id"`
    Organization   Organization `json:"organization" gorm:"foreignKey:OrganizationID;references:OrganizationID;"`
    UserID         uuid.UUID    `json:"user_id" gorm:"type:uuid;default:uuid_generate_v4();"`
    Name           string       `json:"name"`
    Role           userRole     `json:"role" sql:"type:user_role"`
    IsLatest       bool         `json:"is_latest" gorm:"default:true;index;"`
    CreatedAt      time.Time    `json:"created_at" gorm:"autoCreateTime"`
}

func main() {
    conn := utils.ConstructDBConnString(utils.PostgresConfig{
        SslMode: option.Some("disable"),
    })

    opts := gorm.Config{
        DisableForeignKeyConstraintWhenMigrating: true,
    }

    db, err := gorm.Open(postgres.Open(conn), &opts)

    if err != nil {
        panic(err)
    }

    db.Exec(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`)

    err = db.AutoMigrate(
        &domain.Organization{},
        &domain.User{},
        // &domain.Location{},
        // &domain.Service{},
        // &domain.Booking{},
    )

    if err != nil {
        panic(err)
    }
}

Currently i have to disable constraints creation because when it tries to create the organization table it also tries to create the constraint to user table but user table does not exist yet.

ERROR: relation "organizations" does not exist (SQLSTATE 42P01)
[0.190ms] [rows:0] ALTER TABLE "users" ADD CONSTRAINT "fk_organizations_users" FOREIGN KEY ("organization_id") REFERENCES "organizations"("id")
panic: ERROR: relation "organizations" does not exist (SQLSTATE 42P01)

goroutine 1 [running]:
main.main()

Related Issues

After a lot of searching i couldn't find any issues related to this

Comment From: mdrokz

Apparently i was doing it wrong you have to specify foreign key like this in the users field instead of in the user struct

type Organization struct {
    ID             uuid.UUID  `json:"id" gorm:"primary_key; unique; type:uuid; column:id; default:uuid_generate_v4();"`
    OrganizationID uuid.UUID  `json:"organization_id" gorm:"type:uuid;default:uuid_generate_v4();"`
    Locations      []Location `json:"locations"`
    Name           string     `json:"name"`
    TimeZone       string     `json:"time_zone"`
    Language       string     `json:"language"`
    IsLatest       bool       `json:"is_latest" gorm:"default:true;index;"`
    CreatedAt      time.Time  `json:"created_at" gorm:"autoCreateTime"`
    Users          []User     `json:"users" gorm:"foreignKey:OrganizationID;references:OrganizationID;"`
}

and in order to load organization field in the user you can do it like this

db.Model(&domain.User{}).Preload("Organization", "organization_id = ?", o.OrganizationID).Find(&u)

Leaving this here in case anybody stumbles onto the same problem as the docs were confusing