File Coverage

lib/Fry/Lib/CDBI/Load.pm
Criterion Covered Total %
statement 9 115 7.8
branch 0 28 0.0
condition 0 15 0.0
subroutine 3 19 15.7
pod 0 6 0.0
total 12 183 6.5


line stmt bran cond sub pod time code
1             package Fry::Lib::CDBI::Load;
2 1     1   844 use strict qw/subs vars/;
  1         2  
  1         279  
3             our @ISA;
4             #local data
5             my %db_driver = (qw/mysql dbi:mysql: postgres dbi:Pg:dbname= sqlite
6             dbi:SQLite:dbname=/);
7             our $cdbi_class = "Class::DBI";
8             our $regex_operator;
9             #methods
10             sub _default_data {
11             return {
12 0     0     vars=>{
13             qw/user bozo
14             pwd bozo
15             db postgres
16             dbname useful/,
17             table=>'junk',
18             columns=>'',
19             action_columns=>'',
20             set_db_opts=>{AutoCommit=>1},
21             db_default=>{
22             postgres=>{
23             regex=>'~',
24             },
25             mysql=>{
26             regex=>'REGEXP',
27             },
28             sqlite=>{
29             },
30              
31             },
32             table_class=>'My::CDBI',
33             #flags
34             CDBI_Loader=>1,
35             get_columns=>1,
36             },
37             opts=>{
38             table=>{qw/a t type var noreset 1 default junk/,
39             action=>sub {shift->Var('cmd_class')->newTable($_[0])} },
40 0           action_columns=>{qw/a C type var noreset 1/,
41 0     0     action=> sub {$_[0]->setVar(action_columns=>[$_[0]->sub->parseNum($_[1],@{$_[0]->Var('columns')})])}
42             }
43             },
44 0     0     class=>'Class::DBI',
45             }
46             }
47             sub _initLib {
48 0     0     my $cls = shift;
49 1     1   5 no strict 'refs';
  1         2  
  1         724  
50              
51             #should be done by tags=class attribute
52 0           my $table_class = $cls->Var('table_class');
53 0           $cls->sub->_require ($cdbi_class);
54 0           push (@{"$table_class\::ISA"},$cdbi_class);
  0            
55              
56 0           $regex_operator = $cls->_regex_operator;
57              
58 0           $cls->setupCdbi;
59             }
60              
61             #Setup subs
62             sub setupCdbi {
63 0     0 0   my $cls = shift;
64            
65 0           my $table_class = $cls->Var('table_class');
66 0           my ($dbname,$db,$user,$pwd,$set_db_opts) = $cls->varMany(qw/dbname db user pwd set_db_opts/);
67 0 0         warn("Database $db doesn't have a dsn entry and thus set_db was not set up correctly")
68             if (! exists $db_driver{$db});
69              
70 0           eval "use Class::DBI::Loader ";
71 0 0         if ($Class::DBI::Loader::VERSION < 0.07) {
72 0           $cls->view("Need at least version 0.07 for Class::DBI::Loader");
73 0           $cls->setFlag('CDBI_Loader'=>0);
74              
75             }
76 0 0 0       if ($@ or ! $cls->Flag('CDBI_Loader')) {
77              
78 0           $table_class->set_db('Main',$db_driver{$db}.$dbname,$user,$pwd,$set_db_opts);
79 0           $cls->newCdbiTable;
80             }
81 0           else { $cls->initCdbiLoader }
82             }
83             sub newTable {
84 0     0 0   my ($cls,$table) = @_;
85 0           eval "require Class::DBI::Loader";
86 0 0 0       if ($@ or ! $cls->Flag('CDBI_Loader')) {
87 0           $cls->setVar(table=>$table);
88 0           $cls->newCdbiTable;
89             }
90 0           else { $cls->initCdbiLoader(table=>$table) }
91             }
92             sub newCdbiTable {
93             #new table info coming from var
94 0     0 0   my $cls = shift;
95 0           my $table_class = $cls->Var('table_class');
96 0           $table_class->table($cls->Var('table'));
97              
98             #td: only works for 3 databases
99 0           $cls->init_columns;
100              
101 0           $table_class->columns(All => @{$cls->Var('columns')});
  0            
102              
103             #td: set sequences for any db
104 0 0         $table_class->sequence($cls->Var('table').'_'.$cls->Var('columns')->[0].'_seq')
105             if ($cls->Var('db') eq "postgres");
106             }
107             sub initCdbiLoader {
108 0     0 0   my ($cls,%arg) = @_;
109 0           my %set = %arg;
110              
111 0           for (qw/pwd user db dbname table set_db_opts/) {
112 0   0       $arg{$_} = $arg{$_} || $cls->Var($_)
113             }
114            
115 0 0         my $loader = Class::DBI::Loader->new(
116             dsn => $db_driver{$arg{db}}.$arg{dbname},
117             user => $arg{user},
118             password => $arg{pwd},
119             options=>$arg{set_db_opts},
120             #tables=>[$arg{table}],
121             constraint=>"^$arg{table}\$",
122             namespace => ucfirst($arg{db}),
123             ) or die "new CDBIL object failed: $@";
124              
125             #if new definition has been successful
126 0           $cls->setVar(%set);
127              
128             #subclass latest shell and its fns into $tableclass
129 0           my $table_class = $loader->find_class($arg{table});
130 0           $cls->setVar(table_class=>$table_class);
131              
132             #hack: each Class::DBI::* loaded table first has cdbi subclass + then class::db::*
133             #as parents
134 1     1   16 { no strict 'refs';
  1         2  
  1         1016  
  0            
135 0           my $tc = $cls->Var('table_class');
136 0           unshift(@{"$tc\::ISA"},'My::CDBI');
  0            
137             }
138              
139             #hack: don't pass existing columns b/c they're out of order
140 0           $cls->init_columns; #(columns=>[map {$_->name} $table_class->columns('All')]);
141             }
142             #Internal subs
143             sub _regex_operator {
144 0 0   0     $_[0]->Var('db_default')->{$_[0]->Var('db')}->{regex} || "LIKE"
145             }
146             sub dbiSource {
147 0     0 0   my $cls = shift;
148 0           my ($db,$dbname,$user,$pwd) = $cls->varMany(qw/db dbname user pwd/);
149 0           return ($db_driver{$db}.$dbname,$user,$pwd);
150             }
151             sub init_columns {
152             #d: initializes column data dependent &columns
153 0     0 0   my ($cls,%arg) = @_;
154 0   0       my $db = $arg{db} || $cls->Var('db');
155 0   0       my $table = $arg{table} || $cls->Var('table');
156 0           my $table_class = $cls->Var('table_class');
157              
158             #set &columns
159 0 0         if (exists $arg{columns}) {
    0          
160 0           $cls->setVar(columns=>$arg{columns})
161             }
162             #create columns
163             elsif ($cls->Flag('get_columns')) {
164 0           my $method = "getcol_$db";
165 0 0         if ($table_class->can($method)){
  0 0          
166 0           $cls->setVar(columns=>[$table_class->$method($table)]);
167             }
168             #fall back on defined columns from Class::DBI, whose order isn't dependable :(
169             elsif (my @columns = map {$_->name} $table_class->columns('All') > 0) {
170 0           $cls->setVar(columns=>[@columns]);
171             }
172 0           else { warn "Columns aren't loaded for this table" }
173             }
174              
175             #sync &action_columns with &columns
176 0           $cls->setVar(action_columns=>$cls->Var('columns'));
177             }
178              
179             package My::CDBI;
180              
181             sub search_regex {
182 0     0     my $cls = shift;
183 0           $cls->_do_search($regex_operator=> @_);
184             }
185             #subclass of Class::DBI b/c these functions expect it
186             #h: the rest of the functions have been copied from their Class::DBI::*
187             #all the getcol* does is return the columns of a table in order
188             sub getcol_postgres {
189 0     0     my ($class,$table) = @_;
190 0           my @columns;
191 0           eval {require DBD::Pg};
  0            
192              
193 0 0         my $catalog = ($class->pg_version >= 7.3) ? "pg_catalog." : "";
194 0           my $sth = $class->db_Main->prepare("SELECT a.attname, a.attnum FROM ${catalog}pg_class c, ${catalog}pg_attribute a
195             WHERE c.relname = ? AND a.attnum > 0 AND a.attrelid = c.oid ORDER BY a.attnum");
196 0           $sth->execute($table);
197 0           my $columns = $sth->fetchall_arrayref;
198 0           $sth->finish;
199              
200 0           foreach my $col(@$columns) {
201             # skip dropped column.
202 0 0         next if $col->[0] =~ /^\.+pg\.dropped\.\d+\.+$/;
203 0           push @columns, $col->[0];
204             }
205 0           return @columns;
206             }
207             sub getcol_sqlite {
208 0     0     my ($class,$table) = @_;
209 0           my $sth = $class->db_Main->prepare("PRAGMA table_info(?)");
210 0           $sth->execute($table);
211 0           my @columns;
212 0           while (my $row = $sth->fetchrow_hashref) {
213 0           push @columns,$row->{name};
214             }
215 0           $sth->finish;
216 0           return @columns;
217             }
218             sub getcol_mysql {
219             #d:get columns of tb
220             #t:mysql
221 0     0     my $class = shift;
222 0           my (@columns, @pri);
223              
224 0           $class->set_sql(desc_table => 'DESCRIBE __TABLE__');
225 0           (my $sth = $class->sql_desc_table)->execute;
226              
227 0           while (my $hash = $sth->fetch_hash) {
228 0           my ($col) = $hash->{field} =~ /(\w+)/;
229 0           push @columns, $col;
230 0 0         push @pri, $col if $hash->{key} eq "PRI";
231             }
232             #$class->_croak("$table has no primary key") unless @pri;
233             return @columns
234 0           }
235             #used by getcol_postgres
236             sub pg_version {
237 0     0     my $class = shift;
238 0           my $dbh = $class->db_Main;
239 0           my $sth = $dbh->prepare("SELECT version()");
240 0           $sth->execute;
241 0           my($ver_str) = $sth->fetchrow_array;
242 0           $sth->finish;
243 0           my($ver) = $ver_str =~ m/^PostgreSQL ([\d\.]{3})/;
244 0           return $ver;
245             }
246             1;
247              
248             __END__