NAME

DBIx::Class::Schema::Slave - DBIx::Class::Schema for slave (EXPERIMENTAL)

CAUTION

DIBx::Class::Schema::Slave is EXPERIMENTAL and DO NOT use. Please check DBIx::Class::Storage::DBI::Replicated or DBIx::Class::Storage::DBI::Replication. DBIx::Class::Schema::Slave will be deleted.

SYNOPSIS

# In your MyApp::Schema (DBIx::Class::Schema based)
package MyApp::Schema;

use base 'DBIx::Class::Schema';

__PACKAGE__->load_components( qw/ Schema::Slave / );
__PACKAGE__->slave_moniker('::Slave');
__PACKAGE__->slave_connect_info( [
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    ...,
] );

# As it is now, DBIx::Class::Schema::Slave works out with DBIx::Class::Schema::Loader.
# If you use DBIx::Class::Schema::Loader based MyApp::Schema, maybe it is just like below.

# In your MyApp::Schema (DBIx::Class::Schema::Loader based)
package MyApp::Schema;

use base 'DBIx::Class::Schema::Loader';

__PACKAGE__->load_components( qw/ Schema::Slave / );
__PACKAGE__->slave_moniker('::Slave');
__PACKAGE__->slave_connect_info( [
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    ...,
] );
__PACKAGE__->loader_options(
    relationships => 1,
    components    => [ qw/
        ...
        ...
        ...
        Row::Slave # DO NOT forget to specify
        Core
    / ],
);

# Somewhere in your code
use MyApp::Schema;

# First, connect to master
my $schema = MyApp::Schema->connect( @master_connect_info );

# Retrieving from master
my $master = $schema->resultset('Track')->find( $id );

# Retrieving from slave
my $slave = $schema->resultset('Track::Slave')->find( $id );

See DBIx::Class::Schema.

DESCRIPTION

DBIx::Class::Schema::Slave is DBIx::Class::Schema for slave. DBIx::Class::Schema::Slave creates result_source classes for slave automatically, and connects slave datasources as you like (or at rondom). You can retrieve rows from either master or slave in the same way DBIx::Class::Schema provies but you can neither add nor remove rows from slave.

SETTIN UP DBIx::Class::Schema::Slave

Setting it up manually

First, load DBIx::Class::Schema::Slave as component in your MyApp::Schema.

# In your MyApp::Schema
package MyApp::Schema;

use base 'DBIx::Class::Schema';

__PACKAGE__->load_components( qw/ Schema::Slave / );

Set "slave_moniker" as you like. If you do not specify, ::Slave is set.

__PACKAGE__->slave_moniker('::Slave');

Set "slave_connect_info" as ARRAYREF of ARRAYREF.

__PACKAGE__->slave_connect_info( [
    [ 'dbi:mysql:database:hostname=host', 'user', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'user', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'user', 'passsword', { ... } ],
    ...,
] );

Next, you have MyApp::Schema::Artist, MyApp::Schema::Album, MyApp::Schema::Track, load these result_source classes.

__PACKAGE__->load_classes( qw/ Artist Album Track / );

In running "register_source", DBIx::Class::Schema::Slave creates slave result_source classes MyApp::Schema::Artist::Slave, MyApp::Schema::Album::Slave and MyApp::Schema::Track::Slave automatically. If you set ::MySlave to "slave_moniker", it creates MyApp::Schema::Artist::MySlave, MyApp::Schema::Album::MySlave and MyApp::Schema::Track::MySlave.

# MyApp::Schema::Artist wouldn't be loaded
# MyApp::Schema::Artist::Slave wouldn't be created
__PACKAGE__->load_classes( qw/ Album Track / );

I recommend every result_source classes to be loaded.

# Every result_source classes are loaded
__PACKAGE__->load_classes;

Next, load DBIx::Class::Row::Slave as component in your result_source classes.

# In your MyApp::Schema::Artist;
package MyApp::Schema::Artist;

use base 'DBIx::Class';

__PACKEAGE__->load_components( qw/ ... Row::Slave Core / );

Using DBIx::Class::Schema::Loader

As it is now, DBIx::Class::Schema::Slave WORKS OUT with DBIx::Class::Schema::Loader. First, load DBIx::Class::Schema::Slave as component in your MyApp::Schema.

# In your MyApp::Schema
package MyApp::Schema;

use base 'DBIx::Class::Schema::Loader';

__PACKAGE__->load_components( qw/ Schema::Slave / );

Set "slave_moniker" as you like. If you do not specify, ::Slave is set.

__PACKAGE__->slave_moniker('::Slave');

Set "slave_connect_info" as ARRAYREF of ARRAYREF.

__PACKAGE__->slave_connect_info( [
    [ 'dbi:mysql:database:hostname=host', 'user', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'user', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'user', 'passsword', { ... } ],
    ...,
] );

Call "loader_options" in DBIx::Class::Schema::Loader. DO NOT forget to specify DBIx::Class::Row::Slave as component.

__PACKAGE__->loader_options(
    relationships => 1,
    components    => [ qw/
        ...
        Row::Slave # DO NOT forget to load
        Core
    / ],
);

Connecting (Create Schema instance)

To connect your Schema, provive connect_info not for slave but for master.

my $schema = MyApp::Schema->connect( @master_connect_info );

Retrieving

Retrieving from master, you don't have to care about anything.

my $album_master     = $schema->resultset('Album')->find( $id );
my $itr_album_master = $schema->resultset('Album')->search( { ... }, { ... } );

Retrieving from slave, set slave moniker to "resultset".

my $track_slave     = $schema->resultset('Album::Slave')->find( $id );
my $itr_track_slave = $schema->resultset('Album::Slave')->search( { ... }, { ... } );

Adding and removing rows

You can either create a new row or remove some rows from master. But you can neither create a new row nor remove some rows from slave.

# These complete normally
my $track = $schema->resultset('Track')->create( {
    created_on  => $dt->now || undef,
    modified_on => $dt->now || undef,
    album_id    => $album->id || undef,
    title       => $title || undef,
    time        => $time || undef,
} );
$track->title('WORLD\'S END SUPERNOVA');
$track->update;
$track->delete;

# You got an error!
# DBIx::Class::ResultSet::create(): Can't insert via result source "Track::Slave". This is slave connection.
my $track = $schema->resultset('Track::Slave')->create( {
    created_on  => $dt->now || undef,
    modified_on => $dt->now || undef,
    album_id    => $album->id || undef,
    title       => $title || undef,
    time        => $time || undef,
} );

$track->title('TEAM ROCK');
# You got an error!
# DBIx::Class::Row::Slave::update(): Can't update via result source "Track::Slave". This is slave connection.
$track->update;

# And, you got an error!
# DBIx::Class::Row::Slave::delete(): Can't delete via result source "Track::Slave". This is slave connection.
$track->delete;

DO NOT call "update_all" in DBIx::Class::ResultSet, "delete_all" in DBIx::Class::ResultSet, "populate" in DBIx::Class::ResultSet and "update_or_create" in DBIx::Class::ResultSet via slave result_sources. Also you SHOULD NOT call "find_or_new" in DBIx::Class::ResultSet, "find_or_create" in DBIx::Class::ResultSet via slave result_sources.

CLASS DATA

slave_moniker

Moniker suffix for slave. ::Slave default.

# In your MyApp::Schema
__PACKAGE__->slave_moniker('::Slave');

IMPORTANT: If you have already MyApp::Schema::Artist::Slave, DO NOT set ::Slave to slave_moniker. Set ::SlaveFor or something else.

slave_connect_info

connect_infos ARRAYREF of ARRAYREF for slave.

# In your MyApp::Schema
__PACKAGE__->slave_connect_info( [
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    [ 'dbi:mysql:database:hostname=host', 'username', 'passsword', { ... } ],
    ...,
] );

slave_schema

Schema for slave. You can get this by "slave".

METHODS

register_source

Arguments: $moniker, $result_source
Return Value: none

