Skip Menu |

This queue is for tickets about the Catalyst-Controller-DBIC-API CPAN distribution.

Report information
The Basics
Id: 93864
Status: resolved
Worked: 1 hour (60 min)
Priority: 0/
Queue: Catalyst-Controller-DBIC-API

People
Owner: abraxxa [...] cpan.org
Requestors: seth.daniel [...] openx.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: 2.006002



Subject: force 'OR' condition across columns?
Date: Fri, 14 Mar 2014 10:53:27 -0700
To: bug-Catalyst-Controller-DBIC-API [...] rt.cpan.org
From: Seth Daniel <seth.daniel [...] openx.com>
It doesn't seem that the equivalent of this is possible using C::C::DBIC::API: When giving multiple columns, with conditions, to the API it is an implicit AND between the columns. There is no way to change that to an 'OR' condition. The following SQL cannot be replicated using the API: select * from tableA where colA = 'foo' or colB = 'bar' The DBIC equivalent is: $d->resultset( 'resultSetA' ) ->search( { -or => [ colA => 'foo', colB => 'bar' ] } ); Is there some way to do this I am missing?
Hello. I also I thought I would want this feature. Thought this was going to ransack of Ruby is enviable. https://github.com/activerecord-hackery/ransack http://ransack-demo.herokuapp.com/users/advanced_search I wrote and tested patch in order to respond to this function. I'm glad if there is no problem, and get to the merge. Cheers, Tomohiro Hosaka
Subject: patch.txt
diff --git a/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm b/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm index 107dc80..b899e77 100644 --- a/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm +++ b/lib/Catalyst/Controller/DBIC/API/RequestArguments.pm @@ -477,6 +477,37 @@ JoinBuilder each layer of recursion. # might be a sql function instead of a column name # e.g. {colname => {like => '%foo%'}} + elsif ( $column eq '-or' or $column eq '-and' ) { + my $i = 0; + my $v = $param->{$column}; + + while (@$v > $i) { + if (not ref $v->[$i]) { + push @{$search_params->{$column}}, + $self->generate_column_parameters( + $source, + { $v->[$i] => $v->[++$i] }, + $join, + $base, + ); + } + elsif (HashRef->check($v->[$i])) { + while ( my ( $k2, $v2 ) = each %{$v->[$i]} ) { + push @{$search_params->{$column}}, + $self->generate_column_parameters( + $source, + { $k2 => $v2 }, + $join, + $base, + ); + } + } + else { + die "aa"; + } + ++$i; + } + } else { # but only if it's not a hashref unless ( ref( $param->{$column} ) diff --git a/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm b/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm index 7631654..aab5232 100644 --- a/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm +++ b/lib/Catalyst/Controller/DBIC/API/StoredResultSource.pm @@ -110,7 +110,27 @@ sub check_column_relation { if ( HashRef->check($col_rel) ) { try { while ( my ( $k, $v ) = each %$col_rel ) { - $self->check_has_relation( $k, $v, undef, $static ); + if ($k eq '-or' or $k eq '-and') { + die unless ArrayRef->check($v); + my $i = 0; + while (@$v > $i) { + if (not ref $v->[$i]) { + $self->check_column_relation( { $v->[$i] => $v->[++$i] } ); + } + elsif (HashRef->check($v->[$i])) { + while ( my ( $k2, $v2 ) = each %{$v->[$i]} ) { + $self->check_column_relation( { $k2 => $v2 } ); + } + } + else { + die; + } + ++$i; + } + } + else { + $self->check_has_relation( $k, $v, undef, $static ); + } } } catch { diff --git a/t/rest/list.t b/t/rest/list.t index a7a6eb6..747948b 100644 --- a/t/rest/list.t +++ b/t/rest/list.t @@ -210,6 +210,129 @@ my $track_list_url = "$base/api/rest/track"; ); } +# -and|-or condition +{ + my @or_variants = ( + # -or + [ + search => { + title => [qw(Yowlin Howlin)], + }, + ], + [ + search => { + -or => [ + title => [qw(Yowlin Howlin)], + ], + }, + ], + [ + search => { + -or => [ + title => [qw(Yowlin)], + title => [qw(Howlin)], + ], + }, + ], + [ + search => { + -or => [ + { title => [qw(Yowlin)] }, + { title => [qw(Howlin)] }, + ], + }, + ], + # -and + [ + search => { + cd => 2, + position => [1, 2], + }, + ], + [ + search => { + -and => [ + cd => 2, + position => [1, 2], + ], + }, + ], + # -and & -or + [ + search => { + -or => [ + -and => [ + cd => 2, + position => [0, 1], + ], + -and => [ + cd => 2, + position => [0, 2], + ], + ], + }, + ], + [ + search => { + -or => [ + { + -and => [ + cd => 2, + position => [0, 1], + ], + }, + { + -and => [ + cd => 2, + position => [0, 2], + ], + }, + ], + }, + ], + [ + search => { + -or => [ + { + -and => [ + cd => 2, + position => [0, 1], + ], + }, + { + -and => [ + cd => 2, + position => [0, 2], + ], + }, + ], + }, + ], + ); + + for (@or_variants) { + my %q = (@$_); + + is $schema->resultset('Track')->search($q{search})->count, 2, 'check -and|-or search param correctness'; + + my $uri = URI->new($track_list_url); + $uri->query_form( map { $_ => encode_json($q{$_}) } keys %q ); + my $req = GET( $uri, 'Accept' => 'text/x-json' ); + $mech->request($req); + cmp_ok( $mech->status, '==', 200, 'attempt with -or search okay' ); + my $response = $json->decode( $mech->content ); + my @expected_response = map { + { $_->get_columns } + } $schema->resultset('Track')->search($q{search})->all; + is_deeply( + $response, + # track does set use_json_boolean + { list => \@expected_response, success => JSON::true, totalcount => 2 }, + 'correct data returned for -and|-or search param' + ) or diag Dumper \%q; + } +} + { my $uri = URI->new($artist_list_url); $uri->query_form( { 'search.cds.track.title' => 'Suicidal' } );
For arbitary complex search arguments the search_arg request parameter is intended. Its default value is 'search' which means that you can pass a JSON string to it, for example: /api/track?search={"-or":[ { "title": "Yowlin" }, { "title": "Howlin" } ]} Please take a look at t/rpc/list_json_search.t and patch it to include one or more tests for -or and -and. A patch like yours shouldn't be needed as DBIC::API passes the data structure straight to DBIC after doing the JSON decoding.
Subject: Re: [rt.cpan.org #93864] force 'OR' condition across columns?
Date: Tue, 1 Jul 2014 11:08:55 -0700
To: bug-Catalyst-Controller-DBIC-API [...] rt.cpan.org
From: Seth Daniel <seth.daniel [...] openx.com>
When I try a search with "-or" as you describe in your response the API thinks that "-or" is a column and the search fails with an error. Here is a patch to t/rpc/list_json_search.t: diff --git a/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t b/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t index e8db665..259f494 100644 --- a/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t +++ b/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t @@ -76,6 +76,24 @@ my $base_rs = { my $uri = URI->new($artist_list_url); + $uri->query_form( + { 'search' => '{ "-or": { "name": "We Are Goth" },{ "id": "1" }}' } ); + my $req = GET( $uri, 'Accept' => 'text/x-json' ); + $mech->request($req); + cmp_ok( $mech->status, '==', 200, 'attempt with related search okay' ); + diag explain $req; BAIL_OUT(''); + my @expected_response = map { + { $_->get_columns } + } $schema->resultset('Artist') + ->search( { 'cds.title' => 'Spoonful of bees' }, { join => 'cds' } ) + ->all; + my $response = $json->decode( $mech->content ); + is_deeply( { list => \@expected_response, success => 'true' }, + $response, 'correct data returned for complex query' ); +} + +{ + my $uri = URI->new($artist_list_url); $uri->query_form( { 'search.name' => '{"LIKE":"%waul%"}' } ); my $req = GET( $uri, 'Accept' => 'text/x-json' ); $mech->request($req); This test fails with a 400 HTTP return code. On Tue, Jul 1, 2014 at 8:18 AM, Alexander Hartmaier via RT < bug-Catalyst-Controller-DBIC-API@rt.cpan.org> wrote: Show quoted text
> <URL: https://rt.cpan.org/Ticket/Display.html?id=93864 > > > For arbitary complex search arguments the search_arg request parameter is > intended. Its default value is 'search' which means that you can pass a > JSON string to it, for example: > /api/track?search={"-or":[ { "title": "Yowlin" }, { "title": "Howlin" } ]} > > Please take a look at t/rpc/list_json_search.t and patch it to include one > or more tests for -or and -and. > A patch like yours shouldn't be needed as DBIC::API passes the data > structure straight to DBIC after doing the JSON decoding. >
Subject: Re: [rt.cpan.org #93864] force 'OR' condition across columns?
Date: Tue, 1 Jul 2014 11:54:22 -0700
To: bug-Catalyst-Controller-DBIC-API [...] rt.cpan.org
From: Seth Daniel <seth.daniel [...] openx.com>
my syntax was wrong in the "search" above, but even when I correct it I still receive an error. $uri->query_form( { 'search' => '{ "-or":[{ "name": "We Are Goth" },{ "id": "1" }]}' } ); But I may have misunderstood the reply from Alexander Hartmaier. I initially read the replay as "using search should work, as-is, right now". But now I wonder if I should be reading it as "this is how it *should* work, but doesn't currently"? On Tue, Jul 1, 2014 at 11:08 AM, Seth Daniel <seth.daniel@openx.com> wrote: Show quoted text
> When I try a search with "-or" as you describe in your response the API > thinks that "-or" is a column and the search fails with an error. Here is > a patch to t/rpc/list_json_search.t: > > diff --git a/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t > b/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t > index e8db665..259f494 100644 > --- a/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t > +++ b/perl-Catalyst-Controller-DBIC-API/t/rpc/list_json_search.t > @@ -76,6 +76,24 @@ my $base_rs = > > { > my $uri = URI->new($artist_list_url); > + $uri->query_form( > + { 'search' => '{ "-or": { "name": "We Are Goth" },{ "id": "1" }}' > } ); > + my $req = GET( $uri, 'Accept' => 'text/x-json' ); > + $mech->request($req); > + cmp_ok( $mech->status, '==', 200, 'attempt with related search okay' > ); > + diag explain $req; BAIL_OUT(''); > + my @expected_response = map { > + { $_->get_columns } > + } $schema->resultset('Artist') > + ->search( { 'cds.title' => 'Spoonful of bees' }, { join => 'cds' > } ) > + ->all; > + my $response = $json->decode( $mech->content ); > + is_deeply( { list => \@expected_response, success => 'true' }, > + $response, 'correct data returned for complex query' ); > +} > + > +{ > + my $uri = URI->new($artist_list_url); > $uri->query_form( { 'search.name' => '{"LIKE":"%waul%"}' } ); > my $req = GET( $uri, 'Accept' => 'text/x-json' ); > $mech->request($req); > > > This test fails with a 400 HTTP return code. > > > On Tue, Jul 1, 2014 at 8:18 AM, Alexander Hartmaier via RT < > bug-Catalyst-Controller-DBIC-API@rt.cpan.org> wrote: >
>> <URL: https://rt.cpan.org/Ticket/Display.html?id=93864 > >> >> For arbitary complex search arguments the search_arg request parameter is >> intended. Its default value is 'search' which means that you can pass a >> JSON string to it, for example: >> /api/track?search={"-or":[ { "title": "Yowlin" }, { "title": "Howlin" } ]} >> >> Please take a look at t/rpc/list_json_search.t and patch it to include >> one or more tests for -or and -and. >> A patch like yours shouldn't be needed as DBIC::API passes the data >> structure straight to DBIC after doing the JSON decoding. >>
> >
I finally found some time at YAPC::EU to look into it. There is an additional operator not handled by the patch: -not I'll add the tests provided and some additional for the -not operator and then look into a futureproof fix.
@Tomohiro: I've changed your tests and code a bit to match the style of the rest of the module and didn't include the patch to StoredResultSource check_column_relation because it's not required to make the tests pass. If you have another reason for it please open another ticket and include tests.
Hello. Thank you for strict check!! My code I was sloppy... Show quoted text
> If you have another reason for it please open another ticket and include tests.
Okay.
I tried to install the Catalyst::Controller::DBIC::API right now, but I failed. % cpanm Catalyst::Controller::DBIC::API --> Working on Catalyst::Controller::DBIC::API Fetching http://www.cpan.org/authors/id/A/AB/ABRAXXA/Catalyst-Controller-DBIC-API-2.006001.tar.gz ... OK Configuring Catalyst-Controller-DBIC-API-2.006001 ... OK Building and testing Catalyst-Controller-DBIC-API-2.006001 ... FAIL ! Installing Catalyst::Controller::DBIC::API failed. See /home/bokutin/.cpanm/work/1409006983.12199/build.log for details. Retry with --force to force install it. % git blame t/rest/list.t | ack Data::Printer 4cb8623a (Alexander Hartmaier 2014-08-25 18:16:44 +0200 15) use Data::Printer
Sorry, I forgot to add Data::Printer to the list of test requirements, fixed in 2.006002.