views:

88

answers:

2

Currently we use DBIx::Class::Schema::Loader to generate and regenerate (when our db schema changes) a set of Result classes.

We add additional relationships and methods to the bottom of these classes and this is causing merge hell when people regenerate or change the schema.

We would like to maintain our custom changes in a separate set of files that sit in parallel with the auto-generated ones.

Is there a simple, clean, recommended way of doing this?

A: 

I ran into the same problem. You can just create another class that inherits from the generated classes. However, you need to pull over the table reference, and the relationships into the class you are editing, but you can leave the column definitions and what not in the generated class. I basically wrote a helper for the loader that generates the classes into an "Immutable" namespace, and creates a child for each of them in a "Mutable" namespace along with the table name reference and the relationships from the generated model. It seems to work reasonably well, and I no longer have to worry about developers editing the generated section of the class. I should probably write up the whole thing in a blog post one of these days.

jjafuller
Sounds like you are on the right lines :)
Tom
A: 

I solved it by Moosifying the schemas and then creating a set of Moose::Roles that I apply to the Schema classes just after schema->connection();

It goes a little like this:

my $schema = My::Schema->connection();

foreach my $source ($schema->sources) {

    my $domain_pkg = "My::Domain::$source";

    eval  "require $domain_pkg";

    # ignore failures due to file-not-found
    if ($@ && $@ =~/^Can't locate.*INC/) {

    # but barf if class doesnt compile
    } elsif ($@) {
        confess "Failed to load $domain_pkg for $pkg!!: - $@";

    # re-register domain class with the resultsource
    # and apply the role 
    } else {
        my $schema_pkg = "${pkg}::$source";
        $c->register_class($source, $schema_pkg);

        use Moose::Util;
        # check schema is moosyfied
        if ( $schema_pkg->can('meta') ) {
            my $meta = $schema_pkg->meta;

            eval {
                Moose::Util::apply_all_roles($meta, $domain_pkg);
            };
            if ($@) {
                confess "Failed to add $domain_pkg role to $schema_pkg: $@\n";
            } else {
                l4p->info("Found and applied Domain role: '$domain_pkg' for schema: '$schema_pkg'");
            }

        } else {
            warn "Cant call meta on $schema_pkg. ";
        }

    }

}

Nearby..

use MooseX::Declare 

role My::Domain::Person {

    # modify schema
    My::Schema::Person->inflate_column( ..);
    My::Schema::Person->belongs_to(..);
    My::Schema::Person->set_primary_key(..);

    # add some method modifiers to check/modify construction 
    around new (ClassName $class : $params) {

        munge params..

        $self->$orig($params);
    }

    # post insert hook
    after insert () {
        do_something..
    }

    # domain methods
    sub fullname {
         $self->firstname.' '.$self->surname;
    }



}
Tom