Registers the DBIx::Class::ResultSource in the schema with the given moniker and re-maps class_mappings and source_registrations.

# Re-mapped class_mappings
class_mappings => {
    MyApp::Schema::Artist        => 'Artist',
    MyApp::Schema::Artist::Slave => 'Artist::Slave',
    MyApp::Schema::Album         => 'Album',
    MyApp::Schema::Album::Slave  => 'Album::Slave',
    MyApp::Schema::Track         => 'Track',
    MyApp::Schema::Track::Slave  => 'Track::Slave',
}

# Re-mapped source_registrations
source_registrations => {
    MyApp::Schema::Artist => {
        bless( {
            ...,
            ...,
            ...,
        }, DBIx::Class::ResultSource::Table )
    },
    MyApp::Schema::Artist::Slave => {
        bless( {
            ...,
            ...,
            ...,
        }, DBIx::Class::ResultSource::Table )
    },
    ...,
    ...,
    ...,
    MyApp::Schema::Track::Slave => {
        bless( {
            ...,
            ...,
            ...,
        }, DBIx::Class::ResultSource::Table )
    },
}

See "register_source" in DBIx::Class::Schema.

resultset

Arguments: $moniker
Return Value: $result_set

If $moniker is slave moniker, this method returns $result_set for slave. See "resultset" in DBIx::Class::Schema.

my $master_rs = $schema->resultset('Artist');
my $slave_rs  = $schema->resultset('Artist::Slave');

sources

Argunemts: none
Return Value: @sources

This method returns the sorted alphabetically source monikers of all source registrations on this schema. See "sources" in DBIx::Class::Schema.

# Returns all sources including slave sources
my @all_sources = $schema->sources;

master_sources

Argunemts: none
Return Value: @sources

This method returns the sorted alphabetically master source monikers of all source registrations on this schema.

my @master_sources = $schema->master_sources;

slave_sources

Argunemts: none
Return Value: @sources

This method returns the sorted alphabetically slave source monikers of all source registrations on this schema.

my @slave_sources = $schema->slave_sources;

slave_connect

Arguments: @info
Return Value: $slave_schema

This method creates slave connection, and store it in slave_schema. You can get this by "slave". Usualy, you don't have to call it directry.

slave

Getter for "slave_schema". You can get schema for slave if it stored in "slave_schema".

my $slave_schema = $schema->slave;

select_connect_info

Argunemts: none
Return Value: $connect_info

You can define this method in your schema class as you like. This method has to return $connect_info as ARRAYREF. If "select_connect_info" returns undef, undef value or not ARRAYREF, "_select_connect_info" will be called, and return $connect_info at random from "slave_connect_info".

# In your MyApp::Schame
sub select_connect_info {
    my $self = shift;

    my @connect_info = @{$self->slave_connect_info};
    my $connect_info;
    # Some algorithm to select connect_info here

    return $connect_info;
}

is_slave

Arguments: $string
Return Value: 1 or 0

This method returns 1 if $string (moniker, class name and so on) is slave stuff, otherwise returns 0.

__PACKAGE__->slave_moniker('::Slave');

# Returns 0
$self->is_slave('Artist');

# Returns 1
$self->is_slave('Artist::Slave');

# Returns 1
$self->is_slave('MyApp::Model::DBIC::MyApp::Artist::Slave');

__PACKAGE__->slave_moniker('::SlaveFor');

# Returns 0
$self->is_slave('Artist');

# Returns 1
$self->is_slave('Artist::SlaveFor');

# Returns 1
$self->is_slave('MyApp::Model::DBIC::MyApp::Artist::SlaveFor');

INTERNAL METHOD

_select_connect_info

Return Value: $connect_info

Internal method. This method returns $connect_info for slave as ARRAYREF. Usually, you don't have to call it directry. If you select $connect_info as you like, define "select_connect_info" in your schema class. See "select_connect_info" for more information.

AUTHOR

travail travail@cabane.no-ip.org

COPYRIGHT

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the LICENSE file included with this module.