はじめに
以前、職業と飲み物のidを設定することで、更新を容易にできるようにしました。
mysqlのファイルを変更しただけでは反映されないのでDB\Schema.pmファイルも編集したのですが、いざサーバを起動しようとしたタイミングでエラーとなりました。
今回はエラーとそこからの学び、という内容でまとめたいと思います。
👇DB\Schema.pmファイルの内容は下記記事になります。
エラー内容把握
さて、早速ですが、なにやら大量のメッセージが表示されています。
$ carton exec perl -Ilib script/questionary1-server
String found where operator expected at script/../lib/questionary1/DB/Schema.pm line 19, near "belongs_to 'occupation'"
(Do you need to predeclare belongs_to?)
String found where operator expected at script/../lib/questionary1/DB/Schema.pm line 20, near "belongs_to 'drink'"
(Do you need to predeclare belongs_to?)
syntax error at script/../lib/questionary1/DB/Schema.pm line 19, near "belongs_to 'occupation'"
Compilation failed in require at script/../lib/questionary1.pm line 7.
BEGIN failed--compilation aborted at script/../lib/questionary1.pm line 7.
Compilation failed in require at /usr/lib/x86_64-linux-gnu/perl-base/parent.pm line 16.
BEGIN failed--compilation aborted at script/../lib/questionary1/Web.pm line 5.
Compilation failed in require at script/questionary1-server line 10.
BEGIN failed--compilation aborted at script/questionary1-server line 10.
どうやら、belongs_to の使い方が間違っている のが原因で、Perl が正しく解析できていないことが読み取れます😥
問題のファイルを確認
問題のファイルと指定された文字の箇所を確認します
table {
name 'member';
pk 'id';
columns qw(id name birthdate occupation_id drink_id remarks created_at updated_at);
# 外部キー制約を設定
belongs_to 'occupation' => 'questionary1::DB::Occupation', 'occupation_id';
belongs_to 'drink' => 'questionary1::DB::Drink', 'drink_id';
};
belongs_to の使い方が間違っている、という事はメッセージからわかっているので解決に向け3つ試してみました。
試したこと1
-
belongs_to を カラム定義の外側 で定義してみる
belongs_toが間違った場所にある事で単なる文字列として認識していることが原因かと思ったから。結果➡️エラー解消ならず😥table { name 'member'; pk 'id'; columns qw(id name birthdate occupation_id drink_id remarks created_at updated_at); }; # 外部キー制約を設定 belongs_to 'occupation' => 'questionary1::DB::Occupation', 'occupation_id'; belongs_to 'drink' => 'questionary1::DB::Drink', 'drink_id';
試したこと2
-
memberテーブルと同じように記述してみる
そもそもTengの機能にbelongs_toというものは定義されていないと思った。(Rubyの感覚で記述していた💦)# member テーブルのカラムを定義 table { name 'member'; pk 'id'; columns qw(id name birthdate occupation_id drink_id remarks created_at updated_at); }; # occupation テーブルのカラムを定義 table { name 'occupation'; pk 'id'; columns qw(id name created_at updated_at); }; # drink テーブルのカラムを定義 table { name 'drink'; pk 'id'; columns qw(id name created_at updated_at); };結果➡️エラー解消😊
試したこと3
- Teng(PerlのORM)の
inflateを使用
👇上記URLから一部抜粋
inflateとdeflate
Tengには, inflateとdeflateという仕組みがあります. inflateを利用することで, Tengがデータベースからデータを取り出してオブジェクトにする際に任意のカラムの値に対して任意の処理を挟むことが出来ます. deflateはその逆で, Tengからデータベースにデータを書き込む際に任意のカラムの値に対して任意の処理を挟むことが出来ます.
以下のようにinflateを使ってoccupation_idとdrink_id に関連するデータを取得できるように修正していきます
table {
name 'member';
pk 'id';
columns qw(id name birthdate occupation_id drink_id remarks created_at updated_at);
# occupation_id から occupation テーブルのデータを取得
inflate 'occupation_id' => sub {
my ($col_value, $row) = @_;
return $row->handle->single('occupation', { id => $col_value });
};
# drink_id から drink テーブルのデータを取得
inflate 'drink_id' => sub {
my ($col_value, $row) = @_;
return $row->handle->single('drink', { id => $col_value });
};
};
結果➡️エラー解消😊
試したこと3を更に詳しくinflate何ぞや?
Teng(PerlのORM)であるinflateを使うことで、occupation_idやdrink_idのIDを、その関連するテーブルのデータに変換できるようにしている
inflate の仕組み
-
inflateは データベースのカラムの値を、より扱いやすいオブジェクトに変換するための関数 - 例えば、
memberテーブルにはoccupation_idというカラムがありますが、通常このカラムには 数字(ID) が入っている -
inflateを使うことで、occupation_idを 実際の occupation テーブルのデータ に変換できる
inflate 'occupation_id' => sub { ... } の意味
inflate 'occupation_id' => sub {
my ($col_value, $row) = @_;
return $row->handle->single('occupation', { id => $col_value });
};
-
inflateはカラムの変換ルールを定義するための関数。 -
sub { ... }は 無名関数(関数に名前をつけずに定義するもの) -
my ($col_value, $row) = @_;-
$col_valueはoccupation_idの数値(例:1や2) -
$rowはmemberテーブルの1行のデータを扱うオブジェクト
-
-
return $row->handle->single('occupation', { id => $col_value });-
$col_valueの ID に一致するoccupationのレコードを取得して返す
-
→ つまり、member の occupation_id を occupation テーブルのデータに変換する処理をしている。
inflate 'drink_id' => sub { ... } の意味
inflate 'drink_id' => sub {
my ($col_value, $row) = @_;
return $row->handle->single('drink', { id => $col_value });
};
- これも
occupation_idと同じ仕組み -
drink_idの 数値ID を、drinkテーブルの実際のデータに変換して返す
さいごに
今回のエラーからinflateを活用することで、関連データを適切に取得できることを知ることができました。
どんな言語でもいえる事ですが、今まで学んできたモノはそのまま別の言語でも使える、という感覚でいると思わぬエラーに繋がることがあります💦
公式ドキュメントや他の実装例を確認しながら、適切な記述を心がけたい所です。