0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【学習・エラー】Perlのinflateで解決!DBのID→名前変換を実装してみた

Posted at

はじめに

以前、職業と飲み物の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 が正しく解析できていないことが読み取れます😥

問題のファイルを確認

問題のファイルと指定された文字の箇所を確認します

.DB\Schema.pm
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_iddrink_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_iddrink_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_valueoccupation_id の数値(例: 12
    • $rowmember テーブルの1行のデータを扱うオブジェクト
  • return $row->handle->single('occupation', { id => $col_value });
    • $col_value の ID に一致する occupation のレコードを取得して返す

つまり、memberoccupation_idoccupation テーブルのデータに変換する処理をしている。


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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?