File Coverage

lib/Oryx/DBI.pm
Criterion Covered Total %
statement 12 100 12.0
branch 1 46 2.1
condition n/a
subroutine 5 13 38.4
pod 10 10 100.0
total 28 169 16.5


line stmt bran cond sub pod time code
1             package Oryx::DBI;
2              
3 15     15   6316 use Oryx::DBI::Class;
  15         50  
  15         158  
4              
5 15     15   442 use base qw(Oryx Oryx::MetaClass Ima::DBI);
  15         28  
  15         14573  
6              
7             our $DEBUG = 0;
8              
9             =head1 NAME
10              
11             Oryx::DBI - DBI Storage interface for Oryx
12              
13             =head1 SYNOPSIS
14              
15             my $storage = Oryx::DBI->new;
16            
17             $storage->connect([ 'dbi:Pg:dbname=mydb', $usname, $passwd]);
18             $storage->connect([ 'dbi:Pg:dbname=mydb', $usname, $passwd], $schema);
19            
20             $storage->dbh;
21             $storage->db_name;
22             $storage->ping;
23             $storage->schema;
24             $storage->util;
25             $storage->set_util;
26             $storage->deploy_class;
27             $storage->deploy_schema;
28              
29             =head1 DESCRIPTION
30              
31             DBI Storage interface for Oryx. You should not need to instantiate
32             this directly, use C<< Oryx->connect() >> instead.
33              
34             =head1 METHODS
35              
36             =over
37              
38             =item new
39              
40             Simple constructor
41              
42             =cut
43              
44             sub new {
45 15     15 1 36 my $class = shift;
46 15         77 return bless { }, $class;
47             }
48              
49             =item connect( \@conn, [$schema] )
50              
51             Called by C<< Oryx->connect() >>. You shouldn't need to be doing this.
52              
53             =cut
54              
55             sub connect {
56 15     15 1 45 my ($self, $conn, $schema) = @_;
57              
58 15 50   15   8205 eval "use $schema"; $self->_croak($@) if $@;
  0         0  
  0         0  
  15         735  
  15         205  
59              
60 0           my $db_name = $schema->name;
61 0 0         $self->_croak("no schema name '$db_name'")
62             unless $db_name;
63              
64 0 0         ref($self)->set_db($db_name, @$conn)
65             unless UNIVERSAL::can($self, "db_$db_name");
66              
67 0           $self->init('Oryx::DBI::Class', $conn, $schema);
68 0           return $self;
69             }
70              
71             =item dbh
72              
73             returns the cached L handle object
74              
75             =cut
76              
77             sub dbh {
78 0     0 1   my $class = shift;
79 0           my $db_name = $class->db_name;
80 0           eval { $class->$db_name };
  0            
81 0 0         $class->_croak($@) if $@;
82 0           return $class->$db_name();
83             }
84              
85             =item db_name
86              
87             Shortcut for C<< "db_".$self->schema->name >> used for passing
88             a name to L's C method.
89              
90             =cut
91              
92             sub db_name {
93 0     0 1   my $self = shift;
94 0           return "db_".$self->schema->name;
95             }
96              
97             =item ping
98              
99             ping the database
100              
101             =cut
102              
103             sub ping {
104 0     0 1   my $self = shift;
105 0           my $sth = $self->dbh->prepare('SELECT 1+1');
106 0           $sth->execute;
107 0           $sth->finish;
108             }
109              
110             =item schema
111              
112             returns the schema if called with no arguments, otherwise
113             sets if called with a L instance.
114              
115             =cut
116              
117             sub schema {
118 0     0 1   my $self = shift;
119 0 0         $self->{schema} = shift if @_;
120 0           $self->{schema};
121             }
122              
123             =item util
124              
125             simple mutator for accessing the oryx::dbi::util::x instance
126              
127             =cut
128              
129             sub util {
130 0     0 1   my $self = shift;
131 0 0         $self->{util} = shift if @_;
132 0           $self->{util};
133             }
134              
135             =item set_util
136              
137             determines which L class to instantiate
138             by looking at the dsn passed to C and sets it
139              
140             =cut
141              
142             sub set_util {
143 0     0 1   my ($self, $dsn) = @_;
144 0           $dsn =~ /^dbi:(\w+)/i;
145 0           my $utilClass = __PACKAGE__."\::Util\::$1";
146              
147 0           eval "use $utilClass";
148 0 0         $self->_carp($@) if $@;
149              
150             # Can't construct the utilClass: fallback to Generic and pray it works
151 0 0         unless (UNIVERSAL::can($utilClass, 'new')) {
152 0           $utilClass = __PACKAGE__."\::Util::Generic";
153              
154 0           eval "use $utilClass";
155 0 0         $self->_croak($@) if $@;
156             }
157              
158 0           $self->util($utilClass->new);
159             }
160              
161              
162             =item deploy_schema( $schema )
163              
164             Takes a L instance and deploys all classes seen by that
165             schema instance to the database building all tables needed for storing
166             your persistent objects.
167              
168             =cut
169              
170             sub deploy_schema {
171 0     0 1   my ($self, $schema) = @_;
172 0 0         $schema = $self->schema unless defined $schema;
173              
174 0 0         $DEBUG && $self->_carp(
175             "deploy_schema $schema : classes => "
176             .join(",\n", $schema->classes)
177             );
178              
179 0           foreach my $class ($schema->classes) {
180 0           $self->deploy_class($class);
181             }
182             }
183              
184             =item deploy_class( $class )
185              
186             does the work of deploying a given class' tables and link tables to
187             the database; called by C
188              
189             =cut
190              
191             sub deploy_class {
192 0     0 1   my $self = shift;
193 0           my $class = shift;
194 0 0         $DEBUG && $self->_carp("DEPLOYING $class");
195              
196 0 0         eval "use $class"; $self->_croak($@) if $@;
  0            
197              
198 0           my $dbh = $class->dbh;
199 0           my $table = $class->table;
200              
201 0           my $int = $self->util->type2sql('Integer');
202 0           my $oid = $self->util->type2sql('Oid');
203              
204 0           my @columns = ('id');
205 0           my @types = ($oid);
206 0 0         if ($class->is_abstract) {
207 0 0         $DEBUG && $self->_carp("CLASS $class IS ABSTRACT");
208 0           push @columns, '_isa';
209 0           push @types, $self->util->type2sql('String');
210             }
211              
212 0           foreach my $attrib (values %{$class->attributes}) {
  0            
213 0 0         $DEBUG && $self->_carp("GOT ATTRIBUTE => $attrib");
214 0           push @columns, $attrib->name;
215 0           push @types, $self->util->type2sql($attrib->primitive, $attrib->size);
216             }
217              
218 0           foreach my $assoc (values %{$class->associations}) {
  0            
219 0           my $target_class = $assoc->class;
220 0 0         eval "use $target_class"; $self->_croak($@) if $@;
  0            
221 0 0         if ($assoc->type ne 'Reference') {
    0          
222             # create a link table
223 0           my $lt_name = $assoc->link_table;
224 0           my @lt_cols = $assoc->link_fields;
225 0           my @lt_types = ($int) x 2;
226              
227             # set up the meta column (3rd entry in @lt_cols) to store
228             # indicies or keys depeding on the type of Association
229 0 0         if (lc($assoc->type) eq 'array') {
    0          
230 0           push @lt_types, $int;
231             }
232             elsif (lc($assoc->type) eq 'hash') {
233 0           push @lt_types, $self->util->type2sql('String');
234             }
235              
236             $self->util->table_create(
237 0           $dbh, $lt_name, \@lt_cols, \@lt_types
238             );
239             }
240             elsif (not $assoc->is_weak) {
241 0           push @types, $int;
242 0           push @columns, $assoc->role;
243             }
244             }
245              
246 0 0         if (@{$class->parents}) {
  0            
247 0           my @lt_cols = (lc($class->name.'_id'));
248 0           my @lt_types = ($int) x (scalar(@{$class->parents}) + 1);
  0            
249 0           my $lt_name = lc($class->name."_parents");
250 0           push @lt_cols, map { lc($_->class->name) } @{$class->parents};
  0            
  0            
251              
252 0 0         $DEBUG && $self->_carp(
253             "PARENT $_, lt_name => $lt_name, lt_cols => "
254             .join("|", @lt_cols).", lt_types => "
255             .join("|", @lt_types));
256              
257             # create the link table
258 0           $self->util->table_create(
259             $dbh, $lt_name, \@lt_cols, \@lt_types
260             );
261             }
262              
263 0           $self->util->table_create($dbh, $table, \@columns, \@types);
264             # $self->util->sequence_create($dbh, $table);
265              
266 0           $dbh->commit;
267             }
268              
269             1;
270              
271             =head1 SEE ALSO
272              
273             L, L, L
274              
275             =head1 AUTHOR
276              
277             Copyright (C) 2005 Richard Hundt
278              
279             =head1 LICENSE
280              
281             This library is free software and may be used under the same terms as Perl itself.
282              
283             =cut