Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

add single_named() #76

Merged
merged 3 commits into from

2 participants

@nihen

single() as a short cut for search()->next
single_by_sql() as a short cut for search_by_sql()->next

and I implemented
single_named() as a short cut for search_named()->next

This implementation depend on #75

@nekokak nekokak merged commit cebd6c9 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
27 bench/lookup_vs_single.pl
@@ -9,7 +9,6 @@
package Bench;
use parent 'Teng';
__PACKAGE__->load_plugin('Lookup');
- __PACKAGE__->load_plugin('SingleBySQL');
package Bench::Schema;
use Teng::Schema::Declare;
@@ -40,18 +39,24 @@
dbi => sub {$dbh->selectrow_hashref('SELECT id,name,age FROM user where id = ?', undef, 1)},
single => sub {$db->single('user', +{id => 1})},
single_by_sql => sub {$db->single_by_sql('SELECT id,name,age FROM user WHERE id = ?', [1], 'user')},
+ single_named => sub {$db->single_named('SELECT id,name,age FROM user WHERE id = :id', {id => 1}, 'user')},
lookup => sub {$db->lookup('user', +{id => 1})},
lookup_arrayref => sub {$db->lookup('user', [id => 1])},
}, 'all');
__END__
-Benchmark: timing 10000 iterations of dbi, lookup, single, single_by_sql...
- dbi: 0.543471 wallclock secs ( 0.50 usr 0.01 sys + 0.00 cusr 0.00 csys = 0.51 CPU) @ 19607.84/s (n=10000)
- lookup: 0.808071 wallclock secs ( 0.78 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.78 CPU) @ 12820.51/s (n=10000)
- single: 1.67938 wallclock secs ( 1.57 usr 0.00 sys + 0.00 cusr 0.00 csys = 1.57 CPU) @ 6369.43/s (n=10000)
-single_by_sql: 0.769787 wallclock secs ( 0.74 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.74 CPU) @ 13513.51/s (n=10000)
- Rate single lookup single_by_sql dbi
-single 6369/s -- -50% -53% -68%
-lookup 12821/s 101% -- -5% -35%
-single_by_sql 13514/s 112% 5% -- -31%
-dbi 19608/s 208% 53% 45% --
+
+Benchmark: timing 10000 iterations of dbi, lookup, lookup_arrayref, single, single_by_sql, single_named...
+ dbi: 0.681385 wallclock secs ( 0.50 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.50 CPU) @ 20000.00/s (n=10000)
+ lookup: 1.53734 wallclock secs ( 1.04 usr 0.00 sys + 0.00 cusr 0.00 csys = 1.04 CPU) @ 9615.38/s (n=10000)
+lookup_arrayref: 1.40989 wallclock secs ( 1.02 usr 0.00 sys + 0.00 cusr 0.00 csys = 1.02 CPU) @ 9803.92/s (n=10000)
+ single: 2.49036 wallclock secs ( 1.57 usr 0.01 sys + 0.00 cusr 0.00 csys = 1.58 CPU) @ 6329.11/s (n=10000)
+single_by_sql: 1.09325 wallclock secs ( 0.76 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.76 CPU) @ 13157.89/s (n=10000)
+single_named: 1.23624 wallclock secs ( 0.86 usr 0.00 sys + 0.00 cusr 0.00 csys = 0.86 CPU) @ 11627.91/s (n=10000)
+ Rate single lookup lookup_arrayref single_named single_by_sql dbi
+single 6329/s -- -34% -35% -46% -52% -68%
+lookup 9615/s 52% -- -2% -17% -27% -52%
+lookup_arrayref 9804/s 55% 2% -- -16% -25% -51%
+single_named 11628/s 84% 21% 19% -- -12% -42%
+single_by_sql 13158/s 108% 37% 34% 13% -- -34%
+dbi 20000/s 216% 108% 104% 72% 52% --
View
79 lib/Teng.pm
@@ -474,24 +474,29 @@ sub search {
$self->search_by_sql($sql, \@binds, $table_name);
}
-sub search_named {
- my ($self, $sql, $args, $table_name) = @_;
+sub _bind_named {
+ my ($self, $sql, $args ) = @_;
- my %named_bind = %{$args};
my @bind;
$sql =~ s{:([A-Za-z_][A-Za-z0-9_]*)}{
- Carp::croak("'$1' does not exist in bind hash") if !exists $named_bind{$1};
- if ( ref $named_bind{$1} && ref $named_bind{$1} eq "ARRAY" ) {
- push @bind, @{ $named_bind{$1} };
- my $tmp = join ',', map { '?' } @{ $named_bind{$1} };
+ Carp::croak("'$1' does not exist in bind hash") if !exists $args->{$1};
+ if ( ref $args->{$1} && ref $args->{$1} eq "ARRAY" ) {
+ push @bind, @{ $args->{$1} };
+ my $tmp = join ',', map { '?' } @{ $args->{$1} };
"( $tmp )";
} else {
- push @bind, $named_bind{$1};
+ push @bind, $args->{$1};
'?'
}
}ge;
- $self->search_by_sql($sql, \@bind, $table_name);
+ return ($sql, \@bind);
+}
+
+sub search_named {
+ my ($self, $sql, $args, $table_name) = @_;
+
+ $self->search_by_sql($self->_bind_named($sql, $args), $table_name);
}
sub single {
@@ -542,6 +547,36 @@ sub search_by_sql {
return wantarray ? $itr->all : $itr;
}
+sub single_by_sql {
+ my ($self, $sql, $bind, $table_name) = @_;
+
+ $table_name ||= $self->_guess_table_name( $sql );
+ my $table = $self->{schema}->get_table( $table_name );
+ Carp::croak("No such table $table_name") unless $table;
+
+ my $sth = $self->_execute($sql, $bind);
+ my $row = $sth->fetchrow_hashref($self->{fields_case});
+
+ return unless $row;
+ return $row if $self->{suppress_row_objects};
+
+ $table->{row_class}->new(
+ {
+ sql => $sql,
+ row_data => $row,
+ teng => $self,
+ table => $table,
+ table_name => $table_name,
+ }
+ );
+}
+
+sub single_named {
+ my ($self, $sql, $args, $table_name) = @_;
+
+ $self->single_by_sql($self->_bind_named($sql, $args), $table_name);
+}
+
sub _guess_table_name {
my ($class, $sql) = @_;
@@ -628,7 +663,7 @@ in your script.
);
$row->update({name => 'nekokak'});
- $row = $teng->search_by_sql(q{SELECT id, name FROM user WHERE id = ?}, [ 1 ]);
+ $row = $teng->single_by_sql(q{SELECT id, name FROM user WHERE id = ?}, [ 1 ]);
$row->delete();
=head1 ARCHITECTURE
@@ -884,6 +919,30 @@ execute your SQL
If $table is specified, it set table infomation to result iterator.
So, you can use table row class to search_by_sql result.
+=item $row = $teng->single_by_sql($sql, [\@bind_values, [$table_name]])
+
+get one record from your SQL.
+
+ my $row = $teng->single_by_sql(q{SELECT id,name FROM user WHERE id = ? LIMIT 1}, [1], 'user');
+
+This is a shortcut for
+
+ my $row = $teng->search_by_sql(q{SELECT id,name FROM user WHERE id = ? LIMIT 1}, [1], 'user')->next;
+
+But optimized implementation.
+
+=item $row = $teng->single_named($sql, [\%bind_values, [$table_name]])
+
+get one record from execute named query
+
+ my $row = $teng->single_named(q{SELECT id,name FROM user WHERE id = :id LIMIT 1}, {id => 1}, 'user');
+
+This is a shortcut for
+
+ my $row = $teng->search_named(q{SELECT id,name FROM user WHERE id = :id LIMIT 1}, {id => 1}, 'user')->next;
+
+But optimized implementation.
+
=item $teng->txn_scope
Creates a new transaction scope guard object.
View
3  lib/Teng/Plugin/SingleBySQL.pm
@@ -5,6 +5,7 @@ use utf8;
our @EXPORT = qw/single_by_sql/;
+warn "IMPORTANT: Teng::Plugin::SingleBySQL is DEPRECATED AND *WILL* BE REMOVED. Because into the Teng core. DO NOT USE.\n";
sub single_by_sql {
my ($self, $sql, $bind, $table_name) = @_;
@@ -35,7 +36,7 @@ __END__
=head1 NAME
-Teng::Plugin::SingleBySQL - single by sql
+Teng::Plugin::SingleBySQL - (DEPRECATED)single by sql
=head1 PROVIDED METHODS
View
3  t/001_basic/029_single_by_sql.t → t/002_common/026_single_by_sql.t
@@ -5,14 +5,13 @@ use Test::More;
my $dbh = t::Utils->setup_dbh;
my $db = Mock::Basic->new({dbh => $dbh});
$db->setup_test_db;
-Mock::Basic->load_plugin('SingleBySQL');
$db->insert('mock_basic',{
id => 1,
name => 'perl',
});
-subtest 'single' => sub {
+subtest 'single_by_sql' => sub {
my $row = $db->single_by_sql('SELECT * from mock_basic where id = ?', [1], 'mock_basic');
isa_ok $row, 'Teng::Row';
is $row->id, 1;
View
21 t/002_common/027_single_named.t
@@ -0,0 +1,21 @@
+use t::Utils;
+use Mock::Basic;
+use Test::More;
+
+my $dbh = t::Utils->setup_dbh;
+my $db = Mock::Basic->new({dbh => $dbh});
+$db->setup_test_db;
+
+$db->insert('mock_basic',{
+ id => 1,
+ name => 'perl',
+});
+
+subtest 'single_named' => sub {
+ my $row = $db->single_named('SELECT * from mock_basic where id = :id', {id => 1}, 'mock_basic');
+ isa_ok $row, 'Teng::Row';
+ is $row->id, 1;
+ is $row->name, 'perl';
+};
+
+done_testing;
Something went wrong with that request. Please try again.