custom resultsource and subclasses

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

custom resultsource and subclasses

Mitchell Elutovich
I have the need for a custom resultsource based on the SQL select of a union of multiple tables; I would like to have a different subclass associated with each table and I would have a column which indicated which subclass to choice.  In a normal result set I know that there is an inflate_result method called which I can hook into to have the results blessed correctly; does the inflate_result or equivalent get used for a custom resultsource ?

_______________________________________________
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@...
Reply | Threaded
Open this post in threaded view
|

Re: custom resultsource and subclasses

Alexander Hartmaier
On 2014-05-28 13:51, Mitchell Elutovich wrote:
I have the need for a custom resultsource based on the SQL select of a union of multiple tables; I would like to have a different subclass associated with each table and I would have a column which indicated which subclass to choice.  In a normal result set I know that there is an inflate_result method called which I can hook into to have the results blessed correctly; does the inflate_result or equivalent get used for a custom resultsource ?
HI Mitchell,
please tell us what you try to achieve and why you think that a custom result source is the right solution.


_______________________________________________
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@...



*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
T-Systems Austria GesmbH Rennweg 97-99, 1030 Wien
Handelsgericht Wien, FN 79340b
*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*
Notice: This e-mail contains information that is confidential and may be privileged.
If you are not the intended recipient, please notify the sender and then
delete this e-mail immediately.
*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*"*

_______________________________________________
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@...
Reply | Threaded
Open this post in threaded view
|

Re: custom resultsource and subclasses

Louis Erickson
In reply to this post by Mitchell Elutovich

You mean like DBIx::Class::DynamicSubclass?  The only odd part is the union of sql select, which sounds like a view to me.

On May 28, 2014, at 4:51 AM, Mitchell Elutovich <[hidden email]> wrote:

I have the need for a custom resultsource based on the SQL select of a union of multiple tables; I would like to have a different subclass associated with each table and I would have a column which indicated which subclass to choice.  In a normal result set I know that there is an inflate_result method called which I can hook into to have the results blessed correctly; does the inflate_result or equivalent get used for a custom resultsource ?
_______________________________________________
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@...


_______________________________________________
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@...
Reply | Threaded
Open this post in threaded view
|

Re: custom resultsource and subclasses

Mitchell Elutovich
In reply to this post by Mitchell Elutovich
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).

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. 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).

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@...
Reply | Threaded
Open this post in threaded view
|

Re: custom resultsource and subclasses

Lianna Eeftinck
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 <[hidden email]> 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).

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. 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).

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@...


_______________________________________________
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@...
Reply | Threaded
Open this post in threaded view
|

Re: custom resultsource and subclasses

Louis Erickson
In reply to this post by Mitchell Elutovich

On May 28, 2014, at 3:43 PM, Mitchell Elutovich <[hidden email]> 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.

You could also put all the user methods in a Role and use it in both places.


_______________________________________________
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@...