[Dbix-class] Should DBIC prefix the table alias on columns in a WHERE?

Peter Rabbitson rabbit+dbic at rabbit.us
Wed May 12 16:48:16 GMT 2010


Bill Moseley wrote:
>     my $rs1 = $schema->resultset( 'Artist' )->search( { id => 3 } );
>     print Dumper $rs1->as_query;
> 
> ...
> 
> So, my question is should (or can??) DBIC add the alias to the "id" in
> the WHERE?  The problem, of course, is if there's a join with another
> table that also has an "id" column.

No. You qualify yourself as DBIC can not possibly know what you meant.

> Why would I want to set the alias?   Why did this come up?  It's obscure
> and easy for me to work around, but if you must know read on:
> 
> Say my Music data base hash this hierarchy:
> 
>   label has artists has cds has tracks
> 
> And say a label has a column "disabled" that I want to check for every
> query for a label's child objects.
> 
> my $artist_rs = $schema->resultset('Artist')->search(
>     { 'me.id <http://me.id>' => $id, 'label.disabled' => 0 },
>     { join => 'label' },
>  );
> 
> my $cd_rs = $schema->resultset( 'CD' )->search(
>     { 'me.id <http://me.id>' => $id, 'label.disabled' => 0 },
>     { join =>  { artist => 'label' } },
>  );
> 
> In real life, the label has a number of columns that must be tested --
> and there might be further joins to an access control table to see if
> the current user has access to that label, etc.  So, to avoid repeating
> that every place an object is fetched I have a method that adds those.
>  For example:
> 
> sub add_label_checks {
>     my $rs = shift;
>     my $new_rs = $rs->search( { 'label.disabled' => 0 } );
> 
>     # more tests ....
> 
>     return $new_rs;
> }
> 
> Then can do this:
> 
> my $artist_rs = $schema->resultset('Artist')->search(
>     { 'me.id <http://me.id>' => $id },
>     { join => 'label' },
>  )
> 
> $artist_rs = add_label_check( $artist_rs );  # add in access checks
> 
> All that's needed is to set the join condition up to label.

Why?

my $new_rs = $rs->search ({ 'label.disabled' => 0}, { join => 'label' });

> 
> 
> The problem is then when I want to fetch a label object:
> 
> $label_rs = $schema->resultset( 'Label' )->search( { 'me.id
> <http://me.id>' => 1 } );
> 
> $label_rs = add_label_check( $label_rs );
> 
> That won't work because add_label_check is using "label.disabled"
> instead of "me.disabled",

Right. What you should be doing in add_label_checks is simply test
if the $rs fed to you is a Label $rs or something else.

> #1 is ugly, and #2 is a bit awkward because I have a base Catalyst
> chained CRUD class that I use for any object that automatically adds in
> the primary key lookup for GET PUT and DELETE requests.  It currently
> does this:
> 
>     my %criteria = ( 'me.' . $primary_keys[0] => $id );

This is totally wrong. This is *exactly* what current_source_alias is
for. You should use it in place of 'me'

> Of course I could do this in my CRUD controller:
> 
>     my $prefix = $self->alias || 'me';
>     my %criteria = ( $prefix . '.' . $primary_keys[0] => $id );
> 
> But it would be nice if I could simply do this:
> 
>     my %criteria = ( $primary_keys[0] => $id );
> 
> Because later I could do $new_rs = $rs->search(undef, { alias => 'label'
> } ); and DBIC would know to add the prefix to the un-prefixed "id".

Again - this will fail spectacularly when chaining is in play, and in
any case can not be done cleanly, as search-condition introspection is
simply lacking.



More information about the DBIx-Class mailing list