File Coverage

blib/lib/Dancer2/Plugin/Database.pm
Criterion Covered Total %
statement 12 28 42.8
branch 0 4 0.0
condition 0 5 0.0
subroutine 4 8 50.0
pod n/a
total 16 45 35.5


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::Database;
2              
3 2     2   543487 use strict;
  2         3  
  2         49  
4              
5 2     2   889 use Dancer::Plugin::Database::Core;
  2         2336  
  2         52  
6 2     2   888 use Dancer::Plugin::Database::Core::Handle;
  2         29192  
  2         52  
7              
8 2     2   992 use Dancer2::Plugin;
  2         3336  
  2         13  
9              
10             =encoding utf8
11              
12             =head1 NAME
13              
14             Dancer2::Plugin::Database - easy database connections for Dancer2 applications
15              
16             =cut
17              
18             our $VERSION = '2.16';
19              
20             register_hook qw(database_connected
21             database_connection_lost
22             database_connection_failed
23             database_error);
24              
25              
26             my $settings = {};
27              
28             sub _load_settings {
29 0     0     my $dsl = shift;
30             # ugly plugin1/2 switch - to be removed one day
31 0 0         if ( $dsl->app->can('with_plugin') ) {
32             # plugin2
33             # We need this for plugins which use this plugins
34 0           $settings = $dsl->config;
35             }
36             else {
37             # plugin1
38 0           $settings = plugin_setting();
39             }
40 0   0       $settings->{charset} ||= $dsl->setting('charset') || 'utf-8';
      0        
41             }
42              
43             register database => sub {
44 0     0     my $dsl = shift;
45              
46             my $logger = sub {
47 0     0     $dsl->log(@_);
48 0           };
49              
50             # wasn't working properly calling the Dancer2::Plugin execute_hook
51             # directly
52             my $hook_exec = sub {
53 0 0   0     if ( $dsl->can('execute_plugin_hook') ) {
54             # Plugin2
55 0           $dsl->execute_plugin_hook(@_);
56             }
57             else {
58             # old behaviour
59 0           $dsl->execute_hook(@_);
60             }
61 0           };
62              
63             ## This is mostly for the case the user uses 'set plugins' and
64             ## changes configuration during runtime. For example in our test suite.
65 0           _load_settings($dsl);
66              
67 0           my ($dbh, $cfg) = Dancer::Plugin::Database::Core::database( arg => $_[0],
68             logger => $logger,
69             hook_exec => $hook_exec,
70             settings => $settings );
71 0           $settings = $cfg;
72 0           return $dbh;
73             };
74              
75             register_plugin;
76              
77             =head1 SYNOPSIS
78              
79             use Dancer2;
80             use Dancer2::Plugin::Database;
81              
82             # Calling the database keyword will get you a connected database handle:
83             get '/widget/view/:id' => sub {
84             my $sth = database->prepare(
85             'select * from widgets where id = ?',
86             );
87             $sth->execute(params->{id});
88             template 'display_widget', { widget => $sth->fetchrow_hashref };
89             };
90              
91             # The handle is a Dancer::Plugin::Database::Core::Handle object, which subclasses
92             # DBI's DBI::db handle and adds a few convenience features, for example:
93             get '/insert/:name' => sub {
94             database->quick_insert('people', { name => params->{name} });
95             };
96              
97             get '/users/:id' => sub {
98             template 'display_user', {
99             person => database->quick_select('users', { id => params->{id} }),
100             };
101             };
102              
103             dance;
104              
105             Database connection details are read from your Dancer2 application config - see
106             below.
107              
108              
109             =head1 DESCRIPTION
110              
111             Provides an easy way to obtain a connected DBI database handle by simply calling
112             the database keyword within your L application
113              
114             Returns a L object, which is a subclass of
115             L's C connection handle object, so it does everything you'd expect
116             to do with DBI, but also adds a few convenience methods. See the documentation
117             for L for full details of those.
118              
119             Takes care of ensuring that the database handle is still connected and valid.
120             If the handle was last asked for more than C seconds
121             ago, it will check that the connection is still alive, using either the
122             C<< $dbh->ping >> method if the DBD driver supports it, or performing a simple
123             no-op query against the database if not. If the connection has gone away, a new
124             connection will be obtained and returned. This avoids any problems for
125             a long-running script where the connection to the database might go away.
126              
127             Care is taken that handles are not shared across processes/threads, so this
128             should be thread-safe with no issues with transactions etc. (Thanks to Matt S
129             Trout for pointing out the previous lack of thread safety. Inspiration was
130             drawn from DBIx::Connector.)
131              
132             =head1 CONFIGURATION
133              
134             Connection details will be taken from your Dancer2 application config file, and
135             should be specified as, for example:
136              
137             plugins:
138             Database:
139             driver: 'mysql'
140             database: 'test'
141             host: 'localhost'
142             port: 3306
143             username: 'myusername'
144             password: 'mypassword'
145             connection_check_threshold: 10
146             dbi_params:
147             RaiseError: 1
148             AutoCommit: 1
149             on_connect_do: ["SET NAMES 'utf8'", "SET CHARACTER SET 'utf8'" ]
150             log_queries: 1
151             handle_class: 'My::Super::Sexy::Database::Handle'
152              
153             The C setting is optional, if not provided, it
154             will default to 30 seconds. If the database keyword was last called more than
155             this number of seconds ago, a quick check will be performed to ensure that we
156             still have a connection to the database, and will reconnect if not. This
157             handles cases where the database handle hasn't been used for a while and the
158             underlying connection has gone away.
159              
160             The C setting is also optional, and if specified, should be settings
161             which can be passed to C<< DBI->connect >> as its fourth argument; see the L
162             documentation for these.
163              
164             The optional C setting is an array of queries which should be
165             performed when a connection is established; if given, each query will be
166             performed using C<< $dbh->do >>. (If using MySQL, you might want to use this to
167             set C to a suitable value to disable MySQL's built-in free data loss
168             'features', for example:
169              
170             on_connect_do: "SET SQL_MODE='TRADITIONAL'"
171              
172             (If you're not familiar with what I mean, I'm talking about the insane default
173             behaviour of "hmm, this bit of data won't fit the column you're trying to put it
174             in.. hmm, I know, I'll just munge it to fit, and throw a warning afterwards -
175             it's not like you're relying on me to, y'know, store what you ask me to store".
176             See L for
177             just one illustration. In hindsight, I wish I'd made a sensible C a
178             default setting, but I don't want to change that now.)
179              
180             The optional C setting enables logging of queries generated by the
181             helper functions C et al in L.
182             If you enable it, generated queries will be logged at 'debug' level. Be aware
183             that they will contain the data you're passing to/from the database, so be
184             careful not to enable this option in production, where you could inadvertently
185             log sensitive information.
186              
187             If you prefer, you can also supply a pre-crafted DSN using the C setting;
188             in that case, it will be used as-is, and the driver/database/host settings will
189             be ignored. This may be useful if you're using some DBI driver which requires
190             a peculiar DSN.
191              
192             The optional C defines your own class into which database handles
193             should be blessed. This should be a subclass of
194             L (or L directly, if you just want to
195             skip the extra features).
196              
197             You will require slightly different options depending on the database engine
198             you're talking to. For instance, for SQLite, you won't need to supply
199             C, C etc, but will need to supply C as the name of the
200             SQLite database file:
201              
202             plugins:
203             Database:
204             driver: SQLite
205             database: 'foo.sqlite'
206              
207             For Oracle, you may want to pass C (system ID) to identify a particular
208             database, e.g.:
209              
210             plugins:
211             Database:
212             driver: Oracle
213             host: localhost
214             sid: ABC12
215              
216              
217             If you have any further connection parameters that need to be appended
218             to the dsn, you can put them in as a hash called dsn_extra. For
219             example, if you're running mysql on a non-standard socket, you could
220             have
221              
222             plugins:
223             Database:
224             driver: mysql
225             host: localhost
226             dsn_extra:
227             mysql_socket: /tmp/mysql_staging.sock
228              
229              
230             =head2 DEFINING MULTIPLE CONNECTIONS
231              
232             If you need to connect to multiple databases, this is easy - just list them in
233             your config under C as shown below:
234              
235             plugins:
236             Database:
237             connections:
238             foo:
239             driver: "SQLite"
240             database: "foo.sqlite"
241             bar:
242             driver: "mysql"
243             host: "localhost"
244             ....
245              
246             Then, you can call the C keyword with the name of the database
247             connection you want, for example:
248              
249             my $foo_dbh = database('foo');
250             my $bar_dbh = database('bar');
251              
252              
253             =head1 RUNTIME CONFIGURATION
254              
255             You can pass a hashref to the C keyword to provide configuration
256             details to override any in the config file at runtime if desired, for instance:
257              
258             my $dbh = database({ driver => 'SQLite', database => $filename });
259              
260             (Thanks to Alan Haggai for this feature.)
261              
262             =head1 AUTOMATIC UTF-8 SUPPORT
263              
264             As of version 1.20, if your application is configured to use UTF-8 (you've
265             defined the C setting in your app config as C) then support for
266             UTF-8 for the database connection will be enabled, if we know how to do so for
267             the database driver in use.
268              
269             If you do not want this behaviour, set C to a false value when
270             providing the connection details.
271              
272              
273              
274             =head1 GETTING A DATABASE HANDLE
275              
276             Calling C will return a connected database handle; the first time it is
277             called, the plugin will establish a connection to the database, and return a
278             reference to the DBI object. On subsequent calls, the same DBI connection
279             object will be returned, unless it has been found to be no longer usable (the
280             connection has gone away), in which case a fresh connection will be obtained.
281              
282             If you have declared named connections as described above in 'DEFINING MULTIPLE
283             CONNECTIONS', then calling the database() keyword with the name of the
284             connection as specified in the config file will get you a database handle
285             connected with those details.
286              
287             You can also pass a hashref of settings if you wish to provide settings at
288             runtime.
289              
290              
291             =head1 CONVENIENCE FEATURES
292              
293             The handle returned by the C keyword is a
294             L object, which subclasses the C DBI
295             connection handle. This means you can use it just like you'd normally use a DBI
296             handle, but extra convenience methods are provided.
297              
298             There's extensive documentation on these features in
299             L, including using the C, C,
300             C options to sort / limit results and include only specific columns.
301              
302             =head1 HOOKS
303              
304             This plugin uses Dancer2's hooks support to allow you to register code that
305             should execute at given times - for example:
306              
307             hook 'database_connected' => sub {
308             my $dbh = shift;
309             # do something with the new DB handle here
310             };
311              
312             Currrently defined hook positions are:
313              
314             =over 4
315              
316             =item C
317              
318             Called when a new database connection has been established, after performing any
319             C statements, but before the handle is returned. Receives the
320             new database handle as a parameter, so that you can do what you need with it.
321              
322             =item C
323              
324             Called when the plugin detects that the database connection has gone away.
325             Receives the no-longer usable handle as a parameter, in case you need to extract
326             some information from it (such as which server it was connected to).
327              
328             =item C
329              
330             Called when an attempt to connect to the database fails. Receives a hashref of
331             connection settings as a parameter, containing the settings the plugin was using
332             to connect (as obtained from the config file).
333              
334             =item C
335              
336             Called when a database error is raised by C. Receives two parameters: the
337             error message being returned by DBI, and the database handle in question.
338              
339             =back
340              
341             If you need other hook positions which would be useful to you, please feel free
342             to suggest them!
343              
344              
345             =head1 AUTHOR
346              
347             David Precious, C<< >>
348              
349              
350              
351             =head1 CONTRIBUTING
352              
353             This module is developed on Github at:
354              
355             L
356              
357             Feel free to fork the repo and submit pull requests! Also, it makes sense to
358             L
359             on GitHub for updates.
360              
361             Feedback and bug reports are always appreciated. Even a quick mail to let me
362             know the module is useful to you would be very nice - it's nice to know if code
363             is being actively used.
364              
365             =head1 ACKNOWLEDGEMENTS
366              
367             Igor Bujna
368              
369             Franck Cuny
370              
371             Alan Haggai
372              
373             Christian Sánchez
374              
375             Michael Stiller
376              
377             Martin J Evans
378              
379             Carlos Sosa
380              
381             Matt S Trout
382              
383             Matthew Vickers
384              
385             Christian Walde
386              
387             Alberto Simões
388              
389             James Aitken (LoonyPandora)
390              
391             Mark Allen (mrallen1)
392              
393             Sergiy Borodych (bor)
394              
395             Mario Domgoergen (mdom)
396              
397             Andrey Inishev (inish777)
398              
399             Nick S. Knutov (knutov)
400              
401             Nicolas Franck (nicolasfranck)
402              
403             mscolly
404              
405             =head1 BUGS
406              
407             Please report any bugs or feature requests to C, or through
408             the web interface at L. I will be notified, and then you'll
409             automatically be notified of progress on your bug as I make changes.
410              
411              
412              
413              
414             =head1 SUPPORT
415              
416             You can find documentation for this module with the perldoc command.
417              
418             perldoc Dancer2::Plugin::Database
419              
420             You can also look for information at:
421              
422             =over 4
423              
424             =item * RT: CPAN's request tracker
425              
426             L
427              
428             =item * AnnoCPAN: Annotated CPAN documentation
429              
430             L
431              
432             =item * CPAN Ratings
433              
434             L
435              
436             =item * Search CPAN
437              
438             L
439              
440             =back
441              
442             You can find the author on IRC in the channel C<#dancer> on .
443              
444              
445             =head1 LICENSE AND COPYRIGHT
446              
447             Copyright 2010-2016 David Precious.
448              
449             This program is free software; you can redistribute it and/or modify it
450             under the terms of either: the GNU General Public License as published
451             by the Free Software Foundation; or the Artistic License.
452              
453             See http://dev.perl.org/licenses/ for more information.
454              
455              
456             =head1 SEE ALSO
457              
458             L and L
459              
460             L, L
461              
462             L
463              
464             L
465              
466             =cut
467              
468             1; # End of Dancer2::Plugin::Database