ariga / atlas-provider-gorm

GORM Provider for https://atlasgo.io
Apache License 2.0
55 stars 14 forks source link

Migrations aren't applied correctly in migration diffs? #26

Closed jakubno closed 10 months ago

jakubno commented 10 months ago

When trying to generate migration for following model:

type TestModel struct {
    ID        uuid.UUID `gorm:"type:uuid;default:gen_random_uuid()"`
    CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
    UpdatedAt time.Time
}

func (i *TestModel) TableName() string {
    return "test_schema.test_models"
}

This is my atlas config

data "external_schema" "gorm" {
  program = [
    "go",
    "run",
    "ariga.io/atlas-provider-gorm",
    "load",
    "--path", "./pkg/schema",
    "--dialect", "postgres"
  ]
}

// Define an environment named "local"
env "local" {
  // Declare where the schema definition resides.
  // Also supported: ["file://multi.hcl", "file://schema.hcl"].
  src = data.external_schema.gorm.url

  // Define the URL of the Dev Database for this environment
  // See: https://atlasgo.io/concepts/dev-database
  dev = "docker://postgres/15/dev"

  migration {
    // Define the path to the migration directory.
    // See: https://entgo.io/docs/migrate/#migration-directory
    dir = "file://migrations"
  }
  format {
    migrate {
      diff = "{{ sql . \"  \" }}"
    }
  }
}

I also tried to create migration by commenting out the table name and the editing the migration file to:

CREATE SCHEMA "test_schema";

-- Create "test_models" table
CREATE TABLE "test_schema.test_models" (
  "id" uuid NOT NULL DEFAULT gen_random_uuid(),
  "created_at" timestamptz NULL DEFAULT CURRENT_TIMESTAMP,
  "updated_at" timestamptz NULL,
  PRIMARY KEY ("id")
);

But I still receive following error:

Error: sql/migrate: read migration directory state: sql/migrate: execute: executing statement "CREATE TABLE \"test_schema\".\"test_models\" (\"id\" uuid DEFAULT gen_random_uuid(),\"created_at\" timestamptz DEFAULT CURRENT_TIMESTAMP,\"updated_at\" timestamptz,PRIMARY KEY (\"id\"));" from version "schema": pq: schema "test_schema" does not exist

How can I use different schema? Am I doing something wrong?

rotemtam commented 10 months ago

Is there a particular reason for using the qualified table name test_schema.test_models?

When working with Atlas, you need to determine if you are working in a single schema scope or a multi schema scope (i.e you are going to be handling resources in multiple named schema like admin.users and cms.blog_posts). Many apps don't need this which is why I ask.

If this is the case, just drop the schema qualifier from the TableName:

func (i *TestModel) TableName() string {
    return "test_models"
}

And set your dev database URL (which is used to calculate diffs) to a schema scope:

dev = = "docker://postgres/15/dev?search_path=public"

Also, I noticed you set revision_schema to billing. In general, aside from special cases it's advised to keep the revisions table with the data tables in the same schema, so again, if you are handling a single schema use case, just drop that attribute.

Multi Schema Use-case

On the chance that you are indeed interested in a multi schema workflow, let me explain the error you are seeing. When Atlas starts to calculate your diff, it first starts by applying the GORM schema on the (empty) dev database. Since that db is empty, the attempt to create a table qualified with the non-existent schema is destined to fail.

A way around this is to use the baseline schema feature using a docker block, which specifies to Atlas how to construct the baseline for this dev database. See the docs here.

Specifically, you would need to define a block such as:

docker "postgres" "dev" {
  image  = "postgres:15"
  baseline = <<SQL
   CREATE SCHEMA "test_schema";
  SQL
}

And set your dev URL to:

  dev = docker.postgres.dev.url

Notice that this feature requires you to login:

atlas login

Alternatively you can spin up your own docker image that already has this pre-existing schema manually.

Please let me know if you have any questions

jakubno commented 10 months ago

I don't exactly need the multi schema, but I would prefer than, because it'll make the database structure cleaner.

Thanks for the answer, now it's working :))