Teng で CRUD をしてみる
id:nekokak さんが開発されている、Teng で CRUD を一通りやってみました。
僕自身、DBIx::Class を以前使っていたんですが、あまりにも機能が富豪的すぎて使うのをやめてしまいました。それからは生 DBI を使っていたんですが、開発効率を考えたときに、ORM は使うべきだと再度考えるようになり、軽量な ORM、Teng に注目している所です。
準備
テスト用のテーブル
+------------+-----------+------+-----+---------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +------------+-----------+------+-----+---------------------+-----------------------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | text | NO | | NULL | | | body | text | NO | | NULL | | | created_at | datetime | NO | | 0000-00-00 00:00:00 | | | updated_at | timestamp | YES | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +------------+-----------+------+-----+---------------------+-----------------------------+
まずは、モデルとスキーマのクラスを作成
package My::DB; use strict; use warnings; use parent 'Teng'; package My::DB::Schema; use strict; use warnings; use Teng::Schema::Declare; use DateTime::Format::MySQL; table { name 'memo'; pk 'id'; columns qw( id title body created_at updated_at ); inflate qr/_at$/ => sub { DateTime::Format::MySQL->parse_datetime(shift); }; deflate qr/_at$/ => sub { DateTime::Format::MySQL->format_datetime(shift); }; }; 1;
inflate/deflate の第一引数には正規表現が書けるので、複数のカラムを一度に inflate/deflate 設定できるようです。
データの作成
use strict; use warnings; use feature qw( say ); use lib "lib"; use My::DB; use DateTime; use Data::Dumper; my $teng = My::DB->new(connect_info => [ 'dbi:mysql:database=testdb', 'test', 'tes10', +{ RaiseError => 1, PrintError => 0, AutoCommit => 1, }, ]); my $row = $teng->insert(memo => +{ id => 1, # auto_incrementを指定しているけどテスト用に固定値を入れる title => 'Hello', body => 'World', created_at => DateTime->now(time_zone => 'local'), }); say Dumper($row->get_columns); # Teng::Row が必要ない場合 my $last_insert_id = $teng->fast_insert(memo => +{ id => 2, title => 'red', body => 'green', created_at => DateTime->now(time_zone => 'local'), }); say "last_insert_id: ", $last_insert_id; # テスト用データを作成 $teng->fast_insert(memo => +{ id => 3, title => 'black', body => 'white', created_at => DateTime->now(time_zone => 'local'), }); $teng->fast_insert(memo => +{ id => 4, title => 'foo', body => 'bar baz', created_at => DateTime->now(time_zone => 'local'), });
Teng#insert を実行すると、Teng::Row オブジェクトが返ってきます。必要ない場合は、Teng#fast_insert が使えます。
実行結果
$VAR1 = { 'body' => 'World', 'created_at' => '2011-11-21 00:30:47', 'updated_at' => '2011-11-21 00:30:47', 'id' => '1', 'title' => 'Hello' }; last_insert_id: 2
データの検索
use strict; use warnings; use feature qw( say ); use lib "lib"; use My::DB; use DateTime; use Data::Dumper; my $teng = My::DB->new(connect_info => [ 'dbi:mysql:database=testdb', 'test', 'tes10', +{ RaiseError => 1, PrintError => 0, AutoCommit => 1, }, ]); my $iter = $teng->search(memo => +{ id => [1, 2] }); while (my $row = $iter->next) { say Dumper($row->get_columns); say $row->created_at->ymd; # DateTime } say ""; # 一件のみ取得 my $memo = $teng->single(memo => +{ id => 2 }); say Dumper($memo->get_columns); say $memo->created_at->ymd; # DateTime
複数行を取得する時は、Teng#search が使えます。Teng::Iterator オブジェクトが返り値となり、Teng::Iterator#next で Teng::Row オブジェクトが取得できます。
一行だけ取得する場合は、Teng#single が使えます。created_at カラムは、DateTime オブジェクトになっています。なお、Teng::Row#get_columns で取得した場合は、単純な値になるみたいです。
実行結果
$VAR1 = { 'body' => 'World', 'created_at' => '2011-11-21 00:30:47', 'updated_at' => '2011-11-21 00:30:47', 'id' => '1', 'title' => 'Hello' }; 2011-11-21 $VAR1 = { 'body' => 'green', 'created_at' => '2011-11-21 00:30:47', 'updated_at' => '2011-11-21 00:30:47', 'id' => '2', 'title' => 'red' }; 2011-11-21 $VAR1 = { 'body' => 'green', 'created_at' => '2011-11-21 00:30:47', 'updated_at' => '2011-11-21 00:30:47', 'id' => '2', 'title' => 'red' }; 2011-11-21
データの更新
use strict; use warnings; use feature qw( say ); use lib "lib"; use My::DB; use DateTime; use Data::Dumper; my $teng = My::DB->new(connect_info => [ 'dbi:mysql:database=testdb', 'test', 'tes10', +{ RaiseError => 1, PrintError => 0, AutoCommit => 1, }, ]); my $iter = $teng->search(memo => +{ id => [1, 2] }); while (my $row = $iter->next) { $row->update({ body => 'update test' }); } say $teng->single(memo => +{ id => 1 })->body; say $teng->single(memo => +{ id => 2 })->body;
Teng#update を実行します。難しいところはないと思います。
実行結果
update test update test
データの削除
use strict; use warnings; use feature qw( say ); use lib "lib"; use My::DB; use DateTime; use Data::Dumper; my $teng = My::DB->new(connect_info => [ 'dbi:mysql:database=testdb', 'test', 'tes10', +{ RaiseError => 1, PrintError => 0, AutoCommit => 1, }, ]); my $rows = $teng->delete(memo => +{ id => 1 } ); say "deleted rows: ", $rows; # 削除した件数 # 別なやり方 my $iter = $teng->search(memo => +{ id => [2, 4] }); while (my $row = $iter->next) { $row->delete; }
Teng#delete と Teng::Row#delete を使用することができます。
実行結果
deleted rows: 1
使ってみた印象
実際に使ってみたところ、非常に簡単に使えるなと言うのが第一印象です。また、Web開発をするにあたり、通常使用する分には必要十分な機能を兼ね揃えていると思います。
最後に
今回は入門編として、トランザクション等の考慮はしておらず、とにかく Teng を触って覚えることを主旨としました。今後は、Teng でのリレーションの仕方等を覚えていこうと思います。