in reply to Re^3: Moose + ORM
in thread Moose + ORM

Thank you very much for this. I tinkered around with my code last night and realized that I should not be exporting like that. This is what I came up with:
package Table; use DBI; use Moose; use Moose::Exporter; Moose::Exporter->setup_import_methods( with_caller => [ 'has_table' ] +); sub has_table { my $class = shift; my $table = shift; my %args = @_; my $rows = _get_table_rows( $table ); # this is just so client doesn't have to pass table name to load() $class->meta->add_attribute( '_table', is => 'ro', reader => 'tabl +e', default => $table ); for my $row (@$rows) { $class->meta->add_attribute( $row->{Field}, is => 'rw' ); } } sub load { my $self = shift; my %args = @_; my %fields = map { /^set_(\w+)$/; $1 => $_ } grep /^set_/, map $_->name, $self->meta->get_all_methods ; my $dbh = DBI->connect( ... ); my $table = $self->table; my $fields = join( ', ', keys %fields ); my $record = $dbh->selectrow_hashref( "select $fields from $table +where id = ?", undef, $self->get_id ); for my $field (keys %fields) { my $writer = $fields{$field}; $self->$writer( $record->{$field} ); } } package Table::Loader; use Moose::Role; sub BUILD { my $self = shift; if ($self->get_id) { Table::load( $self, id => $self->get_id ); } } package MyTable; use Moose::Policy 'Moose::Policy::FollowPBP'; use Moose; use Table; with 'Table::Loader'; has_table 'my_table'; # psuedo code package main; my $table = MyTable->new( id => 1 );
I wonder what kind of contracts I am breaking with any class that wants to use this ... but it seems to work. The trick is loading the data into the object after it has been defined.

Question if you have the gumption ... how would you handle loading the data? How would you pass the unique identifier of the database table row to be loaded into your MooseX::Role::Parameterized solution? That's the trouble I seem to have now, and hence why I added the Table::Loader role.

Thanks again!

Replies are listed 'Best First'.
Re^5: Moose + ORM
by stvn (Monsignor) on Jul 24, 2009 at 17:15 UTC
    Question if you have the gumption ... how would you handle loading the data?

    Honestly, I would have used DBIx::Class or Fey::ORM. I wrote my own ORM years ago when SPOPS was state of the art and Class::DBI was still very much an ugly/dirty hack. I won't ever write one again, it is a solved problem and I have no interest in re-inventing that wheel.

    First, it is very much not recommended to put a BUILD method in roles because it could get overridden by a local class version. You should do a before/after/around for BUILD instead, which will do what you want it to do.

    Second, I would get rid of the BUILD method anyway and put the load function into the role and then call  MyTable->load( id => 1 ) to get things from the DB, because using new to fetch from the database is misleading since it is not creating a new instance, but loading an old one.

    -stvn
      Would you have used one of those two modules inside a Moose role? Or would you not use Moose at all?

      Thank you so very much for your BUILD suggestions ... I took a stab at implementing them and broke my code horribly. :) Third time is a charm ... so I'll take a rest before I attempt my second try. ;)

        Would you have used one of those two modules inside a Moose role?

        No, I would have just used one of those modules.

        The role is actually irrelevant here. Both of those modules do exactly what you are trying to do but are much more featureful and battle-tested (DBIx::Class somewhat more so then Fey::ORM, but Fey::ORM is written by Dave Rolsky who writes some pretty tight code).

        Or would you not use Moose at all?

        Fey::ORM is written in Moose already, and DBIx::Class will be written in Moose before too much longer so using it now means it will eventually be Mooseified (and i will have to do is upgrade).

        -stvn