はじめに
以前、職業と飲み物の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
を活用することで、関連データを適切に取得できることを知ることができました。
どんな言語でもいえる事ですが、今まで学んできたモノはそのまま別の言語でも使える、という感覚でいると思わぬエラーに繋がることがあります💦
公式ドキュメントや他の実装例を確認しながら、適切な記述を心がけたい所です。