File Coverage

blib/lib/Mojo/Pg.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Mojo::Pg;
2 6     6   1342977 use Mojo::Base 'Mojo::EventEmitter';
  6         61  
  6         61  
3              
4 6     6   5516 use Carp 'croak';
  6         17  
  6         350  
5 6     6   7315 use DBI;
  6         98441  
  6         499  
6 6     6   3286 use Mojo::Pg::Database;
  0            
  0            
7             use Mojo::Pg::Migrations;
8             use Mojo::Pg::PubSub;
9             use Mojo::URL;
10             use Scalar::Util qw(blessed weaken);
11             use SQL::Abstract;
12              
13             has abstract => sub {
14             SQL::Abstract->new(array_datatypes => 1, name_sep => '.', quote_char => '"');
15             };
16             has [qw(auto_migrate parent search_path)];
17             has database_class => 'Mojo::Pg::Database';
18             has dsn => 'dbi:Pg:';
19             has max_connections => 1;
20             has migrations => sub {
21             my $migrations = Mojo::Pg::Migrations->new(pg => shift);
22             weaken $migrations->{pg};
23             return $migrations;
24             };
25             has options => sub {
26             {
27             AutoCommit => 1,
28             AutoInactiveDestroy => 1,
29             PrintError => 0,
30             PrintWarn => 0,
31             RaiseError => 1
32             };
33             };
34             has [qw(password username)] => '';
35             has pubsub => sub {
36             my $pubsub = Mojo::Pg::PubSub->new(pg => shift);
37             weaken $pubsub->{pg};
38             return $pubsub;
39             };
40              
41             our $VERSION = '4.03';
42              
43             sub db { $_[0]->database_class->new(dbh => $_[0]->_prepare, pg => $_[0]) }
44              
45             sub from_string {
46             my ($self, $str) = @_;
47              
48             # Parent
49             return $self unless $str;
50             return $self->parent($str) if blessed $str && $str->isa('Mojo::Pg');
51              
52             # Protocol
53             my $url = Mojo::URL->new($str);
54             croak qq{Invalid PostgreSQL connection string "$str"}
55             unless $url->protocol =~ /^postgres(?:ql)?$/;
56              
57             # Connection information
58             my $db = $url->path->parts->[0];
59             my $dsn = defined $db ? "dbi:Pg:dbname=$db" : 'dbi:Pg:';
60             if (my $host = $url->host) { $dsn .= ";host=$host" }
61             if (my $port = $url->port) { $dsn .= ";port=$port" }
62             if (defined(my $username = $url->username)) { $self->username($username) }
63             if (defined(my $password = $url->password)) { $self->password($password) }
64              
65             # Service and search_path
66             my $hash = $url->query->to_hash;
67             if (my $service = delete $hash->{service}) { $dsn .= "service=$service" }
68             if (my $path = delete $hash->{search_path}) {
69             $self->search_path(ref $path ? $path : [$path]);
70             }
71              
72             # Options
73             @{$self->options}{keys %$hash} = values %$hash;
74              
75             return $self->dsn($dsn);
76             }
77              
78             sub new { @_ > 1 ? shift->SUPER::new->from_string(@_) : shift->SUPER::new }
79              
80             sub _dequeue {
81             my $self = shift;
82              
83             # Fork-safety
84             delete @$self{qw(pid queue)} unless ($self->{pid} //= $$) eq $$;
85              
86             while (my $dbh = shift @{$self->{queue} || []}) { return $dbh if $dbh->ping }
87             my $dbh = DBI->connect(map { $self->$_ } qw(dsn username password options));
88              
89             # Search path
90             if (my $path = $self->search_path) {
91             my $search_path = join ', ', map { $dbh->quote_identifier($_) } @$path;
92             $dbh->do("set search_path to $search_path");
93             }
94              
95             $self->emit(connection => $dbh);
96              
97             return $dbh;
98             }
99              
100             sub _enqueue {
101             my ($self, $dbh) = @_;
102              
103             if (my $parent = $self->parent) { return $parent->_enqueue($dbh) }
104              
105             my $queue = $self->{queue} ||= [];
106             push @$queue, $dbh if $dbh->{Active};
107             shift @$queue while @$queue > $self->max_connections;
108             }
109              
110             sub _prepare {
111             my $self = shift;
112              
113             # Automatic migrations
114             ++$self->{migrated} and $self->migrations->migrate
115             if !$self->{migrated} && $self->auto_migrate;
116              
117             my $parent = $self->parent;
118             return $parent ? $parent->_prepare : $self->_dequeue;
119             }
120              
121             1;
122              
123             =encoding utf8
124              
125             =head1 NAME
126              
127             Mojo::Pg - Mojolicious ♥ PostgreSQL
128              
129             =head1 SYNOPSIS
130              
131             use Mojo::Pg;
132              
133             # Use a PostgreSQL connection string for configuration
134             my $pg = Mojo::Pg->new('postgresql://postgres@/test');
135              
136             # Select the server version
137             say $pg->db->query('select version() as version')->hash->{version};
138              
139             # Use migrations to create a table
140             $pg->migrations->name('my_names_app')->from_string(<migrate;
141             -- 1 up
142             create table names (id serial primary key, name text);
143             -- 1 down
144             drop table names;
145             EOF
146              
147             # Use migrations to drop and recreate the table
148             $pg->migrations->migrate(0)->migrate;
149              
150             # Get a database handle from the cache for multiple queries
151             my $db = $pg->db;
152              
153             # Use SQL::Abstract to generate simple CRUD queries for you
154             $db->insert('names', {name => 'Isabell'});
155             my $id = $db->select('names', ['id'], {name => 'Isabell'})->hash->{id};
156             $db->update('names', {name => 'Belle'}, {id => $id});
157             $db->delete('names', {name => 'Belle'});
158              
159             # Insert a few rows in a transaction with SQL and placeholders
160             eval {
161             my $tx = $db->begin;
162             $db->query('insert into names (name) values (?)', 'Sara');
163             $db->query('insert into names (name) values (?)', 'Stefan');
164             $tx->commit;
165             };
166             say $@ if $@;
167              
168             # Insert another row with SQL::Abstract and return the generated id
169             say $db->insert('names', {name => 'Daniel'}, {returning => 'id'})->hash->{id};
170              
171             # JSON roundtrip
172             say $db->query('select ?::json as foo', {json => {bar => 'baz'}})
173             ->expand->hash->{foo}{bar};
174              
175             # Select all rows blocking with SQL::Abstract
176             say $_->{name} for $db->select('names')->hashes->each;
177              
178             # Select all rows non-blocking with SQL::Abstract
179             $db->select('names' => sub {
180             my ($db, $err, $results) = @_;
181             die $err if $err;
182             say $_->{name} for $results->hashes->each;
183             });
184             Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
185              
186             # Concurrent non-blocking queries (synchronized with promises)
187             my $now = $pg->db->query_p('select now() as now');
188             my $names = $pg->db->query_p('select * from names');
189             Mojo::Promise->all($now, $names)->then(sub {
190             my ($now, $names) = @_;
191             say $now->[0]->hash->{now};
192             say $_->{name} for $names->[0]->hashes->each;
193             })->catch(sub {
194             my $err = shift;
195             warn "Something went wrong: $err";
196             })->wait;
197              
198             # Send and receive notifications non-blocking
199             $pg->pubsub->listen(foo => sub {
200             my ($pubsub, $payload) = @_;
201             say "foo: $payload";
202             $pubsub->notify(bar => $payload);
203             });
204             $pg->pubsub->listen(bar => sub {
205             my ($pubsub, $payload) = @_;
206             say "bar: $payload";
207             });
208             $pg->pubsub->notify(foo => 'PostgreSQL rocks!');
209             Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
210              
211             =head1 DESCRIPTION
212              
213             L is a tiny wrapper around L that makes
214             L a lot of fun to use with the
215             L real-time web framework. Perform queries
216             blocking and non-blocking, use all
217             L
218             PostgreSQL has to offer, generate CRUD queries from data structures, manage your
219             database schema with migrations and build scalable real-time web applications
220             with the publish/subscribe pattern.
221              
222             Database and statement handles are cached automatically, and will be reused
223             transparently to increase performance. You can handle connection timeouts
224             gracefully by holding on to them only for short amounts of time.
225              
226             use Mojolicious::Lite;
227             use Mojo::Pg;
228              
229             helper pg => sub { state $pg = Mojo::Pg->new('postgresql://postgres@/test') };
230              
231             get '/' => sub {
232             my $c = shift;
233             my $db = $c->pg->db;
234             $c->render(json => $db->query('select now() as now')->hash);
235             };
236              
237             app->start;
238              
239             In this example application, we create a C helper to store a L
240             object. Our action calls that helper and uses the method L to
241             dequeue a L object from the connection pool. Then we use the
242             method L to execute an
243             L statement, which
244             returns a L object. And finally we call the method
245             L to retrieve the first row as a hash reference.
246              
247             While all I/O operations are performed blocking, you can wait for long running
248             queries asynchronously, allowing the L event loop to perform
249             other tasks in the meantime. Since database connections usually have a very low
250             latency, this often results in very good performance.
251              
252             Every database connection can only handle one active query at a time, this
253             includes asynchronous ones. To perform multiple queries concurrently, you have
254             to use multiple connections.
255              
256             # Performed concurrently (5 seconds)
257             $pg->db->query('select pg_sleep(5)' => sub {...});
258             $pg->db->query('select pg_sleep(5)' => sub {...});
259              
260             All cached database handles will be reset automatically if a new process has
261             been forked, this allows multiple processes to share the same L
262             object safely.
263              
264             =head1 GROWING
265              
266             And as your application grows, you can move queries into model classes.
267              
268             package MyApp::Model::Time;
269             use Mojo::Base -base;
270              
271             has 'pg';
272              
273             sub now { shift->pg->db->query('select now() as now')->hash }
274              
275             1;
276              
277             Which get integrated into your application with helpers.
278              
279             use Mojolicious::Lite;
280             use Mojo::Pg;
281             use MyApp::Model::Time;
282              
283             helper pg => sub { state $pg = Mojo::Pg->new('postgresql://postgres@/test') };
284             helper time => sub { state $time = MyApp::Model::Time->new(pg => shift->pg) };
285              
286             get '/' => sub {
287             my $c = shift;
288             $c->render(json => $c->time->now);
289             };
290              
291             app->start;
292              
293             =head1 EXAMPLES
294              
295             This distribution also contains two great
296             L
297             you can use for inspiration. The minimal
298             L
299             application will show you how to scale WebSockets to multiple servers, and the
300             well-structured
301             L application
302             how to apply the MVC design pattern in practice.
303              
304             =head1 EVENTS
305              
306             L inherits all events from L and can emit the
307             following new ones.
308              
309             =head2 connection
310              
311             $pg->on(connection => sub {
312             my ($pg, $dbh) = @_;
313             ...
314             });
315              
316             Emitted when a new database connection has been established.
317              
318             $pg->on(connection => sub {
319             my ($pg, $dbh) = @_;
320             $dbh->do('set search_path to my_schema');
321             });
322              
323             =head1 ATTRIBUTES
324              
325             L implements the following attributes.
326              
327             =head2 abstract
328              
329             my $abstract = $pg->abstract;
330             $pg = $pg->abstract(SQL::Abstract->new);
331              
332             L object used to generate CRUD queries for L,
333             defaults to enabling C and setting C to C<.> and
334             C to C<">.
335              
336             # Generate WHERE clause and bind values
337             my($stmt, @bind) = $pg->abstract->where({foo => 'bar', baz => 'yada'});
338              
339             =head2 auto_migrate
340              
341             my $bool = $pg->auto_migrate;
342             $pg = $pg->auto_migrate($bool);
343              
344             Automatically migrate to the latest database schema with L, as
345             soon as L has been called for the first time.
346              
347             =head2 database_class
348              
349             my $class = $pg->database_class;
350             $pg = $pg->database_class('MyApp::Database');
351              
352             Class to be used by L, defaults to L. Note that this
353             class needs to have already been loaded before L is called.
354              
355             =head2 dsn
356              
357             my $dsn = $pg->dsn;
358             $pg = $pg->dsn('dbi:Pg:dbname=foo');
359              
360             Data source name, defaults to C.
361              
362             =head2 max_connections
363              
364             my $max = $pg->max_connections;
365             $pg = $pg->max_connections(3);
366              
367             Maximum number of idle database handles to cache for future use, defaults to
368             C<1>.
369              
370             =head2 migrations
371              
372             my $migrations = $pg->migrations;
373             $pg = $pg->migrations(Mojo::Pg::Migrations->new);
374              
375             L object you can use to change your database schema more
376             easily.
377              
378             # Load migrations from file and migrate to latest version
379             $pg->migrations->from_file('/home/sri/migrations.sql')->migrate;
380              
381             =head2 options
382              
383             my $options = $pg->options;
384             $pg = $pg->options({AutoCommit => 1, RaiseError => 1});
385              
386             Options for database handles, defaults to activating C,
387             C as well as C and deactivating C
388             as well as C. Note that C and C are
389             considered mandatory, so deactivating them would be very dangerous.
390              
391             =head2 parent
392              
393             my $parent = $pg->parent;
394             $pg = $pg->parent(Mojo::Pg->new);
395              
396             Another L object to use for connection management, instead of
397             establishing and caching our own database connections.
398              
399             =head2 password
400              
401             my $password = $pg->password;
402             $pg = $pg->password('s3cret');
403              
404             Database password, defaults to an empty string.
405              
406             =head2 pubsub
407              
408             my $pubsub = $pg->pubsub;
409             $pg = $pg->pubsub(Mojo::Pg::PubSub->new);
410              
411             L object you can use to send and receive notifications very
412             efficiently, by sharing a single database connection with many consumers.
413              
414             # Subscribe to a channel
415             $pg->pubsub->listen(news => sub {
416             my ($pubsub, $payload) = @_;
417             say "Received: $payload";
418             });
419              
420             # Notify a channel
421             $pg->pubsub->notify(news => 'PostgreSQL rocks!');
422              
423             =head2 search_path
424              
425             my $path = $pg->search_path;
426             $pg = $pg->search_path(['$user', 'foo', 'public']);
427              
428             Schema search path assigned to all new connections.
429              
430             # Isolate tests and avoid race conditions when running them in parallel
431             my $pg = Mojo::Pg->new('postgresql:///test')->search_path(['test_one']);
432             $pg->db->query('drop schema if exists test_one cascade');
433             $pg->db->query('create schema test_one');
434             ...
435             $pg->db->query('drop schema test_one cascade');
436              
437             =head2 username
438              
439             my $username = $pg->username;
440             $pg = $pg->username('sri');
441              
442             Database username, defaults to an empty string.
443              
444             =head1 METHODS
445              
446             L inherits all methods from L and implements the
447             following new ones.
448              
449             =head2 db
450              
451             my $db = $pg->db;
452              
453             Get a database object based on L (which is usually
454             L) for a cached or newly established database connection.
455             The L database handle will be automatically cached again when that
456             object is destroyed, so you can handle problems like connection timeouts
457             gracefully by holding on to it only for short amounts of time.
458              
459             # Add up all the money
460             say $pg->db->select('accounts')
461             ->hashes->reduce(sub { $a->{money} + $b->{money} });
462              
463             =head2 from_string
464              
465             $pg = $pg->from_string('postgresql://postgres@/test');
466             $pg = $pg->from_string(Mojo::Pg->new);
467              
468             Parse configuration from connection string or use another L object as
469             L.
470              
471             # Just a database
472             $pg->from_string('postgresql:///db1');
473              
474             # Just a service
475             $pg->from_string('postgresql://?service=foo');
476              
477             # Username and database
478             $pg->from_string('postgresql://sri@/db2');
479              
480             # Short scheme, username, password, host and database
481             $pg->from_string('postgres://sri:s3cret@localhost/db3');
482              
483             # Username, domain socket and database
484             $pg->from_string('postgresql://sri@%2ftmp%2fpg.sock/db4');
485              
486             # Username, database and additional options
487             $pg->from_string('postgresql://sri@/db5?PrintError=1&pg_server_prepare=0');
488              
489             # Service and additional options
490             $pg->from_string('postgresql://?service=foo&PrintError=1&RaiseError=0');
491              
492             # Username, database, an option and search_path
493             $pg->from_string('postgres://sri@/db6?&PrintError=1&search_path=test_schema');
494              
495             =head2 new
496              
497             my $pg = Mojo::Pg->new;
498             my $pg = Mojo::Pg->new('postgresql://postgres@/test');
499             my $pg = Mojo::Pg->new(Mojo::Pg->new);
500              
501             Construct a new L object and parse connection string with
502             L if necessary.
503              
504             # Customize configuration further
505             my $pg = Mojo::Pg->new->dsn('dbi:Pg:service=foo');
506              
507             =head1 DEBUGGING
508              
509             You can set the C environment variable to get some advanced
510             diagnostics information printed by L.
511              
512             DBI_TRACE=1
513             DBI_TRACE=15
514             DBI_TRACE=SQL
515              
516             =head1 REFERENCE
517              
518             This is the class hierarchy of the L distribution.
519              
520             =over 2
521              
522             =item * L
523              
524             =item * L
525              
526             =item * L
527              
528             =item * L
529              
530             =item * L
531              
532             =item * L
533              
534             =back
535              
536             =head1 AUTHOR
537              
538             Sebastian Riedel, C.
539              
540             =head1 CREDITS
541              
542             In alphabetical order:
543              
544             =over 2
545              
546             Christopher Eveland
547              
548             Dan Book
549              
550             Flavio Poletti
551              
552             Hernan Lopes
553              
554             William Lindley
555              
556             =back
557              
558             =head1 COPYRIGHT AND LICENSE
559              
560             Copyright (C) 2014-2017, Sebastian Riedel and others.
561              
562             This program is free software, you can redistribute it and/or modify it under
563             the terms of the Artistic License version 2.0.
564              
565             =head1 SEE ALSO
566              
567             L, L,
568             L.
569              
570             =cut