From: Matt S Trout Date: Wed, 16 Oct 2019 01:03:49 +0000 (+0000) Subject: try to fold custom join conds back to something DBIC will allow X-Git-Tag: v2.000000~3^2~2 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=09cfd2c811356002fcea90881d258cf4b0b22e0f;p=dbsrgits%2FSQL-Abstract.git try to fold custom join conds back to something DBIC will allow --- diff --git a/Changes b/Changes index c042198..a65608d 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,7 @@ Revision history for SQL::Abstract + - Collapse custom join conditions back to something DBIC might understand + 1.90_03 - 2019-10-13 - Add proof of concept DBIx::Class::SQLMaker::Role::SQLA2Passthrough - _where_field_IN/BETWEEN are documented as subclassable; feature restored diff --git a/examples/sqla2passthrough.pl b/examples/sqla2passthrough.pl index 4cf87b9..8a6d051 100644 --- a/examples/sqla2passthrough.pl +++ b/examples/sqla2passthrough.pl @@ -21,7 +21,8 @@ use With::Roles; use DBIx::Class::SQLMaker::Role::SQLA2Passthrough qw(on); MySchema->source('Foo')->add_relationship(bars => 'Bar' => on { +{ 'foreign.x' => 'self.x', - 'self.y' => { -between => [ qw(foreign.y1 foreign.y2) ] } + 'foreign.y1' => { '<=', 'self.y' }, + 'foreign.y2' => { '>=', 'self.y' }, }; }); } @@ -44,7 +45,7 @@ $s->storage warn ref($s->storage->sql_maker); my $rs2 = $s->resultset('Foo')->search({ - -op => [ '=', { -ident => 'outer.y' }, { -ident => 'me.x' } ] + -op => [ '=', { -ident => 'outer.x' }, { -ident => 'me.y' } ] }, { 'select' => [ 'me.x', { -ident => 'me.z' } ], '!with' => [ outer => $rs->get_column('x')->as_query ], @@ -56,3 +57,11 @@ my $rs3 = $s->resultset('Foo') ->search({}, { prefetch => 'bars' }); ::Dwarn(${$rs3->as_query}->[0]); + +$s->source('Foo')->result_class('DBIx::Class::Core'); +$s->source('Foo')->set_primary_key('x'); + +my $rs4 = $s->resultset('Foo')->new_result({ x => 1, y => 2 }) + ->search_related('bars'); + +::Dwarn(${$rs4->as_query}->[0]); diff --git a/lib/DBIx/Class/SQLMaker/Role/SQLA2Passthrough.pm b/lib/DBIx/Class/SQLMaker/Role/SQLA2Passthrough.pm index d7db581..04a5434 100644 --- a/lib/DBIx/Class/SQLMaker/Role/SQLA2Passthrough.pm +++ b/lib/DBIx/Class/SQLMaker/Role/SQLA2Passthrough.pm @@ -50,19 +50,64 @@ around select => sub { sub expand_join_condition { my ($self, $cond, $args) = @_; + my ($type, %known) = do { + if (my $obj = $args->{self_result_object}) { + (self => $obj->get_columns) + } elsif (my $val = $args->{foreign_values}) { + (foreign => %$val) + } else { + ('') + } + }; + my $maybe = $type ? 1 : 0; + my $outside; my $wrap = sub { my ($orig) = @_; + $outside = $orig; sub { my $res = $orig->(@_); - my ($name, @rest) = @{$res->{-ident}}; + my ($name, $col) = @{$res->{-ident}}; if ($name eq 'self' or $name eq 'foreign') { - $res->{-ident} = [ $args->{"${name}_alias"}, @rest ]; + if ($type eq $name) { + $maybe = 0 unless exists $known{$col}; + } + return { -ident => [ $args->{"${name}_alias"}, $col ] }; } return $res; }; }; my $sqla = $self->clone->wrap_op_expander(ident => $wrap); - $sqla->expand_expr($cond, -ident); + my $aqt = $sqla->expand_expr($cond, -ident); + return $aqt unless $maybe; + my $inner_wrap = sub { + my $res = $outside->(@_); + my ($name, $col) = @{$res->{-ident}}; + if ($name eq 'self' or $name eq 'foreign') { + if ($type eq $name) { + return { -bind => [ $args->{"${name}_alias"}.'.'.$col, $known{$col} ] }; + } + return { -ident => [ $args->{"${name}_alias"}, $col ] }; + } + return $res; + }; + $sqla->op_expander(ident => $inner_wrap); + my $inner_aqt = $self->_collapsify($sqla->expand_expr($cond, -ident)); + return ($aqt, $inner_aqt); +} + +sub _collapsify { + my ($self, $aqt) = @_; + return $aqt unless my @opargs = @{$aqt->{-op}}; + my ($logop, @args) = @opargs; + return $aqt unless $logop eq 'and'; + my %collapsed = map { + my $q = $_; + return $aqt unless my @opargs = @{$q->{-op}}; + my ($op, $lhs, @rest) = @opargs; + return $aqt unless my @ident = @{$lhs->{-ident}}; + (join('.', @ident), { $op => \@rest }); + } @args; + return \%collapsed; } 1;