In my recent Class::DBI wanderings, I found that Class::DBI::AbstractSearch doesn't support limit or offset. So, I decided to subclass it and create Class::DBI::AbstractSearch::Pg. But I didn't see an easy way to re-use the base code (i.e. intercept the limit and offset options, then call the SUPER class) without changing how it was implemented as well.
For something so small and simple, what is your opinion over which is better - extending the base to be inheritable by various sub-classes (Pg, MySQL, Oracle, etc) or just copy-n-paste the code, given how simple and unlikely it is to change.
A secondary question: Is this worthy of CPAN, or should I just save it for my own toolbox (or just post it to the catacombs)?
Here's the diff for the Pg version against the base version (to show how trivial the copy-n-paste changes are), as well as the full code for the Pg version.
I'm well aware of the arguments for going whole hog and patching the base to be subclassable - all the OO reasons, etc. - just wondering if the benefits outweigh the effort in this case.
Thanks for your time.
dcvr69
Full module:$ diff `pdng -l Class::DBI::AbstractSearch` Pg.pm 1c1 < package Class::DBI::AbstractSearch; --- > package Class::DBI::AbstractSearch::Pg; 5c5 < $VERSION = 0.05; --- > $VERSION = 0.01; 18a19,21 > my $limit = ($attr) ? delete($attr->{limit}) : undef; > my $offset = ($attr) ? delete($attr->{offset}) : undef; > 30a34,43 > > if ( defined $limit ) { > $limit = int($limit) unless uc($limit) eq 'ALL'; > $phrase .= " LIMIT $limit" > } > if ( defined $offset ) { > $offset = int($offset); > $phrase .= " OFFSET $offset" > } >
package Class::DBI::AbstractSearch::Pg; use strict; use vars qw($VERSION @EXPORT); $VERSION = 0.01; require Exporter; *import = \&Exporter::import; @EXPORT = qw(search_where); use SQL::Abstract; sub search_where { my $class = shift; my $where = (ref $_[0]) ? $_[0] : { @_ }; my $attr = (ref $_[0]) ? $_[1] : undef; my $order = ($attr) ? delete($attr->{order_by}) : undef; my $limit = ($attr) ? delete($attr->{limit}) : undef; my $offset = ($attr) ? delete($attr->{offset}) : undef; # order is deprecated, but still backward compatible if ($attr && exists($attr->{order})) { $order = delete($attr->{order}); } $class->can('retrieve_from_sql') or do { require Carp; Carp::croak("$class should inherit from Class::DBI >= 0.90"); }; my $sql = SQL::Abstract->new(%$attr); my($phrase, @bind) = $sql->where($where, $order); $phrase =~ s/^\s*WHERE\s*//i; if ( defined $limit ) { $limit = int($limit) unless uc($limit) eq 'ALL'; $phrase .= " LIMIT $limit" } if ( defined $offset ) { $offset = int($offset); $phrase .= " OFFSET $offset" } return $class->retrieve_from_sql($phrase, @bind); } 1; __END__ =head1 NAME Class::DBI::AbstractSearch::Pg - Abstract Class::DBI's SQL with SQL::Abstract =head1 SYNOPSIS package CD::Music; use Class::DBI::AbstractSearch::Pg; package main; my @music = CD::Music->search_where( artist => [ 'Ozzy', 'Kelly' ], status => { '!=', 'outdated' }, ); my @misc = CD::Music->search_where( { artist => [ 'Ozzy', 'Kelly' ], status => { '!=', 'outdated' } }, { order_by => "reldate DESC", limit => 20, offset => 0, }); =head1 DESCRIPTION Class::DBI::AbstractSearch::Pg is a Class::DBI plugin to glue SQL::Abstract into Class::DBI - with extensions to allow for LIMIT and OFFSET as provided by Postgresql. =head1 METHODS Using this module adds following methods into your data class. =over 4 =item search_where $class->search_where(%where); Takes a hash to specify WHERE clause. See L<SQL::Abstract> for hash options. $class->search_where(\%where,\%attrs); Takes hash reference to specify WHERE clause. See L<SQL::Abstract> for hash options. Takes a hash reference to specify additional query attributes. Class::DBI::AbstractSearch uses these attributes: =over 4 =item * B<order_by> Array reference of fields that will be used to order the results of your query. B<limit> Scalar used to limit the number of records returned by the search. Any value other than /ALL/i will be converted to an int and added to the sql generated. B<offset> Scalar that detemines how many records to skip in the results. Is converted to an int before being added to the sql generated. =back Any other attributes are passed to the SQL::Abstract constructor, and can be used to control how queries are created. For example, to use 'AND' instead of 'OR' by default, use: $clsas->search_where(\%where, { logic => 'AND' }); =head1 AUTHOR James Helm E<lt>jjhelm@att.net<gt>. Based on L<Class::DBI::AbstractSearch> by: Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt> This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L<Class::DBI::AbstractSearch>, L<Class::DBI>, L<SQL::Abstract> =cut
In reply to Inherit or copy-n-paste? by dcvr69
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |