File Coverage

lib/MojoX/Mysql.pm
Criterion Covered Total %
statement 65 108 60.1
branch 17 70 24.2
condition 6 21 28.5
subroutine 10 13 76.9
pod 3 4 75.0
total 101 216 46.7


line stmt bran cond sub pod time code
1             package MojoX::Mysql;
2 7     7   1890644 use Mojo::Base -base;
  7         11  
  7         37  
3 7     7   771 use List::Util qw(shuffle);
  7         9  
  7         372  
4 7     7   26 use Time::HiRes qw(sleep gettimeofday);
  7         12  
  7         44  
5 7     7   780 use Mojo::Util qw(dumper);
  7         9  
  7         233  
6 7     7   9328 use DBI;
  7         79573  
  7         385  
7 7     7   50 use Carp qw(croak);
  7         7  
  7         385  
8              
9             our $VERSION = '0.22';
10              
11 7     7   2754 use MojoX::Mysql::DB;
  7         10  
  7         44  
12 7     7   2338 use MojoX::Mysql::Result;
  7         11  
  7         54  
13 7     7   2136 use MojoX::Mysql::Util;
  7         11  
  7         49  
14              
15             has [qw(async slave)];
16             has [qw(id)] => '_default';
17             has 'db'=> sub {
18             my $self = shift;
19             return MojoX::Mysql::DB->new(config=>$self->{'config'});
20             };
21              
22             has 'result'=> sub {
23             my $self = shift;
24             return MojoX::Mysql::Result->new();
25             };
26              
27             has 'util'=> sub {
28             my $self = shift;
29             return MojoX::Mysql::Util->new(config=>$self->{'config'});
30             };
31              
32             sub new {
33 1     1 1 33 my $class = shift;
34 1         3 my %args = @_;
35              
36 1         2 my %config = ();
37 1 50       3 if(exists $args{'server'}){
38 1         1 for my $server (@{$args{'server'}}){
  1         3  
39              
40             # Add the global login
41 6 50 33     21 $server->{'user'} = $args{'user'} if(!exists $server->{'user'} && exists $args{'user'});
42              
43             # Add the global password
44 6 50 33     16 $server->{'password'} = $args{'password'} if(!exists $server->{'password'} && exists $args{'password'});
45              
46             # Add the global write_timeout
47 6 50 33     14 $server->{'write_timeout'} = $args{'write_timeout'} if(!exists $server->{'write_timeout'} && exists $args{'write_timeout'});
48              
49             # Add the global read_timeout
50 6 50 33     14 $server->{'read_timeout'} = $args{'read_timeout'} if(!exists $server->{'read_timeout'} && exists $args{'read_timeout'});
51              
52             # Add the global read_timeout
53 6 50 33     15 $server->{'read_timeout'} = $args{'read_timeout'} if(!exists $server->{'read_timeout'} && exists $args{'read_timeout'});
54              
55             # Add the global connect_timeout
56 6 50 33     13 $server->{'connect_timeout'} = $args{'connect_timeout'} if(!exists $server->{'connect_timeout'} && exists $args{'connect_timeout'});
57              
58              
59 6 100       10 $server->{'id'} = '_default' if(!exists $server->{'id'});
60 6 50       8 $server->{'type'} = 'slave' if(!exists $server->{'type'});
61 6 50       8 $server->{'weight'} = 1 if(!exists $server->{'weight'});
62 6 50       10 $server->{'write_timeout'} = 60 if(!exists $server->{'write_timeout'});
63 6 50       11 $server->{'read_timeout'} = 60 if(!exists $server->{'read_timeout'});
64 6 50       8 $server->{'connect_timeout'} = 15 if(!exists $server->{'connect_timeout'});
65              
66 6         6 my $id = $server->{'id'};
67 6 100       8 if($server->{'type'} eq 'slave'){
68 3         6 for(1..$server->{'weight'}){
69 3         1 push(@{$config{$id}}, $server);
  3         7  
70             }
71             }
72             else{
73 3         1 push(@{$config{$id}}, $server);
  3         7  
74             }
75             }
76             }
77              
78 1         2 my %migration = ();
79 1         2 my %fake = ();
80 1         5 while(my($id,$data) = each(%config)){
81 3         3 my @master = grep($_->{'type'} eq 'master', @{$data});
  3         8  
82 3         3 my @slave = grep($_->{'type'} eq 'slave', @{$data});
  3         5  
83 3         33 @slave = shuffle @slave;
84 3         3 my $master = {};
85 3 50       5 $master = $master[0] if(@master);
86 3         8 $config{$id} = {master=>$master, slave=>\@slave};
87 3         10 $migration{$id} = $master->{'migration'};
88             }
89 1         13 return $class->SUPER::new(config=>\%config, migration=>\%migration, app=>$args{'app'});
90             }
91              
92             sub do {
93 0     0 1   my ($self,$sql) = (shift,shift);
94 0           my $id = $self->id;
95 0           $self->flush;
96              
97 0           my $dbh = $self->db->id($id)->connect_master;
98 0 0         warn "sql do $sql" if(defined $ENV{'MOJO_MYSQL_DEBUG'});
99              
100 0 0         my $counter = $dbh->do($sql,undef,@_) or die $dbh->errstr;
101 0           my $insertid = int $dbh->{'mysql_insertid'};
102 0 0         return wantarray ? ($insertid,$counter) : $insertid;
103             }
104              
105             sub query {
106 0     0 1   my ($self, $query) = (shift, shift);
107 0 0         my $cb = ref $_[-1] eq 'CODE' ? pop : undef;
108              
109 0           my $id = $self->id;
110 0           my $slave = $self->slave;
111 0           my $async = $self->async;
112 0           $self->flush;
113              
114 0           my $dbh;
115 0 0 0       if(defined $async && defined $slave){
    0          
    0          
116 0           $dbh = $self->db->id($id)->connect_slave;
117 0 0         croak 'No connect server' if(ref $dbh ne 'DBI::db');
118 0           $dbh = $dbh->clone;
119             }
120             elsif(defined $async){
121 0           $dbh = $self->db->id($id)->connect_master;
122 0 0         if(ref $dbh ne 'DBI::db'){
123 0           $dbh = $self->db->id($id)->connect_slave;
124             }
125 0 0         croak 'No connect server' if(ref $dbh ne 'DBI::db');
126 0           $dbh = $dbh->clone;
127             }
128             elsif(defined $slave){
129 0           $dbh = $self->db->id($id)->connect_slave;
130 0 0         croak 'No connect server' if(ref $dbh ne 'DBI::db');
131             }
132             else{
133 0           $dbh = $self->db->id($id)->connect_master;
134 0 0         if(ref $dbh ne 'DBI::db'){
135 0           $dbh = $self->db->id($id)->connect_slave;
136             }
137 0 0         croak 'No connect server' if(ref $dbh ne 'DBI::db');
138             }
139              
140 0 0         warn "sql query $query" if(defined $ENV{'MOJO_MYSQL_DEBUG'});
141              
142 0 0         if(defined $async){
143 0 0         my $sth = $dbh->prepare($query, {async=>1}) or croak $dbh->errstr;
144 0 0         $sth->execute(@_) or croak $dbh->errstr;
145 0           return ($sth,$dbh);
146             }
147             else{
148 0 0         my $sth = $dbh->prepare($query) or croak $dbh->errstr;
149 0 0         my $counter = $sth->execute(@_) or croak $dbh->errstr;
150 0           my $collection = $self->result->collection($sth,$cb);
151 0 0         return wantarray ? ($collection,$counter,$sth,$dbh,$id) : $collection;
152             }
153             }
154              
155             sub flush {
156 0     0 0   my $self = shift;
157 0           $self->id('_default');
158 0           $self->slave(undef);
159 0           $self->async(undef);
160             }
161              
162             1;
163              
164             =encoding utf8
165              
166             =head1 NAME
167              
168             MojoX::Mysql - Mojolicious ♥ Mysql
169            
170             =head1 SYNOPSIS
171              
172             use MojoX::Mysql;
173             use Mojo::Util qw(dumper);
174              
175             my %config = (
176             user=>'root',
177             password=>undef,
178             server=>[
179             {dsn=>'database=test;host=localhost;port=3306;mysql_connect_timeout=5;', type=>'master'},
180             {dsn=>'database=test;host=localhost;port=3306;mysql_connect_timeout=5;', type=>'slave'},
181             {dsn=>'database=test;host=localhost;port=3306;mysql_connect_timeout=5;', id=>1, type=>'master'},
182             {dsn=>'database=test;host=localhost;port=3306;mysql_connect_timeout=5;', id=>1, type=>'slave'},
183             {dsn=>'database=test;host=localhost;port=3306;mysql_connect_timeout=5;', id=>2, type=>'master'},
184             {dsn=>'database=test;host=localhost;port=3306;mysql_connect_timeout=5;', id=>2, type=>'slave'},
185             ]
186             );
187              
188             my $mysql = MojoX::Mysql->new(%config);
189              
190             =head1 DESCRIPTION
191              
192             MojoX::Mysql is a tiny wrapper around DBD::mysql that makes Mysql a lot of fun to use with the Mojolicious real-time web framework.
193              
194             =head1 ATTRIBUTES
195              
196             =head2 id
197              
198             $mysql->id(1); # choice id server
199              
200             =head2 slave
201              
202             $mysql->slave(1); # query only slave server
203              
204             =head2 async
205              
206             $mysql->async(1); # query async mode
207              
208             =head1 METHODS
209              
210             =head2 db
211              
212             $mysql->db;
213              
214             Return L object.
215              
216             =head2 do
217              
218             my ($insertid,$counter) = $mysql->do('INSERT INTO `names` (`id`,`name`) VALUES(1,?)', 'Lilu Kazerogova');
219              
220             =head2 do (choice server)
221              
222             my ($insertid,$counter) = $mysql->id(1)->do('INSERT INTO `names` (`id`,`name`) VALUES(1,?)', 'Lilu Kazerogova');
223              
224             =head2 query
225              
226             my $collection_object = $mysql->query('SELECT * FROM `names` WHERE id = ?', 1);
227              
228             # or
229              
230             my ($collection,$counter,$sth,$dbh) = $mysql->query('SELECT * FROM `names` WHERE id = ?', 1);
231              
232             # or callback
233              
234             $mysql->query('SELECT `text` FROM `test` WHERE `id` = ? LIMIT 1', $insertid, sub {
235             my ($self,$data) = @_;
236             say dumper $data;
237             });
238              
239             Return L object.
240              
241             =head2 query (choice server)
242              
243             my $collection_object = $mysql->id(1)->query('SELECT * FROM `names` WHERE id = ?', 1);
244              
245             # or
246              
247             my ($collection,$counter,$sth,$dbh) = $mysql->id(1)->query('SELECT * FROM `names` WHERE id = ?', 1);
248              
249             =head2 query (async)
250              
251             my ($sth1,$dbh1) = $mysql->id(1)->async(1)->query('SELECT SLEEP(?) as `sleep`', 1); # Automatically new connection
252             my ($sth2,$dbh2) = $mysql->id(1)->async(1)->query('SELECT SLEEP(?) as `sleep`', 1); # Automatically new connection
253              
254             my $collection_object1 = $mysql->result->async($sth1,$dbh1); # Automatically executed methods finish, commit, disconnect
255             my $collection_object2 = $mysql->result->async($sth2,$dbh2); # Automatically executed methods finish, commit, disconnect
256              
257             # Performed concurrently (1 seconds)
258              
259             Return L object.
260              
261             =head2 query (slave server)
262              
263             my $collection_object = $mysql->id(1)->slave(1)->query('SELECT * FROM `names` WHERE id = ?', 1);
264              
265             # or
266              
267             my ($collection,$counter,$sth,$dbh) = $mysql->id(1)->slave(1)->query('SELECT * FROM `names` WHERE id = ?', 1);
268              
269             =head2 commit, rollback, disconnect
270              
271             $mysql->db->commit;
272             $mysql->db->rollback;
273             $mysql->db->disconnect;
274              
275             =head2 quote
276              
277             $mysql->util->quote("test'test");
278              
279             =head2 id
280              
281             $mysql->util->id;
282              
283             Return id servers in L object.
284              
285             =head1 Mojolicious Plugin
286              
287             SEE ALSO L
288              
289             =head1 AUTHOR
290              
291             Kostya Ten, C.
292              
293             =head1 COPYRIGHT AND LICENSE
294              
295             Copyright (C) 2014, Kostya Ten.
296              
297             This program is free software, you can redistribute it and/or modify it under
298             the terms of the Apache License version 2.0.
299              
300             =cut
301