File Coverage

blib/lib/Mojo/MySQL5.pm
Criterion Covered Total %
statement 28 60 46.6
branch 5 24 20.8
condition 1 8 12.5
subroutine 9 15 60.0
pod 6 6 100.0
total 49 113 43.3


line stmt bran cond sub pod time code
1             package Mojo::MySQL5;
2 7     7   467179 use Mojo::Base 'Mojo::EventEmitter';
  7         13  
  7         38  
3              
4 7     7   5673 use Carp 'croak';
  7         8  
  7         300  
5 7     7   2375 use Mojo::MySQL5::Database;
  7         15  
  7         67  
6 7     7   2858 use Mojo::MySQL5::Migrations;
  7         14  
  7         51  
7 7     7   2877 use Mojo::MySQL5::PubSub;
  7         13  
  7         57  
8 7     7   209 use Mojo::MySQL5::URL;
  7         11  
  7         38  
9 7     7   140 use Scalar::Util 'weaken';
  7         9  
  7         5042  
10              
11             has max_connections => 5;
12             has migrations => sub {
13             my $migrations = Mojo::MySQL5::Migrations->new(mysql => shift);
14             weaken $migrations->{mysql};
15             return $migrations;
16             };
17             has pubsub => sub {
18             my $pubsub = Mojo::MySQL5::PubSub->new(mysql => shift);
19             weaken $pubsub->{mysql};
20             return $pubsub;
21             };
22             has url => sub { Mojo::MySQL5::URL->new('mysql:///test') };
23              
24             our $VERSION = '0.09';
25              
26             sub db {
27 0     0 1 0 my $self = shift;
28              
29             # Fork safety
30 0 0 0     0 delete @$self{qw(pid queue)} unless ($self->{pid} //= $$) eq $$;
31              
32 0         0 my $c = $self->_dequeue;
33 0         0 my $db = Mojo::MySQL5::Database->new(connection => $c, mysql => $self);
34              
35 0 0       0 if (!$c) {
36 0         0 $db->connect;
37 0 0       0 croak 'connect failed' unless $db->connection->state eq 'idle';
38 0         0 $self->emit(connection => $db);
39             }
40 0         0 return $db;
41             }
42              
43             sub from_string {
44 6     6 1 26 my ($self, $str) = @_;
45 6         15 my $url = Mojo::MySQL5::URL->new($str);
46 6 50 33     14 croak qq{Invalid MySQL connection string "$str"}
47             unless $url->protocol eq 'mysql' or $url->protocol eq 'mysql5';
48              
49 6 50       41 $url->options->{utf8} = 1 unless exists $url->options->{utf8};
50 6 50       9 $url->options->{found_rows} = 1 unless exists $url->options->{found_rows};
51              
52 6         10 return $self->url($url);
53             }
54              
55 7 100   7 1 50 sub new { @_ == 2 ? shift->SUPER::new->from_string(@_) : shift->SUPER::new(@_) }
56              
57             sub _dequeue {
58 0     0     my $self = shift;
59              
60 0 0         while (my $c = shift @{$self->{queue} || []}) { return $c if $c->ping }
  0 0          
  0            
61 0           return undef;
62             }
63              
64             sub _enqueue {
65 0     0     my ($self, $c) = @_;
66 0   0       my $queue = $self->{queue} ||= [];
67 0           push @$queue, $c;
68 0           shift @{$self->{queue}} while @{$self->{queue}} > $self->max_connections;
  0            
  0            
69             }
70              
71             # deprecated attributes
72              
73             sub password {
74 0     0 1   my $self = shift;
75 0 0         return $self->url->password unless @_;
76 0           $self->url->password(@_);
77 0           return $self;
78             }
79              
80             sub username {
81 0     0 1   my $self = shift;
82 0 0         return $self->url->username unless @_;
83 0           $self->url->username(@_);
84 0           return $self;
85             }
86              
87             sub options {
88 0     0 1   my $self = shift;
89 0 0         return $self->url->options unless @_;
90 0           $self->url->options(@_);
91 0           return $self;
92             }
93              
94             1;
95              
96             =encoding utf8
97              
98             =head1 NAME
99              
100             Mojo::MySQL5 - Pure-Perl non-blocking I/O MySQL Connector
101              
102             =head1 SYNOPSIS
103              
104             use Mojo::MySQL5;
105              
106             # Create a table
107             my $mysql = Mojo::MySQL5->new('mysql://username@/test');
108             $mysql->db->query(
109             'create table names (id integer auto_increment primary key, name text)');
110              
111             # Insert a few rows
112             my $db = $mysql->db;
113             $db->query('insert into names (name) values (?)', 'Sara');
114             $db->query('insert into names (name) values (?)', 'Stefan');
115              
116             # Insert more rows in a transaction
117             {
118             my $tx = $db->begin;
119             $db->query('insert into names (name) values (?)', 'Baerbel');
120             $db->query('insert into names (name) values (?)', 'Wolfgang');
121             $tx->commit;
122             };
123              
124             # Insert another row and return the generated id
125             say $db->query('insert into names (name) values (?)', 'Daniel')
126             ->last_insert_id;
127              
128             # Select one row at a time
129             my $results = $db->query('select * from names');
130             while (my $next = $results->hash) {
131             say $next->{name};
132             }
133              
134             # Select all rows blocking
135             $db->query('select * from names')
136             ->hashes->map(sub { $_->{name} })->join("\n")->say;
137              
138             # Select all rows non-blocking
139             Mojo::IOLoop->delay(
140             sub {
141             my $delay = shift;
142             $db->query('select * from names' => $delay->begin);
143             },
144             sub {
145             my ($delay, $err, $results) = @_;
146             $results->hashes->map(sub { $_->{name} })->join("\n")->say;
147             }
148             )->wait;
149              
150             # Send and receive notifications non-blocking
151             $mysql->pubsub->listen(foo => sub {
152             my ($pubsub, $payload) = @_;
153             say "foo: $payload";
154             $pubsub->notify(bar => $payload);
155             });
156             $mysql->pubsub->listen(bar => sub {
157             my ($pubsub, $payload) = @_;
158             say "bar: $payload";
159             });
160             $mysql->pubsub->notify(foo => 'MySQL rocks!');
161              
162             Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
163              
164             =head1 DESCRIPTION
165              
166             L makes L a lot of fun to use with the
167             L real-time web framework.
168              
169             Database handles are cached automatically, so they can be reused transparently
170             to increase performance. And you can handle connection timeouts gracefully by
171             holding on to them only for short amounts of time.
172              
173             use Mojolicious::Lite;
174             use Mojo::MySQL5;
175              
176             helper mysql =>
177             sub { state $mysql = Mojo::MySQL5->new('mysql://sri:s3cret@localhost/db') };
178              
179             get '/' => sub {
180             my $c = shift;
181             my $db = $c->mysql->db;
182             $c->render(json => $db->query('select now() as time')->hash);
183             };
184              
185             app->start;
186              
187             Every database connection can only handle one active query at a time, this
188             includes asynchronous ones. So if you start more than one, they will be put on
189             a waiting list and performed sequentially. To perform multiple queries
190             concurrently, you have to use multiple connections.
191            
192             # Performed sequentially (10 seconds)
193             my $db = $mysql->db;
194             $db->query('select sleep(5)' => sub {...});
195             $db->query('select sleep(5)' => sub {...});
196            
197             # Performed concurrently (5 seconds)
198             $mysql->db->query('select sleep(5)' => sub {...});
199             $mysql->db->query('select sleep(5)' => sub {...});
200            
201             All cached database handles will be reset automatically if a new process has
202             been forked, this allows multiple processes to share the same L
203             object safely.
204              
205              
206             Note that this whole distribution is EXPERIMENTAL and will change without
207             warning!
208              
209             =head1 EVENTS
210              
211             L inherits all events from L and can emit the
212             following new ones.
213              
214             =head2 connection
215              
216             $mysql->on(connection => sub {
217             my ($mysql, $db) = @_;
218             ...
219             });
220              
221             Emitted when a new database connection has been established.
222              
223             =head1 ATTRIBUTES
224              
225             L implements the following attributes.
226              
227             =head2 max_connections
228              
229             my $max = $mysql->max_connections;
230             $mysql = $mysql->max_connections(3);
231              
232             Maximum number of idle database handles to cache for future use, defaults to
233             C<5>.
234              
235             =head2 migrations
236              
237             my $migrations = $mysql->migrations;
238             $mysql = $mysql->migrations(Mojo::MySQL5::Migrations->new);
239              
240             L object you can use to change your database schema more
241             easily.
242              
243             # Load migrations from file and migrate to latest version
244             $mysql->migrations->from_file('/home/sri/migrations.sql')->migrate;
245              
246             MySQL does not support nested transactions and DDL transactions.
247             DDL statements cause implicit C. C will be called if
248             any step of migration script fails, but only DML statements after the
249             last implicit or explicit C can be reverted.
250             Not all MySQL storage engines (like C) support transactions.
251              
252             This means database will most likely be left in unknown state if migration script fails.
253             Use this feature with caution and remember to always backup your database.
254              
255             =head2 pubsub
256              
257             my $pubsub = $mysql->pubsub;
258             $mysql = $mysql->pubsub(Mojo::MySQL5::PubSub->new);
259              
260             L object you can use to send and receive notifications very
261             efficiently, by sharing a single database connection with many consumers.
262              
263             # Subscribe to a channel
264             $mysql->pubsub->listen(news => sub {
265             my ($pubsub, $payload) = @_;
266             say "Received: $payload";
267             });
268              
269             # Notify a channel
270             $mysql->pubsub->notify(news => 'MySQL rocks!');
271              
272             =head2 url
273              
274             my $url = $mysql->url;
275             $url = $mysql->url(
276             Mojo::MySQL5::URL->new('mysql://user@host/test?connect_timeout=0'));
277              
278             Connection L.
279              
280             =head2 options
281              
282             Use L->options.
283              
284             See L for list of supported options.
285              
286             =head2 password
287              
288             Use L->password.
289              
290             =head2 username
291              
292             Use L->username.
293              
294              
295             =head1 METHODS
296              
297             L inherits all methods from L and implements the
298             following new ones.
299              
300             =head2 db
301              
302             my $db = $mysql->db;
303              
304             Get L object for a cached or newly created database
305             handle. The database handle will be automatically cached again when that
306             object is destroyed, so you can handle connection timeouts gracefully by
307             holding on to it only for short amounts of time.
308              
309             # Add up all the money
310             say $mysql->db->query('select * from accounts')
311             ->hashes->reduce(sub { $a->{money} + $b->{money} });
312              
313             =head2 from_string
314              
315             $mysql = $mysql->from_string('mysql://user@/test');
316              
317             Parse configuration from connection string.
318              
319             # Just a database
320             $mysql->from_string('mysql:///db1');
321              
322             # Username and database
323             $mysql->from_string('mysql://batman@/db2');
324              
325             # Username, password, host and database
326             $mysql->from_string('mysql://batman:s3cret@localhost/db3');
327              
328             # Username, domain socket and database
329             $mysql->from_string('mysql://batman@%2ftmp%2fmysql.sock/db4');
330              
331             # Username, database and additional options
332             $mysql->from_string('mysql://batman@/db5?PrintError=1');
333              
334             =head2 new
335              
336             my $mysql = Mojo::MySQL5->new;
337             my $mysql = Mojo::MySQL5->new('mysql://user:s3cret@host:port/database');
338             my $mysql = Mojo::MySQL5->new(
339             url => Mojo::MySQL5::URL->new(
340             host => 'localhost',
341             port => 3306,
342             username => 'user',
343             password => 's3cret',
344             options => { utf8 => 1, found_rows => 1 }
345             )
346             );
347              
348             Construct a new L object and parse connection string with
349             L if necessary.
350              
351             =head1 REFERENCE
352              
353             This is the class hierarchy of the L distribution.
354              
355             =over 2
356              
357             =item * L
358              
359             =item * L
360              
361             =item * L
362              
363             =item * L
364              
365             =item * L
366              
367             =item * L
368              
369             =item * L
370              
371             =item * L
372              
373             =back
374              
375             =head1 AUTHOR
376              
377             Jan Henning Thorsen, C.
378              
379             Svetoslav Naydenov, C.
380              
381             A lot of code in this module is taken from Sebastian Riedel's L.
382              
383             =head1 COPYRIGHT AND LICENSE
384              
385             Copyright (C) 2015, Svetoslav Naydenov.
386              
387             This program is free software, you can redistribute it and/or modify it under
388             the terms of the Artistic License version 2.0.
389              
390             =head1 SEE ALSO
391              
392             L,
393              
394             L Async Connector for PostgreSQL using L, L,
395              
396             L Async Connector for MySQL using L, L,
397              
398             L, L.
399              
400             =cut