File Coverage

lib/MojoX/Mysql.pm
Criterion Covered Total %
statement 76 100 76.0
branch 17 60 28.3
condition 5 15 33.3
subroutine 13 13 100.0
pod 3 4 75.0
total 114 192 59.3


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