ドライバを知るB!

はじめに

これまでは Data::Model カラムの定義周りを重点的にボリュームを上げて書いていました。

これからは最終回に向けて、より確実に Data::Model を使えるような内容でお送りしたいと思います。

Driver

Data::Model を ORM 的に使うには use base 'Data::Model' して use Data::Model:Schema して DSL を使ってスキーマ定義をすると説明してきました。

ただ、これだけではデータベースと接続する事ができません。なぜならスキーマ定義にはデータベースと接続する機能がないからです。

データベースなどのデータソースと接続するためにはドライバーを利用しなければなりません。

このあたりは Data::ObjectDriver と同じです。もしかしたら DBIx::MoCo も当てはまるかもしれません。

簡単な Driver の定義は下記のような形です。

    use Data::Model::Driver::DBI;
    my $driver = Data::Model::Driver::DBI->new(
        dsn => 'dbi:SQLite:dbname=mybookmark.db'
    );

new のオプションは Driver によって異なります。

DBI Driver の全オプションを含めると以下のようなコードになります。

  my $driver = Data::Model::Driver::DBI->new(
      dsn             => 'dbi:mysql:host=localhost:database=test',
      username        => 'user',
      password        => 'password',
      connect_options => $dbi_connect_options,
      reuse_dbh       => 1,
  );

dsn, username, password などは DBI のあれと同じですね。

connect_options は DBI->connect( $dsn, $user, $pass, $connect_options ) の $connect_options に渡されるものと同等です。

default で RaiseError => 1, PrintError => 0, AutoCommit => 1 がそれぞれ設定されます。

reuse_dbh は、同じ dsn の接続は1つの接続を使いまわすようにしてくれます。

例えば、 DB::User, DB::Bookmark, DB::Diary, DB::Fotolife と複数のスキーマ定義をしておいて、それぞれ別々の Data::Model::Driver::DBI インスタンスを使っているときに、 dsn は同じ物を利用していた場合に reuse_dbh を真にしておくと DB 接続は一つだけにしてくれるようになります。

様々な Driver

Data::Model では DBI 以外にも様々なデータソースが扱えます。代表的な物としては Driver::Memcached なのですが、これは17日に dann さんが素敵な紹介を寄稿していただいたのでそちらを参照ください。

http://perl-users.jp/articles/advent-calendar/2009/data-model/17.html

kumofs にデータを出し入れするために僕は使っています。

この Driver の圧縮オプションをつけまくる事で素の Cache::Memcached などのライブラリを使うよりは利点があると思っています。

Driver::Memory

依存ライブラリ無しでかつ on memory でデータの管理をしてくれるドライバです。

sort や where や index, unique を始めとした Driver::DBI とほぼ同等のクエリが利用出来ます。

一応 Driver::DBI と同じテストコードを通しているので品質もそこそこです。

Driver::Logic

モデルロジック処理をデータソースとして扱うためのラッパーを書くたに作りましたがちょっと不評ちゃんです。

もうちょっと作戦立ててから作り替えて使いやすくしようと思ってますが、あまり使って欲しくないので undocumented なのです。

Driver::HASH

スキーマレスになデータモデルに好きなときに好きなだけ index はれたりするような物を作ろうとしてますが現在コードがありません。

Driver::DBI::MasterSlave

Driver::Queue::Q4M

Driver::Cache

上記3種類はそれぞれ個別で紹介しようと思います。

スキーマ定義の設定

最初の方でスキーマ定義を下だけではデータソースを使うことができませんとありました。

実際にスキーマ定義と Driver を紐づける必要がありますので以下で紹介します。

ちなみにここでのサンプルは全て Data::Model::Driver::Memory を使ってます余計なコードないので。

スキーマ定義の中で全テーブルに設定する

基本的に DB サーバの database の単位や、役割ごとにスキーマ定義ファイルを書くと思いますが、そういった場合はもちろんスキーマクラスの中で定義されている DSN やら DB サーバは同一になるはずなので一括で Driver の設定を行います。

package MyDatabase;
use strict;
use warnings;
use base 'Data::Model';
use Data::Model::Schema;
use Data::Model::Driver::Memory;
my $driver = Data::Model::Driver::Memory->new;

# MyBookmark の中で定義したテーブル全てで $driver を使う
base_driver $driver;

base_driver 関数でスキーマ定義全体で使う Driver を設定します。

テーブル毎に Driver を変える

基本的にはありえないのですが、テーブル毎に driver を変える事が出来ます。

package MyDatabase;
use strict;
use warnings;
use base 'Data::Model';
use Data::Model::Schema;
use Data::Model::Driver::Memory;
my $driver1 = Data::Model::Driver::Memory->new;

# MyBookmark の中で定義したテーブル全てで $driver1 を使う
base_driver $driver1;
install_model yappo => schema {
};

my $driver2 = Data::Model::Driver::Memory->new;
install_model nekokak => schema {
    # このテーブルだけ $driver2 をつかう
    driver $driver2;
};

# kan さんは $driver1
install_model kan => schema {
};

driver は install_model の定義の中だけで使えます。

base_driver で設定した driver を部分的に上書きするので、 yappo, kan は $driver1 を使って nekokak は $driver2 を使います。

使うときに設定する

スキーマ定義の中だけではなくて、そのスキーマ定義を実際に利用する時に定義することが出来ます。

これは Web フレームワークの中に Data::Model を組み込んだ際に実行環境によって Driver の設定を変えたい時に利用すると便利になります。

    my $model = MyDatabase->new;

    # MyDatabase の base_driver として $driver1 を設定する
    my $driver1 = Data::Model::Driver::Memory->new;
    $model->set_base_driver( $driver1 );

    # MyDatabase の nekokak テーブルの driver として $driver2 を設定する
    my $driver2 = Data::Model::Driver::Memory->new;
    $model->set_driver( nekokak => $driver2 );

スキーマ定義の時に使った driver と base_driver に set_ の接頭辞をつけたメソッドをスキーマオブジェクトにはやして使います。

その他関連メソッド

今これを書いてる時に気がついたのですがスキーマクラスに生えている set_driver や set_base_driver が undocument でした。

ついでに関連する未文書なメソッドを紹介します。

driver 定義を取得する

set_driver や set_base_driver のついとなる get_driver などのメソッドがあります。

    my $model = MyDatabase->new;

    # MyDatabase の base_driver を取り出す
    $model->get_base_driver;

    # MyDatabase の nekokak テーブルの driver をとりだす
    $model->get_driver( 'nekokak' );

定義されたテーブルの一覧を取り出す

スキーマ定義にて定義した install_model もテーブルの一覧を返すメソッドがあります。

    my $model = MyDatabase->new;
    # 定義されたテーブルのリストを返す
    # yappo, nekokak, kan が返る
    say join ',', $model->schema_names;

普通の人はあまり使わないかもしれませんが Data::Model->as_sqls にて以下のように使っています。

sub as_sqls {
    my $self   = shift;
    my $target = shift;
    my @sql = ();
    for my $model ($self->schema_names) {
        next if $target && $model ne $target;
        push @sql, $self->get_schema($model)->sql->as_sql;
    }
    @sql;
}

まとめ

本日は Data::Model の重要な要素の Driver に関して紹介しました。

どのようにしてデータソースとつなげるかが理解できたかと思います。

これからラストまで Driver 関連の解説を行う予定です。