File Coverage

lib/MojoX/Mysql.pm
Criterion Covered Total %
statement 63 104 60.5
branch 14 60 23.3
condition 4 15 26.6
subroutine 10 13 76.9
pod 3 4 75.0
total 94 196 47.9


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