[Dbix-class] custom join condition weirdness
Peter Mottram
peter at sysnix.com
Mon Dec 1 18:31:34 GMT 2014
I'm working on a custom join condition for use in
https://metacpan.org/pod/Interchange6::Schema full reasons for which are
hard to explain - maybe we'll get to that in a later email if
explanation is needed.
I've added a new relationship to my Product class:
has_many
current_price_modifiers => "Interchange6::Schema::Result::PriceModifier",
sub {
my $args = shift;
my $subquery =
$args->{self_resultsource}->schema->resultset('UserRole')
->search( { "me.users_id" => { '=' => \"?" } }
)->get_column('roles_id')
->as_query;
return (
{
"$args->{foreign_alias}.sku" =>
{ -ident => "$args->{self_alias}.sku" },
"$args->{foreign_alias}.end_date" => [ undef, { '>=', \"?"
} ],
"$args->{foreign_alias}.quantity" => { '<=', \"?" },
"$args->{foreign_alias}.roles_id" =>
[ undef, { -in => $subquery } ],
"$args->{foreign_alias}.start_date" => [ undef, { '<=', \"?"
} ],
},
);
};
This is consumed by a new method in ::ResultSet::Product:
sub with_selling_price {
my ( $self, $args ) = @_;
my $schema = $self->result_source->schema;
if ( defined($args) ) {
$self->throw_exception(
"argument to with_price_modifiers must be a hash reference")
unless ref($args) eq "HASH";
}
# we need a quantity
$args->{quantity} = 1 unless defined $args->{quantity};
my $dtf = $schema->storage->datetime_parser;
my $today = $dtf->format_datetime(DateTime->today);
my $rset = $self->search(
undef,
{
join => "current_price_modifiers",
bind => [
[ end_date => $today ],
[ quantity => $args->{quantity} ],
[ { sqlt_datatype => "integer" } => $args->{users_id} ],
[ start_date => $today ],
],
'+select' => [ { min => "current_price_modifiers.price" } ],
'+as' => [ "selling_price" ],
group_by => [ "product.sku" ],
}
);
return $rset;
}
Via a relation with Navigation through NavigationProduct link table I
have a query thus:
$products =
$nav->navigation_products->search_related('product')
->with_selling_price( { quantity => 10, users_id => 1 } );
A few weird things happen:
$products->count is zero but if I iterate through this resultset I get
the expected 3 results.
Iterating through my products I would expect to be able to use
$product->get_column('selling_price') to find the min price from the
related current_price_modifiers relation but it is always undef.
Using DBIC_TRACE I see the resulting query:
SELECT "product"."sku", "product"."name", "product"."short_description",
"product"."description", "product"."price", "product"."uri",
"product"."weight", "product"."priority", "product"."gtin",
"product"."canonical_sku", "product"."active",
"product"."inventory_exempt", "product"."created",
"product"."last_modified", MIN( "current_price_modifiers"."price" ) FROM
"navigation_products" "me" JOIN "products" "product" ON "product"."sku"
= "me"."sku" LEFT JOIN "price_modifiers" "current_price_modifiers" ON (
( "current_price_modifiers"."end_date" IS NULL OR
"current_price_modifiers"."end_date" >= ? ) AND
"current_price_modifiers"."quantity" <= ? AND (
"current_price_modifiers"."roles_id" IS NULL OR
"current_price_modifiers"."roles_id" IN ( SELECT "me"."roles_id" FROM
"user_roles" "me" WHERE ( "me"."users_id" = ? ) ) ) AND
"current_price_modifiers"."sku" = "product"."sku" AND (
"current_price_modifiers"."start_date" IS NULL OR
"current_price_modifiers"."start_date" <= ? ) ) WHERE (
"me"."navigation_id" = ? ) GROUP BY "product"."sku": '2014-12-01
00:00:00', '10', '1', '2014-12-01 00:00:00', '24'
In that query on the LHS I see MIN( "current_price_modifiers"."price" )
but the expected "AS selling_price" is missing - here is one clue but I
am completely baffled as to why.
The count problem is due to everything being collapsed so the bind
values no longer match:
SELECT COUNT( * ) FROM (SELECT "product"."sku" FROM
"navigation_products" "me" JOIN "products" "product" ON "product"."sku"
= "me"."sku" WHERE ( "me"."navigation_id" = ? ) GROUP BY
"product"."sku") "product": '2014-12-01 00:00:00', '10', '1',
'2014-12-01 00:00:00', '24'
I can get around that by grabbing the count before applying
with_selling_price so that is not such a hardship (cheaper on the db
anyway) but shows my lack of understanding of custom joins I guess. Do I
need to return a second join condition in my relation to fix that?
Hoping someone can shed some light on the missing 'AS selling_price'.
TIA
PeteM
More information about the DBIx-Class
mailing list