経緯
カラムの属性をintegerで作るつもりだったのに phx.gen.html 時にタイプミスしてしまって、stringに
$ mix phx.gen.html MovieCxt Movie movies title:string summary:string year integer
↑year:integer
とすべきところを year integer
としてしまったために、
year:string
とinteger:string
のカラムが作られてしまった
yearカラムの属性をintegerに変更し、integerカラムは削除したい。
まず試したこと
migrationファイルを作成し・・・
mix ecto.gen.migration mod_col_movies
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カラムは先に消すことに。
先ほどのファイルを変更
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で以下の投稿を発見
どうやら、PostgreSQLのalter table
文を直接書くらしい。 ありがたく参考にさせてもらうことにした。
新たにmigrationファイルを作成
$ mix ecto.gen.migration mod_col_attr_movies
以下のように記述
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
成功!
モデルの属性も忘れずに変更
<省略>
schema "movies" do
<省略>
field :year, :integer
<省略>
end
<省略>
タイプミスしたおかげで、余計な時間がかかってしまった。。
でも記事のネタができたからヨシとするか