[Bps-public-commit] dbix-searchbuilder branch, in-operator, created. 1.63-2-ge37c201
Ruslan Zakirov
ruz at bestpractical.com
Sun Feb 3 06:35:49 EST 2013
The branch, in-operator has been created
at e37c201c2b4df2b73a21df77ee0f58af1a90fcc4 (commit)
- Log -----------------------------------------------------------------
commit e37c201c2b4df2b73a21df77ee0f58af1a90fcc4
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 15 00:06:31 2012 +0400
add support for [NOT] IN operator in ->Limit
VALUE can be array reference or DBIx::SearchBuilder instance
diff --git a/Changes b/Changes
index 3c0b285..d7bfd27 100755
--- a/Changes
+++ b/Changes
@@ -1,5 +1,9 @@
Revision history for Perl extension DBIx::SearchBuilder.
+1.64
+
+* IN and NOT IN operators in ->Limit method
+
1.63 Fri Sep 14 2012 01:19:38 GMT+0400 (MSK)
* joins_are_distinct hint to indicate that distinct is not
diff --git a/Makefile.PL b/Makefile.PL
index 09afb1b..af765ff 100755
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -10,6 +10,7 @@ requires('Encode' => '1.99');
requires('Class::ReturnValue', 0.40);
requires('Cache::Simple::TimedExpiry' => '0.21');
requires('Clone');
+requires('Scalar::Util');
build_requires('Test::More' => 0.52);
build_requires('DBD::SQLite');
build_requires('File::Temp');
diff --git a/lib/DBIx/SearchBuilder.pm b/lib/DBIx/SearchBuilder.pm
index d042d27..798b8da 100755
--- a/lib/DBIx/SearchBuilder.pm
+++ b/lib/DBIx/SearchBuilder.pm
@@ -8,6 +8,7 @@ our $VERSION = "1.63";
use Clone qw();
use Encode qw();
+use Scalar::Util qw(blessed);
=head1 NAME
@@ -760,6 +761,17 @@ ENDSWITH is like LIKE, except it prepends a % to the beginning of the string
MATCHES is equivalent to the database's LIKE -- that is, it's actually LIKE, but
doesn't surround the string in % signs as LIKE does.
+=item "IN" and "NOT IN"
+
+VALUE can be an array reference or an object inherited from this class. If
+it's not then it's treated as any other operator and in most cases SQL would
+be wrong. Values in array are considered as constants and quoted according
+to QUOTEVALUE.
+
+If object is passed as VALUE then its select statement is used. If no L</Column>
+is selected then C<id> is used, if more than one selected then warning is issued
+and first column is used.
+
=back
=item ENTRYAGGREGATOR
@@ -836,6 +848,33 @@ sub Limit {
elsif ( $args{'OPERATOR'} =~ /ENDSWITH/i ) {
$args{'VALUE'} = "%" . $args{'VALUE'};
}
+ elsif ( $args{'OPERATOR'} =~ /\bIN$/i ) {
+ if ( blessed $args{'VALUE'} && $args{'VALUE'}->isa(__PACKAGE__) ) {
+ # if no columns selected then select id
+ local $args{'VALUE'}{'columns'} = $args{'VALUE'}{'columns'};
+ unless ( $args{'VALUE'}{'columns'} ) {
+ $args{'VALUE'}->Column( FIELD => 'id' );
+ } elsif ( @{ $args{'VALUE'}{'columns'} } > 1 ) {
+ warn "Collection in '$args{OPERATOR}' with more than one column selected, using first";
+ splice @{ $args{'VALUE'}{'columns'} }, 1;
+ }
+ $args{'VALUE'} = '('. $args{'VALUE'}->BuildSelectQuery .')';
+ $args{'QUOTEVALUE'} = 0;
+ }
+ elsif ( ref $args{'VALUE'} ) {
+ if ( $args{'QUOTEVALUE'} ) {
+ my $dbh = $self->_Handle->dbh;
+ $args{'VALUE'} = join ', ', map $dbh->quote( $_ ), @{ $args{'VALUE'} };
+ } else {
+ $args{'VALUE'} = join ', ', @{ $args{'VALUE'} };
+ }
+ $args{'VALUE'} = "($args{VALUE})";
+ $args{'QUOTEVALUE'} = 0;
+ }
+ else {
+ # otherwise behave in backwards compatible way
+ }
+ }
$args{'OPERATOR'} =~ s/(?:MATCHES|ENDSWITH|STARTSWITH)/LIKE/i;
#if we're explicitly told not to to quote the value or
diff --git a/t/01searches.t b/t/01searches.t
index 9fdfc45..ce01165 100644
--- a/t/01searches.t
+++ b/t/01searches.t
@@ -7,7 +7,7 @@ use Test::More;
BEGIN { require "t/utils.pl" }
our (@AvailableDrivers);
-use constant TESTS_PER_DRIVER => 117;
+use constant TESTS_PER_DRIVER => 130;
my $total = scalar(@AvailableDrivers) * TESTS_PER_DRIVER;
plan tests => $total;
@@ -167,6 +167,67 @@ SKIP: {
$users_obj->Limit( FIELD => 'Phone', OPERATOR => 'IS NOT', VALUE => 'NULL', QOUTEVALUE => 0 );
is( $users_obj->Count, $count_all - 2, "found users who has phone number filled" );
+ # IN [...] operator
+ $users_obj->CleanSlate;
+ is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new object');
+ $users_obj->Limit( FIELD => 'Login', OPERATOR => 'IN', VALUE => ['obra', 'cubic'] );
+ is( $users_obj->Count, 2, "found two users using IN operator" );
+ is_deeply(
+ [ sort map $_->Login, @{ $users_obj->ItemsArrayRef } ],
+ [ 'cubic', 'obra' ],
+ 'found correct records',
+ );
+ $users_obj->CleanSlate;
+ $users_obj->Limit( FIELD => 'Login', OPERATOR => 'NOT IN', VALUE => ['obra', 'cubic'] );
+ is( $users_obj->Count, 2, "found two users using NOT IN operator" );
+ is_deeply(
+ [ sort map $_->Login, @{ $users_obj->ItemsArrayRef } ],
+ [ 'autrijus', 'glasser' ],
+ 'found correct records',
+ );
+
+ # IN $collection operator
+ $users_obj->CleanSlate;
+ is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new object');
+ {
+ my $tmp = $users_obj->Clone;
+ $tmp->Limit( FIELD => 'Login', OPERATOR => 'IN', VALUE => ['obra', 'cubic'] );
+ $users_obj->Limit( FIELD => 'id', OPERATOR => 'IN', VALUE => $tmp );
+ }
+ is( $users_obj->Count, 2, "found two users using IN operator" );
+ is_deeply(
+ [ sort map $_->Login, @{ $users_obj->ItemsArrayRef } ],
+ [ 'cubic', 'obra' ],
+ 'found correct records',
+ );
+ $users_obj->CleanSlate;
+ {
+ my $tmp = $users_obj->Clone;
+ $tmp->Limit( FIELD => 'Login', OPERATOR => 'IN', VALUE => ['obra', 'cubic'] );
+ $users_obj->Limit( FIELD => 'id', OPERATOR => 'NOT IN', VALUE => $tmp );
+ }
+ is( $users_obj->Count, 2, "found two users using IN operator" );
+ is_deeply(
+ [ sort map $_->Login, @{ $users_obj->ItemsArrayRef } ],
+ [ 'autrijus', 'glasser' ],
+ 'found correct records',
+ );
+ # IN with object and Column preselected
+ $users_obj->CleanSlate;
+ is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new object');
+ {
+ my $tmp = $users_obj->Clone;
+ $tmp->Limit( FIELD => 'Login', OPERATOR => 'IN', VALUE => ['obra', 'cubic'] );
+ $tmp->Column(FIELD => 'Login');
+ $users_obj->Limit( FIELD => 'Login', OPERATOR => 'IN', VALUE => $tmp );
+ }
+ is( $users_obj->Count, 2, "found two users using IN operator" );
+ is_deeply(
+ [ sort map $_->Login, @{ $users_obj->ItemsArrayRef } ],
+ [ 'cubic', 'obra' ],
+ 'found correct records',
+ );
+
# ORDER BY / GROUP BY
$users_obj->CleanSlate;
is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new object');
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list