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.001003';
3             # ABSTRACT: Detect what database you are connected to
4              
5 4     4   261314 use Moo;
  4         66880  
  4         25  
6 4     4   8637 use DBIx::Introspector::Driver;
  4         15  
  4         5981  
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 15     15   49 sub _root_driver { shift->_drivers->[0] }
68              
69             has _drivers_by_name => (
70             is => 'ro',
71 6     6   1936 builder => sub { +{ map { $_->name => $_ } @{$_[0]->_drivers} } },
  68         213  
  6         30  
72             clearer => '_clear_drivers_by_name',
73             lazy => 1,
74             );
75              
76             sub add_driver {
77 2     2 1 85 my ($self, $driver) = @_;
78              
79 2         11 $self->_clear_drivers_by_name;
80             # check for dupes?
81 2         699 push @{$self->_drivers}, DBIx::Introspector::Driver->new($driver)
  2         56  
82             }
83              
84             sub replace_driver {
85 2     2 1 774 my ($self, $driver) = @_;
86              
87 2         54 $self->_clear_drivers_by_name;
88 2         28 @{$self->_drivers} = (
  2         67  
89 2         15 (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 70 my ($self, $name, $key, $value) = @_;
106              
107 1 50       6 if (my $d = $self->_drivers_by_name->{$name}) {
108 1         6 $d->_add_connected_option($key => $value)
109             } else {
110 0         0 die "no such driver <$name>"
111             }
112             }
113              
114             sub get {
115 14     14 1 82592 my ($self, $dbh, $dsn, $key, $opt) = @_;
116 14   100     135 $opt ||= {};
117              
118 14         316 my @args = (
119             drivers_by_name => $self->_drivers_by_name,
120             key => $key
121             );
122              
123 14 100 66     149 if ($dbh and my $driver = $self->_driver_for((ref $dbh eq 'CODE' ? $dbh->() : $dbh), $dsn)) {
    100          
124 8         78 my $ret = $driver
125             ->_get_when_connected({
126             dbh => $dbh,
127             dsn => $dsn,
128             @args,
129             });
130 8 100       73 return $ret if defined $ret;
131 2         11 $ret = $driver
132             ->_get_when_unconnected({
133             dsn => $dsn,
134             @args,
135             });
136 2 100       13 return $ret if defined $ret;
137             }
138              
139 7 50       66 my $dsn_ret = $self->_driver_for($dbh, $dsn)
140             ->_get_when_unconnected({
141             dsn => $dsn,
142             @args,
143             }) if $dsn;
144 7 100       61 return $dsn_ret if defined $dsn_ret;
145              
146 2 50 33     12 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         23 die "wtf"
158             }
159              
160             sub _driver_for {
161 15     15   30 my ($self, $dbh, $dsn) = @_;
162              
163 15 50 66     171 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 15         46 my $driver = $self->_root_driver;
172 15         19 my $done;
173              
174             DETECT:
175 15         19 do {
176 43         387 $done = $driver->_determine($dbh, $dsn);
177 43 50       908 if (!defined $done) {
    100          
178 0         0 die "cannot figure out wtf this is"
179             } elsif ($done ne 1) {
180 28 50       9785 $driver = $self->_drivers_by_name->{$done}
181             or die "no such driver <$done>"
182             }
183             } while $done ne 1;
184              
185 15         103 return $driver
186             }
187              
188             1;
189              
190             __END__