|
NAMEGantry::Utils::Model - a general purpose Object Relational Model base class SYNOPSIS use base 'Gantry::Utils::Model';
sub get_table_name { return 'your_table'; }
sub get_sequence_name { return 'your_table_seq'; }
sub get_primary_col { return 'id'; }
sub get_essential_cols { return 'id, text_col'; }
sub get_primary_key { goto &get_id; }
sub set_id { croak "Can't change primary key"; }
sub get_id { return $_->[0]{id}; }
sub quote_id { return $_[1]; }
sub set_text_col {
my $self = shift;
my $value = shift;
$self->{text_col} = $value;
$self->{__DIRTY__}{text_col}++;
return $value;
}
sub get_text_col { return $_->[0]{text_col}; }
sub quote_text_col {
return ( defined $_[1] ) ? "'$_[1]'" : 'NULL';
}
sub set_other_text_col {
my $self = shift;
my $value = shift;
$self->{other_text_col} = $value;
$self->{__DIRTY__}{other_text_col}++;
return $value;
}
sub get_other_text_col {
my $self = shift;
unless ( defined $self->{other_text_col} ) {
$self->lazy_fetch( 'other_text_col' );
}
return $self->{other_text_col};
}
sub quote_other_text_col {
return ( defined $_[1] ) ? "'$_[1]'" : 'NULL';
}
DESCRIPTIONThis module is a Class::DBI replacement. Its goal is to reduce the mystery in the internals of that module, while still providing most of its functionality. You'll notice that the inheriting class has a lot more code than a Class::DBI subclass would. This is because we use Bigtop to generate the subclasses. Thus, we don't care so much about the volume of code. The result is code which is easy to read, understand, override and/or modify. RATIONALEClass::DBI and its cousins provide beautiful APIs for client code. By implementing straightforward database row to Perl object correspondence, they save a lot of mental effort when writing most applications. They do have drawbacks. My premise is that most of these drawbacks stem from a single fundamental design descision. Perl's traditional Object Relation Mappers (ORMs) do a lot of work at run time. For instance, they build accessors at run time. When I first started using them, I thought this was gorgeous. Class::DBI::mysql was one of my favorite modules. I bought the promise of a future where all you had to say was something like package MyModel;
use Class::DBI::SuperClever
'dbi:Pg:dbname=somedb', 'user', 'passwd', 'MyModel';
and the whole somedb database would be mapped without another word. Each table would become a class under MyModel with an accessor for each column. Then I could create, retrieve, update, and delete to my heart's content while beholding the power of Perl. The problem is that use statements like the above example require extreme magic (and not a small amount of time). This leads to a lack of transperency which leaves me with three problems: (1) I worry, in the back of my mind I always have the doubt of not knowing what is going on in these complex beasts (2) I get hit by subtle bugs, like name collisions from inheritence and inadvertant overriding (3) worst, I am left with a system that works really well to do the things the author thought of, but not the thing I really need to do in a particular instance (either because the system is inherently limiting or more likely because it is so complex I can't wrap my small mind around it well enough to carry out my task). This leads to the fundamental principle of this module: simplicity. Any programmer with intermediate Perl skills and a passing familiarity with SQL databases should be able to digest this in a morning. There are other goals, but simplicity is at the core. In order to achieve transperency, it is necessary to have more code in the subclasses. This is really why the magical schemes sprang up. But, recently I have been working on generation of code. This amounts to the same thing, but it happens ahead of time. So, instead of code being generated by magic during run time, my code is generated by grammar based parsing before compile time. The generator in question is bigtop which can build a completely funcational web app from a description of its data model and controllers. Then, when a programmer wonders what the model is up to, she has a set of simple modules which explicitly show what is going on. To make change, she may add methods or override the existing generated ones. METHODS PROVIDED BY THIS MODULE
METHODS SUBCLASSES MUST PROVIDEYou can include any useful method you like in your subclass, but these are the ones this module needs.
OMISSIONSThere is no caching. This means two things: (1) no sql statement is prepared with bind parameter place holders and stored for possible reuse (2) objects are always built for each row retrieved, even if there is a live object for that row elsewhere in memory. There are no triggers. If you need these, put them in the accessors as needed. Feel free to override construct. There are no iterators. Class::DBI makes iterators, but they only delay object instantiation, the full query results are pulled from the beginning. Replicating that behavior seems like the pursuit of diminishing returns. AUTHORPhil Crow <philcrow2000@yahoo.com> COPYRIGHT and LICENSECopyright (c) 2006, Phil Crow. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.
|