[Dbix-class] custom resultsource and subclasses
Lianna Eeftinck
liannaee at gmail.com
Thu May 29 08:25:30 GMT 2014
What we're doing to subclass is
basically this (
obviously we're
using Moose):
around inflate_result => sub {
my $orig = shift;
my $self = shift;
my $row = $self->$orig( @_ );
bless $row, __PACKAGE__ if ref( $row ) ne __PACKAGE__;
my $product_subclass;
foreach ( $row ) {
if ( $_->is_of_type_one ) { $product_subclass = 'One'; }
elsif ( $_->is_of_type_two ) { $product_subclass = 'Two'; }
elsif ( $_->is_of_type_three ) { $product_subclass = 'Three'; }
}
if ( defined $product_subclass ) {
$product_subclass = __PACKAGE__.'::'.$product_subclass;
$self->ensure_class_loaded( $product_subclass );
bless $row, $product_subclass;
}
return $row;
};
So if this is in Result/MySubclassableTable.pm, that would rebless to
Result/MySubclassableTable/One.pm and
its siblings.
The initial bless is there because we saw some rows being returned as a
subclassed object already (never truly understood why, but probably
interpreter persistence has to do with it) which broke things.
On 28 May 2014 23:43, Mitchell Elutovich <melutovich at gmail.com> wrote:
> *Louis Erickson:*
>
> *>*You mean like DBIx::Class::DynamicSubclass? The only odd part is the
> union of sql select, which sounds like a view to me.
> I'll have to think about the possibility of just using a view instead of a
> resultsource.
>
> Yes I've used DynamicSubclass in which it is described (in the
> Cookbook.pod#Dynamic_Sub-classing_DBIx::Class_proxy_classes) as:
>
> |DBIx::Class classes are proxy classes, therefore some different
> techniques need to be employed for more than basic subclassing. In this
> example we have a single user table that carries a boolean bit for |admin.
> We would like to give the admin users objects (DBIx::Class::Row) the same
> methods as a regular user but also special admin only methods. It doesn't
> make sense to create two separate proxy-class |files for this. We would be
> copying all the user methods into the Admin class. There is a cleaner way
> to accomplish this.
> |
> |Overriding the inflate_result method within the User proxy-class gives us
> the effect we want. This method is called by DBIx::Class::ResultSet when
> inflating a result from storage. So we grab the object being |returned,
> inspect the values we are looking for, bless it if it's an admin object,
> and then return it.
>
> Which based on this, I believe my question boils down to if I use a custom
> resultsource to select rows from the database, is DBIx::Class::ResultSet still
> used and does it still call the inflate_result method.
>
> Based on the following from the Cookbook it looks like the answer to the
> questions is that it is using ResultSet and I presume it should be calling
> inflate_result, but it will need testing(unless someone already knows this).
>
> Arbitrary SQL through a custom ResultSource<http://perl.mines-albi.fr/perl5.8.5/site_perl/5.8.5/DBIx/Class/Manual/Cookbook.html#arbitrary_sql_through_a_custom_resultsource>
>
> Sometimes you have to run arbitrary SQL because your query is too complex
> (e.g. it contains Unions, Sub-Selects, Stored Procedures, etc.) or has to
> be optimized for your database in a special way, but you still want to get
> the results as a the DBIx::Class::ResultSet manpage<http://perl.mines-albi.fr/perl5.8.5/DBIx/Class/ResultSet.html>.
> The recommended way to accomplish this is by defining a separate
> ResultSource for your query. You can then inject complete SQL statements
> using a scalar reference (this is a feature of the SQL::Abstract manpage<http://perl.mines-albi.fr/perl5.8.5/SQL/Abstract.html>
> ).
>
> Say you want to run a complex custom query on your user data, here's what
> you have to add to your User class:
>
> package My::Schema::User;
>
> use base qw/DBIx::Class/;
>
> # ->load_components, ->table, ->add_columns, etc.
>
> # Make a new ResultSource based on the User class
> my $source = __PACKAGE__->result_source_instance();
> my $new_source = $source->new( $source );
> $new_source->source_name( 'UserFriendsComplex' );
>
> # Hand in your query as a scalar reference
> # It will be added as a sub-select after FROM,
> # so pay attention to the surrounding brackets!
> $new_source->name( \<<SQL );
> ( SELECT u.* FROM user u
> INNER JOIN user_friends f ON u.id = f.user_id
> WHERE f.friend_user_id = ?
> UNION
> SELECT u.* FROM user u
> INNER JOIN user_friends f ON u.id = f.friend_user_id
> WHERE f.user_id = ? )
> SQL
>
> # Finally, register your new ResultSource with your Schema
> My::Schema->register_source( 'UserFriendsComplex' => $new_source );
>
> Next, you can execute your complex query using bind parameters like this:
>
> my $friends = [ $schema->resultset( 'UserFriendsComplex' )->search( {},
> {
> bind => [ 12345, 12345 ]
> }
> ) ];
>
> ... and you'll get back a perfect L<DBIx::Class::ResultSet>.
>
>
> _______________________________________________
> List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
> IRC: irc.perl.org#dbix-class
> SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
> Searchable Archive:
> http://www.grokbase.com/group/dbix-class@lists.scsys.co.uk
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.scsys.co.uk/pipermail/dbix-class/attachments/20140529/3ec1b214/attachment-0001.htm>
More information about the DBIx-Class
mailing list