File Coverage

blib/lib/Algorithm/Dependency/Source/DBI.pm
Criterion Covered Total %
statement 49 52 94.2
branch 9 16 56.2
condition 2 6 33.3
subroutine 12 12 100.0
pod 4 4 100.0
total 76 90 84.4


line stmt bran cond sub pod time code
1             package Algorithm::Dependency::Source::DBI;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Algorithm::Dependency::Source::DBI - Database source for Algorithm::Dependency
8              
9             =head1 SYNOPSIS
10              
11             use DBI;
12             use Algorithm::Dependency;
13             use Algorithm::Dependency::Source::DBI;
14            
15             # Load the data from a database
16             my $data_source = Algorithm::Dependency::Source::DBI->new(
17             dbh => DBI->connect('dbi:SQLite:sqlite.db'),
18             select_ids => 'select name from stuff',
19             select_depends => 'select from, to from m2m_deps',
20             );
21            
22             # Create the dependency object, and indicate the items that are already
23             # selected/installed/etc in the database
24             my $dep = Algorithm::Dependency->new(
25             source => $data_source,
26             selected => [ 'This', 'That' ]
27             ) or die 'Failed to set up dependency algorithm';
28            
29             # For the item 'Foo', find out the other things we also have to select.
30             # This WON'T include the item we selected, 'Foo'.
31             my $also = $dep->depends( 'Foo' );
32             print $also
33             ? "By selecting 'Foo', you are also selecting the following items: "
34             . join( ', ', @$also )
35             : "Nothing else to select for 'Foo'";
36            
37             # Find out the order we need to act on the items in.
38             # This WILL include the item we selected, 'Foo'.
39             my $schedule = $dep->schedule( 'Foo' );
40              
41             =head1 DESCRIPTION
42              
43             The L module has shown itself to be quite reliable
44             over a long period of time, as well as relatively easy to setup and use.
45              
46             However, recently there has been an increasing use of things like
47             L to store and distribute structured data.
48              
49             L extends L
50             by providing a simple way to create dependency objects that pull their
51             data from a database directly.
52              
53             =head1 METHODS
54              
55             =cut
56              
57 2     2   119050 use 5.005;
  2         7  
  2         73  
58 2     2   11 use strict;
  2         4  
  2         74  
59 2     2   1189 use Params::Util qw{ _STRING _ARRAY _INSTANCE };
  2         4440  
  2         139  
60 2     2   2101 use Algorithm::Dependency::Item ();
  2         4873  
  2         36  
61 2     2   13 use Algorithm::Dependency::Source ();
  2         5  
  2         37  
62              
63 2     2   10 use vars qw{$VERSION @ISA};
  2         3  
  2         117  
