Ecto.migrationでPostgreSQLのカラム属性をstringからintegerに変更時の注意点

#経緯
カラムの属性をintegerで作るつもりだったのに　phx.gen.html 時にタイプミスしてしまって、stringに:scream:

```
$ mix phx.gen.html MovieCxt Movie movies title:string summary:string year integer
```

↑`year:integer`とすべきところを `year integer`としてしまったために、
`year:string`と`integer:string`のカラムが作られてしまった:sweat:　　

yearカラムの属性をintegerに変更し、integerカラムは削除したい。

#まず試したこと
migrationファイルを作成し・・・

```
mix ecto.gen.migration mod_col_movies
```
priv/repo/migrations/<タイムスタンプ>_mod_col_movies.exsファイルを編集

```elixir:priv/repo/migrations/<タイムスタンプ>_mod_col_movies.exs
  def change do
    alter table("movies") do
      modify :year, :integer
      remove :integer 
    end
  end
```
そしてmigrate...

```
$ mix ecto.migrate
```
見事に失敗

```
15:37:10.229 [info]  alter table movies
** (Postgrex.Error) ERROR 42804 (datatype_mismatch) 列"year"は型integerには自動的に型変換できません

    hint: 必要に応じて"USING year::integer"を追加してください。
    (ecto_sql 3.7.1) lib/ecto/adapters/sql.ex:760: Ecto.Adapters.SQL.raise_sql_call_error/1
    (elixir 1.13.1) lib/enum.ex:1593: Enum."-map/2-lists^map/1-0-"/2
    (ecto_sql 3.7.1) lib/ecto/adapters/sql.ex:852: Ecto.Adapters.SQL.execute_ddl/4
    (ecto_sql 3.7.1) lib/ecto/migration/runner.ex:343: Ecto.Migration.Runner.log_and_execute_ddl/3
    (ecto_sql 3.7.1) lib/ecto/migration/runner.ex:117: anonymous fn/6 in Ecto.Migration.Runner.flush/0
    (elixir 1.13.1) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto_sql 3.7.1) lib/ecto/migration/runner.ex:116: Ecto.Migration.Runner.flush/0
    (ecto_sql 3.7.1) lib/ecto/migration/runner.ex:280: Ecto.Migration.Runner.perform_operation/3

```

よくわからんけどポスグレ固有の問題？

#　次に試したこと

##　余計なカラムをまず消す

問題の切り分けにもなるので、
とりあえず、integerカラムは先に消すことに。
先ほどのファイルを変更

```elixir
  def change do
    alter table("movies") do
      remove :integer 
    end
  end
```

そしてmigrate。これは成功 
※ 実際は、この後、html.heexやモデルから該当カラムを削除。本題から外れるので記述は省略。


```
$ mix ecto.migrate

15:47:35.899 [info]  == Running 20220118054701 StdApp.Repo.Migrations.ModColToMovies.change/0 forward

15:47:35.906 [info]  alter table movies

15:47:35.950 [info]  == Migrated 20220118054701 in 0.0s
```

## executeでalter table文発行
このままstringでもバリデーションで逃げてもいいかなと思ったけど、elixirforumで以下の投稿を発見

https://elixirforum.com/t/postgrex-error-error-42804-datatype-mismatch-column-cannot-be-cast-automatically-to-type-integer/16776/2

どうやら、PostgreSQLの`alter table `文を直接書くらしい。  ありがたく参考にさせてもらうことにした。

新たにmigrationファイルを作成

```
$ mix ecto.gen.migration mod_col_attr_movies
```
以下のように記述

```elixir
defmodule StdApp.Repo.Migrations.ModColAttrMovies do
  use Ecto.Migration

   def up do
      execute """
        alter table movies alter column year type integer using (year::integer)
       """
   end

   def down do
      execute """
        alter table movies alter column year type varchar(255);
       """
   end
end
```
migrate...

```
$ mix ecto.migrate

16:02:13.928 [info]  == Running 20220118065531 StdApp.Repo.Migrations.ModColAttrMovies.up/0 forward

16:02:13.939 [info]  execute " alter table movies alter column year type integer using (year::integer)\n"

16:02:14.107 [info]  == Migrated 20220118065531 in 0.1s
```
成功！

モデルの属性も忘れずに変更

```elixir
　　　　<省略>
  schema "movies" do
    <省略>
　　　　　　　　field :year, :integer
    <省略>
  end
  <省略>
```

タイプミスしたおかげで、余計な時間がかかってしまった。。
でも記事のネタができたからヨシとするか:sweat_smile: