DBI のお供になりそうなモジュールたち
2011-12-11
師走にも関わらず風邪を引いてしましました。こんばんは、zigorou です。
今日は DBI のお供になりそうな拙作モジュールたちをご紹介します。
Data::RuledFactory
p5-data-ruledfactory で開発中のモジュールです。
主要機能は大体出来てるんですが、後はテストを充実させて pod をきちんと書いたらリリースしようかなとか思ってる所です。
とはいえ現時点でもやりたいなと思っている事は既に出来ます。
論より証拠と言う事で、examples フォルダにある 001_define_rules.pl についてちょっと解説。
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib";
use DateTime;
use Data::RuledFactory;
my $rf = Data::RuledFactory->new;
$rf->add_rule( id => [ Sequence => { min => 1, max => 100, step => 1 } ] );
$rf->add_rule( name => [ ListRandom => { data => [qw/foo bar baz/] } ] );
$rf->add_rule(
published_on => [
RangeRandom => {
min => DateTime->new( year => 2011, month => 12, day => 1 )->epoch,
max => DateTime->new( year => 2011, month => 12, day => 24 )->epoch,
incremental => 1,
integer => 1,
}
]
);
$rf->rows(10);
while ($rf->has_next) {
my $d = $rf->next;
printf(
"id: %d, name: %s, published_on: %s\n",
$d->{id},
$d->{name},
$d->{published_on},
);
}
このスクリプトのやらんとしているところは、id, name, published_on と言うカラムを持つテーブルのレコードを生成する為のルール定義を行い、
そのルールに基づいて10件のレコードを生成するって事です。
このモジュールの良い所は DBI に特に依存していないと言う事です。なので何にでも使えます。
この例では next() 時にハッシュリファレンスとして受けてますが、事前にカラム定義を columns() メソッドでやっておけば、
csv の各行の用にレコードを配列リファレンスとして受け取る事も出来ます。
色んなレシピがあるんですが、詳しい解説はまた別の機会にやるとします。
Iterator::GroupedRange
- SQL::Maker::Plugin::InsertMulti
- Iterator::GroupedRange
- Data::RuledFactory
の組み合わせによって、大量のデータをランダムに生成して bulk insert を用いて一気に突っ込んだり出来ます。
コードにするとこんな感じになります。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dump qw(dump);
use Data::RuledFactory;
use DateTime;
use DBI;
use Getopt::Long;
use Iterator::GroupedRange;
use SQL::Maker;
my $opts = {};
GetOptions(
$opts,
'dsn|d=s', 'user|u=s',
'password|p=s', 'rows|r=s',
);
%$opts = (
rows => 100,
%$opts,
);
SQL::Maker->load_plugin(qw/InsertMulti/);
my $dbh = DBI->connect($opts->{dsn}, $opts->{user}, $opts->{password}, { AutoCommit => 0, RaiseError => 1, });
my $sql = SQL::Maker->new(
driver => $dbh->{Driver},
new_line => " ",
quote_char => "",
);
my $rf = Data::RuledFactory->new(
columns => [qw/id app_id user_id title published_on/],
rules => [
id => [ Sequence => { min => 1, max => 10000, step => 1 } ],
app_id => [ ListRandom => { data => [ 1000 .. 1100 ] } ],
user_id => [ RangeRandom => { min => 100, max => 1000, integer => 1 } ],
title => [
StringRandom => { data => q#[A-Za-z0-9]{10,16}# }
],
published_on => [
RangeRandom => {
min => DateTime->new( year => 2011, month => 12, day => 1 )->epoch,
max => DateTime->new( year => 2011, month => 12, day => 25 )->epoch,
incremental => 1,
integer => 1,
}
]
],
rows => $opts->{rows},
);
my $iter = Iterator::GroupedRange->new(
sub {
if ($rf->has_next) {
return [ $rf->next(1) ];
}
else {
return;
}
}, 10
);
while ($iter->has_next) {
my $values = $iter->next;
my ($stmt, @bind) = $sql->insert_multi(
'activity',
$rf->columns,
$values,
);
dump($stmt, \@bind);
$dbh->do($stmt, undef, @bind);
$dbh->commit;
}
まとめ
DBIx 以下にあるべきか否かは考えて作るとよりポータブルになるんじゃないかなって思ったりしましたよ!