64             BEGIN {
65 2     2   6 $VERSION = '1.06';
66 2         1237 @ISA = 'Algorithm::Dependency::Source';
67             }
68              
69              
70              
71              
72              
73             #####################################################################
74             # Constructor and Accessors
75              
76             =pod
77              
78             =head2 new
79              
80             my $simple = Algorithm::Dependency::Source::DBI->new(
81             dbh => $dbi_db_handle,
82             select_ids => 'select name from stuff',
83             select_depends => 'select from, to from m2m_deps',
84             );
85            
86             my $complex = Algorithm::Dependency::Source::DBI->new(
87             dbh => $dbi_db_handle,
88             select_ids => [ 'select name from stuff where foo = ?', 'bar' ],
89             select_depends => [ 'select from, to from m2m_deps where from = ?', 'bar' ],
90             );
91              
92             The C constructor takes three named named params.
93              
94             The C param should be a standard L database connection.
95              
96             The C param is either a complete SQL string, or a reference to
97             an C containing a SQL string with placeholders and matching
98             variables.
99              
100             When executed on the database, it should return a single column containing
101             the complete set of all item identifiers.
102              
103             The C param is either a complete SQL string, or a reference
104             to an C containing a SQL string with placeholders and matching
105             variables.
106              
107             When executed on the database, it should return two columns containing
108             the complete set of all dependencies, where identifiers in the first-column
109             depends on identifiers in the second-column.
110              
111             Returns a new L object, or dies on
112             error.
113              
114             =cut
115              
116             sub new {
117 1     1 1 1372158 my $class = shift;
118              
119             # Create the object
120 1         7 my $self = bless { @_ }, $class;
121              
122             # Apply defaults
123 1 50       17 if ( _STRING($self->{select_ids}) ) {
124 1         5 $self->{select_ids} = [ $self->{select_ids} ];
125             }
126 1 50       143 if ( _STRING($self->{select_depends}) ) {
127 1         4 $self->{select_depends} = [ $self->{select_depends} ];
128             }
129              
130             # Check params
131 1 50       5 unless ( _INSTANCE($self->dbh, 'DBI::db') ) {
132 0         0 Carp::croak("The dbh param is not a DBI database handle");
133             }
134 1 50 33     5 unless ( _ARRAY($self->select_ids) and _STRING($self->select_ids->[0]) ) {
135 0         0 Carp::croak("Missing or invalid select_ids param");
136             }
137 1 50 33     5 unless ( _ARRAY($self->select_depends) and _STRING($self->select_depends->[0]) ) {
138 0         0 Carp::croak("Did not provide the select_depends query");
139             }
140              
141 1         4 return $self;
142             }
143              
144             =pod
145              
146             =head2 dbh
147              
148             The C accessor returns the database handle provided to the constructor.
149              
150             =cut
151              
152             sub dbh {
153 4     4 1 990 $_[0]->{dbh};
154             }
155              
156             =pod
157              
158             =head2 select_ids
159              
160             The C accessor returns the SQL statement provided to the
161             constructor. If a raw string was provided, it will be returned as a
162             reference to an C containing the SQL string and no params.
163              
164             =cut
165              
166             sub select_ids {
167 5     5 1 146 $_[0]->{select_ids};
168             }
169              
170             =pod
171              
172             =head2 select_depends
173              
174             The C accessor returns the SQL statement provided to
175             the constructor. If a raw string was provided, it will be returned as
176             a reference to an C containing the SQL string and no params.
177              
178             =cut
179              
180             sub select_depends {
181 5     5 1 109 $_[0]->{select_depends};
182             }
183              
184              
185              
186              
187              
188             #####################################################################
189             # Main Functionality
190              
191             sub _load_item_list {
192 1     1   12 my $self = shift;
193              
194             # Get the list of ids
195 1         4 my $ids = $self->dbh->selectcol_arrayref(
196             $self->select_ids->[0],
197             {}, # No options
198 1         7 @{$self->select_ids}[1..-1],
199             );
200 1         737 my %hash = map { $_ => [ ] } @$ids;
  4         17  
201              
202             # Get the list of links
203 1         4 my $depends = $self->dbh->selectall_arrayref(
204             $self->select_depends->[0],
205             {}, # No options
206 1         6 @{$self->select_depends}[1..-1],
207             );
208 1         314 foreach my $depend ( @$depends ) {
209 4 50       14 next unless $hash{$depend->[0]};
210 4 100       15 next unless $hash{$depend->[1]};
211 3         3 push @{$hash{$depend->[0]}}, $depend->[1];
  3         11  
212             }
213              
214             # Now convert to items
215 4         24 my @items = map {
216 1 50       193 Algorithm::Dependency::Item->new( $_, @{$hash{$_}} )
  4         52  
217             or return undef;
218             } keys %hash;
219              
220 1         18 \@items;
221             }
222              
223             1;
224              
225             =pod
226              
227             =head1 SUPPORT
228              
229             To file a bug against this module, use the CPAN bug tracking system
230              
231             L
232              
233             For other comments, contact the author.
234              
235             =head1 AUTHOR
236              
237             Adam Kennedy Eadamk@cpan.orgE
238              
239             =head1 SEE ALSO
240              
241             L, L
242              
243             =head1 COPYRIGHT
244              
245             Copyright 2007 - 2009 Adam Kennedy.
246              
247             This program is free software; you can redistribute
248             it and/or modify it under the same terms as Perl itself.
249              
250             The full text of the license can be found in the
251             LICENSE file included with this module.
252              
253             =cut