File Coverage

blib/lib/Dancer2/Plugin/Database.pm
Criterion Covered Total %
statement 15 31 48.3
branch 0 4 0.0
condition 0 5 0.0
subroutine 5 9 55.5
pod n/a
total 20 49 40.8


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