DBIx::Admin::DSNManager - Manage a file of DSNs, for both testing and production
#!/usr/bin/env perl
use strict;
use warnings;
use DBIx::Admin::DSNManager;
# --------------------------
my($man1) = DBIx::Admin::DSNManager -> new
(
config => {'Pg.1' => {dsn => 'dbi:Pg:dbname=test', username => 'me', active => 1} },
verbose => 1,
) || die $DBIx::Admin::DSNManager::errstr;
my($file_name) = '/tmp/dsn.ini';
$man1 -> write($file_name);
my($man2) = DBIx::Admin::DSNManager -> new
(
file_name => $file_name,
verbose => 1,
) || die $DBIx::Admin::DSNManager::errstr;
$man2 -> report;
See scripts/synopsis.pl.
DBIx::Admin::DSNManager manages a file of DSNs, for both testing and production.
The default directory and file name ('dsn.ini') are discussed in "Method: new()", under file_name.
The INI-style format was selected, rather than, say, using an SQLite database, so that casual users could edit the file without needing to know SQL and without having to install the command line program sqlite3.
Each DSN is normally for something requiring manual preparation, such as creating the database named in the DSN.
In the case of SQLite, etc, where manual intervention is not required, you can still put the DSN in dsn.ini.
One major use of this module is to avoid environment variable overload, since it's common to test Perl modules by setting the env vars $DBI_DSN, $DBI_USER and $DBI_PASS.
But then the problem becomes: What do you do when you want to run tests against a set of databases servers? Some modules define sets of env vars, one set per database server, with awkward and hard-to-guess names. This is messy and obscure.
DBIx::Admin::DSNManager is a solution to this problem.
By design, DBIx::Admin::DSNManager does not provide a create-database option.
For database servers like Postgres, MySQL, etc, you must create users, and give them the createdb privilege. Such actions are outside the scope of this module.
For database servers like SQLite, any code can create a database anyway, but you can use options in dsn.ini to indicate the DSN is inactive, or not to be used for testing. See "The Format of dsn.ini" below.
Of course, you may have DSNs in dsn.ini which you don't want to be used for testing.
Here's a policy for handling such situations:
Each DSN in the file can be marked with the option 'use_for_testing = 0', to stop usage for testing, or 'use_for_testing = 1', to allow usage for testing.
The default is 0 - do not use for testing.
For cases like SQLite, testing code can either look in dsn.ini, or manufacture a temporary directory and file name for testing.
This leads to a new question: If the testing code finds a DSN in dsn.ini which is marked use_for_testing = 0, should that code still generate another DSN for testing? My suggestions is: Yes, since the one in dsn.ini does not indicate that all possible DSNs should be blocked from testing.
On disk, dsn.ini is a typical INI-style file. In RAM it is a hashref of config options. E.g.:
config => {'Pg.1' => {dsn => 'dbi:Pg:dbname=test', ...}, 'Pg.2' => {...} }
where config is the name of this module's getter/setter which provides access to the hashref.
Section names are unique, case-sensitive, strings.
So 2 Postgres sections might be:
[Pg.1]
...
[Pg.2]
...
Each section can have these keys:
A typical Postgres dsn would be:
dsn = dbi:Pg:dbname=test
A dsn key is mandatory within each section.
The DSN names the driver to use and the database.
E.g.: username = testuser
A username is optional.
If a username is not provided for a dsn, the empty string is used.
E.g.: password = testpass
A password is optional.
If a password is not provided for a dsn, the empty string is used.
E.g.:
attributes = {AutoCommit => 1, PrintError => 0, RaiseError = 1}
Attributes are optional.
Their format is exactly the same as for DBI.
If attributes are not provided, they default to the example above.
E.g.: active = 0
or active = 1
The active key is optional.
If the active key is not provided for a dsn, it defaults to 0 - do not use.
This key means you can easily disable a DSN without having to delete the section, or comment it all out.
E.g.: use_for_testing = 0
or use_for_testing = 1
The use_for_testing key is optional.
If the use_for_testing key is not provided for a dsn, it defaults to 0 - do not use for testing.
So, a sample dsn.ini file looks like:
[Pg.1]
dsn=dbi:Pg:dbname=test1
username=user1
password=pass1
attributes = {AutoCommit => 1, PrintError => 0, RaiseError => 1}
use_for_testing = 0
[Pg.2]
dsn=dbi:Pg:dbname=test2
username=user2
password=pass2
active = 0
use_for_testing = 1
[SQLite.1]
dsn=dbi:SQLite:dbname=/tmp/test.module.sqlite
This file is read by Config::Tiny. Check its docs for details, but there is one thing to be aware of: Config::Tiny does not recognize comments at the ends of lines. So:
key = value # A comment.
sets key to 'value # A comment.', which is probably not what you intended.
Calling new() returns a object of type DBIx::Admin::DSNManager, or - if new() fails - it returns undef. For details see "Trouble with Errors".
new() takes a hash of key/value pairs, some of which might be mandatory. Further, some combinations might be mandatory.
The keys are listed here in alphabetical order.
They are lower-case because they are (also) method names, meaning they can be called to set or get the value at any time.
But a warning: In some cases, setting them after this module has used the previous value, will have no effect. All such cases are documented (or should be).
Specifies a hashref to use as the initial value of the internal config hashref which holds the set of DSNs.
This hashref is keyed by section name, with each key pointing to a hashref of dsn data. E.g.:
config => {'Pg.1' => {dsn => 'dbi:Pg:dbname=test', ...}, 'Pg.2' => {...} }
Specifies the name of the file holding the DSNs.
If the $string is an absolute path to a file, it is used as-is.
If it is not absolute, it is assumed to be relative to this module's configuration directory, which is determined by:
my($config_dir) = File::HomeDir -> my_dist_config('DBIx-Admin-DSNManager', {create => 1});
See File::HomeDir for details.
This key is optional.
The default value is "$config_dir/dsn.ini".
Specify more or less output.
The default value is 0.
Get or set the internal config hashref holding all the DSN data.
The [] mean the hashref parameter is optional.
If called as config({...}), set the config hashref to the parameter.
If called as config(), return the config hashref.
Returns a string corresponding to the $hashref.
{} is converted to '{}'.
Read $file_name using Config::Tiny and set the config hashref.
If called as $object -> report, print both $object -> file_name, and the contents of the config hashref, to STDERR.
If called as $object -> report({...}), print just the contents of the hashref to STDERR.
The [] mean the hashref parameter is optional.
Returns a hashref built from the string, or the empty string.
The string is expected to be something like '{AutoCommit => 1, PrintError => 0}'.
The empty string is returned as {}.
Validate the given or config hashref.
Returns the validated hashref, with defaults filled in.
The [] mean the hashref parameter is optional.
If a hashref is not supplied, validate the config one.
Currently, the checks are:
Write the given or config hashref to $file_name.
The [] mean a parameter is optional.
If called as $object -> write('dsn.ini'), write the config hashref to $file_name.
If called as $object -> write('dsn.ini', {...}), write the given hashref to $file_name.
If called as $object -> write({...}), write the given hashref to $object -> file_name.
File::Slurp is used to write this file, since these hashes are not of type Config::Tiny.
When object construction fails, new() sets $DBIx::Admin::DSNManager::errstr and returns undef. This means you can use this idiom:
my($dsn_manager) = DBIx::Admin::DSNManager -> new(...) || process_error($DBIx::Admin::DSNManager::errstr);
However, when methods detect errors they die, so after successful object construction, you can do:
use Try::Tiny;
try
{
$dsn_manager -> some_method_which_may_die;
}
catch
{
process_error($_); # Because $_ holds the error message.
};
Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.
Log a bug on RT: https://rt.cpan.org/Public/Dist/Display.html?Name=Test-Setup-Database.
DBIx::Admin::DSNManager was written by Ron Savage
in 2010.
Home page: http://savage.net.au/index.html.
Australian copyright © 2010, Ron Savage.
All Programs of mine are 'OSI Certified Open Source Software';
you can redistribute them and/or modify them under the terms of
The Artistic License, a copy of which is available at:
http://www.opensource.org/licenses/index.html