DBIx-Class-ResultSource-MultipleTableInheritance

 view release on metacpan or  search on metacpan

lib/DBIx/Class/ResultSource/MultipleTableInheritance.pm  view on Meta::CPAN

This only works with PostgreSQL at the moment. It has been tested with
PostgreSQL 9.0, 9.1 beta, and 9.1.

There is one additional caveat: the "parent" result classes that you
defined with this resultsource must have one primary column and it must
be named "id."

=head1 SYNOPSIS

    {
        package Cafe::Result::Coffee;

        use strict;
        use warnings;
        use parent 'DBIx::Class::Core';
        use aliased 'DBIx::Class::ResultSource::MultipleTableInheritance'
            => 'MTI';

        __PACKAGE__->table_class(MTI);
        __PACKAGE__->table('coffee');
        __PACKAGE__->add_columns(
            "id", { data_type => "integer" },
            "flavor", {
                data_type => "text",
                default_value => "good" },
        );

        __PACKAGE__->set_primary_key("id");

        1;
    }

    {
        package Cafe::Result::Sumatra;

        use parent 'Cafe::Result::Coffee';

        __PACKAGE__->table('sumatra');

        __PACKAGE__->add_columns( "aroma",
            { data_type => "text" }
        );

        1;
    }

    ...

    my $schema = Cafe->connect($dsn,$user,$pass);

    my $cup = $schema->resultset('Sumatra');

    print STDERR Dwarn $cup->result_source->columns;

        "id"
        "flavor"
        "aroma"
        ..

Inherit from this package and you can make a resultset class from a view, but
that's more than a little bit misleading: the result is B<transparently
writable>.

This is accomplished through the use of stored procedures that map changes
written to the view to changes to the underlying concrete tables.

=head1 WHY?

In many applications, many classes are subclasses of others. Let's say you
have this schema:

    # Conceptual domain model

    class User {
        has id,
        has name,
        has password
    }

    class Investor {
        has id,
        has name,
        has password,
        has dollars
    }

That's redundant. Hold on a sec...

    class User {
        has id,
        has name,
        has password
    }

    class Investor extends User {
        has dollars
    }

Good idea, but how to put this into code?

One far-too common and absolutely horrendous solution is to have a "checkbox"
in your database: a nullable "investor" column, which entails a nullable
"dollars" column, in the user table.

    create table "user" (
        "id" integer not null primary key autoincrement,
        "name" text not null,
        "password" text not null,
        "investor" tinyint(1),
        "dollars" integer
    );

Let's not discuss that further.

A second, better, solution is to break out the two tables into user and
investor:

    create table "user" (
        "id" integer not null primary key autoincrement,
        "name" text not null,
        "password" text not null



( run in 2.446 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )