- Deprecate legacy $rs->search( %condition ) syntax
- NULL is now supplied unquoted to all debug-objects, in order to
differentiate between a real NULL and the string 'NULL'
+ - New search() condition operator -value used to pass complex bind
+ values to DBI: search({ array_col => { -value => [1,2,3] }})
- +columns now behaves just like columns by not stripping a
fully-qualified 'as' spec (i.e. foo.bar results in $obj->foo->bar)
jshirley: J. Shirley <jshirley@gmail.com>
+kaare: Kaare Rasmussen
+
konobi: Scott McWhirter
lukes: Luke Saunders <luke.saunders@gmail.com>
=item * The -ident operator
+=item * The -value operator
+
=back
=cut
sub new {
my $self = shift->next::method(@_);
- # use the same coderef, it is prepared to handle both cases
- push @{$self->{special_ops}}, {
- regex => qr/^ ident $/xi, handler => '_where_op_IDENT',
- };
- push @{$self->{unary_ops}}, {
- regex => qr/^ ident $/xi, handler => '_where_op_IDENT',
- };
+ # use the same coderefs, they are prepared to handle both cases
+ my @extra_dbic_syntax = (
+ { regex => qr/^ ident $/xi, handler => '_where_op_IDENT' },
+ { regex => qr/^ value $/xi, handler => '_where_op_VALUE' },
+ );
+
+ push @{$self->{special_ops}}, @extra_dbic_syntax;
+ push @{$self->{unary_ops}}, @extra_dbic_syntax;
$self;
}
croak "-$op takes a single scalar argument (a quotable identifier)";
}
- # in case we are called as a top level special op
+ # in case we are called as a top level special op (no '=')
my $lhs = shift;
$_ = $self->_convert($self->_quote($_)) for ($lhs, $rhs);
;
}
+sub _where_op_VALUE {
+ my $self = shift;
+ my ($op, $rhs) = splice @_, -2;
+
+ # in case we are called as a top level special op (no '=')
+ my $lhs = shift;
+
+ my @bind = [
+ ($lhs || $self->{_nested_func_lhs} || croak "Unable to find bindtype for -value $rhs"),
+ $rhs
+ ];
+
+ return $lhs
+ ? (
+ $self->_convert($self->_quote($lhs)) . ' = ' . $self->_convert('?'),
+ @bind
+ )
+ : (
+ $self->_convert('?'),
+ @bind,
+ )
+ ;
+}
+
# Handle limit-dialect selection
sub select {
my ($self, $table, $fields, $where, $rs_attrs, $limit, $offset) = @_;
use strict;
use warnings;
- use base 'DBIx::Class::Core';
+ use base 'DBICTest::BaseResult';
__PACKAGE__->table('dbic_t_schema.array_test');
__PACKAGE__->add_columns(qw/id arrayfield/);
SKIP: {
skip "Need DBD::Pg 2.9.2 or newer for array tests", 4 if $DBD::Pg::VERSION < 2.009002;
+ my $arr_rs = $schema->resultset('ArrayTest');
+
lives_ok {
- $schema->resultset('ArrayTest')->create({
+ $arr_rs->create({
arrayfield => [1, 2],
});
} 'inserting arrayref as pg array data';
lives_ok {
- $schema->resultset('ArrayTest')->update({
+ $arr_rs->update({
arrayfield => [3, 4],
});
} 'updating arrayref as pg array data';
- $schema->resultset('ArrayTest')->create({
+ $arr_rs->create({
arrayfield => [5, 6],
});
- my $afield_rs = $schema->resultset('ArrayTest')->search({
- arrayfield => \[ '= ?' => [arrayfield => [3, 4]] ], #Todo anything less ugly than this?
- });
+ # Search using arrays
+ lives_ok {
+ is_deeply (
+ $arr_rs->search({ arrayfield => { -value => [3,4] } })->first->arrayfield,
+ [3,4],
+ 'Array value matches'
+ );
+ } 'searching by arrayref';
- my $count;
lives_ok {
- $count = $afield_rs->count
- } 'comparing arrayref to pg array data does not blow up';
- is($count, 1, 'comparing arrayref to pg array data gives correct result');
+ is_deeply (
+ $arr_rs->search({ arrayfield => { '=' => { -value => [3,4] }} })->first->arrayfield,
+ [3,4],,
+ 'Array value matches explicit equal'
+ );
+ } 'searching by arrayref (explicit equal sign)';
- TODO: {
- local $TODO = 'No introspection of scalarref conditions :(';
- my $row = $afield_rs->create({});
+ lives_ok {
+ is_deeply (
+ $arr_rs->search({ arrayfield => { '>' => { -value => [3,1] }} })->first->arrayfield,
+ [3,4],
+ 'Array value matches greater than'
+ );
+ } 'searching by arrayref (greater than)';
+
+ lives_ok {
+ is (
+ $arr_rs->search({ arrayfield => { '>' => { -value => [3,7] }} })->count,
+ 1,
+ 'Greater than search found [5,6]',
+ );
+ } 'searching by arrayref (greater than)';
+
+ # Find using arrays
+ lives_ok {
+ is_deeply (
+ $arr_rs->find({ arrayfield => { -value => [3,4] } })->arrayfield,
+ [3,4],
+ 'Array value matches implicit equal'
+ );
+ } 'find by arrayref';
+
+ lives_ok {
+ is_deeply (
+ $arr_rs->find({ arrayfield => { '=' => { -value => [3,4] }} })->arrayfield,
+ [3,4],
+ 'Array value matches explicit equal'
+ );
+ } 'find by arrayref (equal)';
+
+ # test inferred condition for creation
+ TODO: for my $cond (
+ { -value => [3,4] },
+ \[ '= ?' => [arrayfield => [3, 4]] ],
+ ) {
+ local $TODO = 'No introspection of complex conditions :(';
+ my $arr_rs_cond = $arr_rs->search({ arrayfield => $cond });
+
+ my $row = $arr_rs_cond->create({});
is_deeply ($row->arrayfield, [3,4], 'Array value taken from $rs condition');
$row->discard_changes;
is_deeply ($row->arrayfield, [3,4], 'Array value made it to storage');
}
}
-
-
########## Case check
BEGIN {
--- /dev/null
+use strict;
+use warnings;
+
+use Test::More;
+
+use lib qw(t/lib);
+use DBIC::SqlMakerTest;
+
+use_ok('DBICTest');
+
+my $schema = DBICTest->init_schema();
+
+my $sql_maker = $schema->storage->sql_maker;
+
+for my $q ('', '"') {
+
+ $sql_maker->quote_char($q);
+
+ is_same_sql_bind (
+ \[ $sql_maker->select ('artist', '*', { arr1 => { -value => [1,2] }, arr2 => { '>', { -value => [3,4] } }, field => [5,6] } ) ],
+ "SELECT *
+ FROM ${q}artist${q}
+ WHERE ${q}arr1${q} = ? AND
+ ${q}arr2${q} > ? AND
+ ( ${q}field${q} = ? OR ${q}field${q} = ? )
+ ",
+ [
+ [ arr1 => [1,2] ],
+ [ arr2 => [3,4] ],
+ [ field => 5 ],
+ [ field => 6 ],
+ ],
+ );
+}
+
+done_testing;