File Coverage

blib/lib/DBIx/Introspector.pm
Criterion Covered Total %
statement 43 55 78.1
branch 18 28 64.2
condition 7 11 63.6
subroutine 9 10 90.0
pod 5 5 100.0
total 82 109 75.2


line stmt bran cond sub pod time code
1             package DBIx::Introspector;
2             $DBIx::Introspector::VERSION = '0.001004';
3             # ABSTRACT: Detect what database you are connected to
4              
5 4     4   135371 use Moo;
  4         34849  
  4         21  
6 4     4   5568 use DBIx::Introspector::Driver;
  4         12  
  4         3910  
7              
8             has _drivers => (
9             is => 'ro',
10             required => 1,
11             init_arg => 'drivers',
12             coerce => sub {
13             return $_[0] if ref $_[0] eq 'ARRAY';
14             return [ map DBIx::Introspector::Driver->new($_),
15             {
16             name => 'DBI',
17             connected_determination_strategy => sub { $_[1]->{Driver}{Name} },
18             unconnected_determination_strategy => sub {
19             my $dsn = $_[1] || $ENV{DBI_DSN} || '';
20             my ($driver) = $dsn =~ /dbi:([^:]+):/i;
21             $driver ||= $ENV{DBI_DRIVER};
22             return $driver
23             },
24             },
25             { name => 'ACCESS', parents => ['DBI'] },
26             { name => 'DB2', parents => ['DBI'] },
27             { name => 'Informix', parents => ['DBI'] },
28             { name => 'InterBase', parents => ['DBI'] },
29             { name => 'MSSQL', parents => ['DBI'] },
30             { name => 'Oracle', parents => ['DBI'] },
31             { name => 'Pg', parents => ['DBI'] },
32             { name => 'SQLAnywhere', parents => ['DBI'] },
33             { name => 'SQLite', parents => ['DBI'] },
34             { name => 'Sybase', parents => ['DBI'] },
35             { name => 'mysql', parents => ['DBI'] },
36             { name => 'Firebird::Common', parents => ['Interbase'] },
37             { name => 'Firebird', parents => ['Interbase'] },
38             {
39             name => 'ODBC',
40             connected_determination_strategy => sub {
41             my $v = $_[0]->_get_info_from_dbh($_[1], 'SQL_DBMS_NAME');
42             $v =~ s/\W/_/g;
43             "ODBC_$v"
44             },
45             parents => ['DBI'],
46             },
47             { name => 'ODBC_ACCESS', parents => ['ACCESS', 'ODBC'] },
48             { name => 'ODBC_DB2_400_SQL', parents => ['DB2', 'ODBC'] },
49             { name => 'ODBC_Firebird', parents => ['Firebird::Common', 'ODBC'] },
50             { name => 'ODBC_Microsoft_SQL_Server', parents => ['MSSQL', 'ODBC'] },
51             { name => 'ODBC_SQL_Anywhere', parents => ['SQLAnywhere', 'ODBC'] },
52             {
53             name => 'ADO',
54             connected_determination_strategy => sub {
55             my $v = $_[0]->_get_info_from_dbh($_[1], 'SQL_DBMS_NAME');
56             $v =~ s/\W/_/g;
57             "ADO_$v"
58             },
59             parents => ['DBI'],
60             },
61             { name => 'ADO_MS_Jet', parents => ['ACCESS', 'ADO'] },
62             { name => 'ADO_Microsoft_SQL_Server', parents => ['MSSQL', 'ADO'] },
63             ] if $_[0] eq '2013-12.01'
64             },
65             );
66              
67 17     17   45 sub _root_driver { shift->_drivers->[0] }
68              
69             has _drivers_by_name => (
70             is => 'ro',
71 6     6   1450 builder => sub { +{ map { $_->name => $_ } @{$_[0]->_drivers} } },
  68         187  
  6         24  
72             clearer => '_clear_drivers_by_name',
73             lazy => 1,
74             );
75              
76             sub add_driver {
77 2     2 1 46 my ($self, $driver) = @_;
78              
79 2         8 $self->_clear_drivers_by_name;
80             # check for dupes?
81 2         610 push @{$self->_drivers}, DBIx::Introspector::Driver->new($driver)
  2         44  
82             }
83              
84             sub replace_driver {
85 2     2 1 736 my ($self, $driver) = @_;
86              
87 2         51 $self->_clear_drivers_by_name;
88 2         22 @{$self->_drivers} = (
  2         51  
89 2         13 (grep $_ ne $driver->{name}, @{$self->_drivers}),
90             DBIx::Introspector::Driver->new($driver)
91             );
92             }
93              
94             sub decorate_driver_unconnected {
95 0     0 1 0 my ($self, $name, $key, $value) = @_;
96              
97 0 0       0 if (my $d = $self->_drivers_by_name->{$name}) {
98 0         0 $d->_add_unconnected_option($key => $value)
99             } else {
100 0         0 die "no such driver <$name>"
101             }
102             }
103              
104             sub decorate_driver_connected {
105 1     1 1 55 my ($self, $name, $key, $value) = @_;
106              
107 1 50       5 if (my $d = $self->_drivers_by_name->{$name}) {
108 1         5 $d->_add_connected_option($key => $value)
109             } else {
110 0         0 die "no such driver <$name>"
111             }
112             }
113              
114             sub get {
115 16     16 1 18668 my ($self, $dbh, $dsn, $key, $opt) = @_;
116 16   100     72 $opt ||= {};
117              
118 16         347 my @args = (
119             drivers_by_name => $self->_drivers_by_name,
120             key => $key
121             );
122              
123 16 100 66     138 if ($dbh and my $driver = $self->_driver_for((ref $dbh eq 'CODE' ? $dbh->() : $dbh), $dsn)) {
    100          
124 10         62 my $ret = $driver
125             ->_get_when_connected({
126             dbh => $dbh,
127             dsn => $dsn,
128             @args,
129             });
130 10 100       56 return $ret if defined $ret;
131 4         14 $ret = $driver
132             ->_get_when_unconnected({
133             dsn => $dsn,
134             @args,
135             });
136 4 100       20 return $ret if defined $ret;
137             }
138              
139 7 50       23 my $dsn_ret = $self->_driver_for($dbh, $dsn)
140             ->_get_when_unconnected({
141             dsn => $dsn,
142             @args,
143             }) if $dsn;
144 7 100       47 return $dsn_ret if defined $dsn_ret;
145              
146 2 50 33     10 if (ref $dbh eq 'CODE' && ref $opt->{dbh_fallback_connect} eq 'CODE') {
147 0         0 $opt->{dbh_fallback_connect}->();
148 0         0 my $dbh = $dbh->();
149 0         0 return $self->_driver_for($dbh, $dsn)
150             ->_get_when_connected({
151             dbh => $dbh,
152             dsn => $dsn,
153             @args,
154             })
155             }
156              
157 2         19 die "wtf"
158             }
159              
160             sub _driver_for {
161 17     17   23 my ($self, $dbh, $dsn) = @_;
162              
163 17 50 66     135 if ($dbh and my $d = $dbh->{private_dbii_driver}) {
164 0 0       0 if (my $found = $self->_drivers_by_name->{$d}) {
165 0         0 return $found
166             } else {
167 0         0 warn "user requested non-existant driver $d"
168             }
169             }
170              
171 17         38 my $driver = $self->_root_driver;
172 17         15 my $done;
173              
174             DETECT:
175 17         18 do {
176 49         383 $done = $driver->_determine($dbh, $dsn);
177 49 50       1063 if (!defined $done) {
    100          
178 0         0 die "cannot figure out wtf this is"
179             } elsif ($done ne 1) {
180 32 50       627 $driver = $self->_drivers_by_name->{$done}
181             or die "no such driver <$done>"
182             }
183             } while $done ne 1;
184              
185 17         68 return $driver
186             }
187              
188             1;
189              
190             __END__