File Coverage

blib/lib/Data/Phrasebook/SQL.pm
Criterion Covered Total %
statement 49 60 81.6
branch 17 24 70.8
condition 3 6 50.0
subroutine 8 8 100.0
pod 2 2 100.0
total 79 100 79.0


line stmt bran cond sub pod time code
1             package Data::Phrasebook::SQL;
2 6     6   22284 use strict;
  6         11  
  6         228  
3 6     6   32 use warnings FATAL => 'all';
  6         14  
  6         877  
4 6     6   40 use base qw( Data::Phrasebook::Generic Data::Phrasebook::Debug );
  6         10  
  6         2269  
5 6     6   40 use Carp qw( croak );
  6         10  
  6         389  
6              
7 6     6   3421 use Data::Phrasebook::SQL::Query;
  6         13  
  6         190  
8              
9 6     6   35 use vars qw($VERSION);
  6         11  
  6         3606  
10             $VERSION = '0.35';
11              
12             =head1 NAME
13              
14             Data::Phrasebook::SQL - The SQL/DBI Phrasebook Model.
15              
16             =head1 SYNOPSIS
17              
18             use Data::Phrasebook;
19             use DBI;
20              
21             my $dbh = DBI->connect(...);
22              
23             my $book = Data::Phrasebook->new(
24             class => 'SQL',
25             dbh => $dbh,
26             file => 'queries.txt',
27             );
28             my $q = $book->query( 'find_author', {
29             author => "Lance Parkin"
30             });
31             while ( my $row = $q->fetchrow_hashref ) {
32             print "He wrote $row->{title}\n";
33             }
34             $q->finish;
35              
36             F:
37              
38             find_author=select title,author from books where author = :author
39              
40             =head1 DESCRIPTION
41              
42             In order to make use of features like placeholders in DBI in conjunction
43             with phrasebooks, it's helpful to have a phrasebook be somewhat more aware
44             of how DBI operates. Thus, you get C.
45              
46             C has knowledge of how DBI works and creates and
47             executes your queries appropriately.
48              
49             =head1 CONSTRUCTOR
50              
51             =head2 new
52              
53             Not to be accessed directly, but via the parent L, by
54             specifying the class as SQL.
55              
56             Additional arguments to those described in L are:
57              
58             =over 4
59              
60             =item *
61              
62             C - a DBI database handle.
63              
64             =back
65              
66             =head1 METHODS
67              
68             =head2 dbh
69              
70             Set, or get, the current DBI handle.
71              
72             =cut
73              
74             sub dbh {
75 12     12 1 18 my $self = shift;
76 12 100       91 return @_ ? $self->{dbh} = shift : $self->{dbh};
77             }
78              
79             =head2 query
80              
81             Constructs a L object from a template. Takes at
82             least one argument, this being the identifier for the query. The identifier is
83             used as a key into the phrasebook C. A second argument can be provided,
84             which is an optional hashref of key to value mappings.
85              
86             If phrasebook has a YAML source looking much like the following:
87              
88             ---
89             find_author:
90             sql: select class,title,author from books where author = :author
91              
92             You could write:
93              
94             my $q = $book->query( 'find_author' );
95              
96             OR
97              
98             my $q = $book->query( 'find_author', {
99             author => 'Lance Parkin'
100             } );
101              
102             OR
103              
104             my $author = 'Lance Parkin';
105             my $q = $book->query( 'find_author', {
106             author => \$author,
107             } );
108              
109             # sql = select class,title,author from books where author = ?
110             # args = 'Lance Parkin'
111              
112             In the above examples, the parameters are bound to the SQL using the bind
113             parameters functionality. This is more efficient in most cases where the
114             same SQL is reused with different values for fields.
115              
116             However, not all SQL statements just need to bind parameters, some may require
117             the ability to replace parameters, such as a field list.
118              
119             ---
120             find_author:
121             sql: select :fields from books where author = :author
122              
123             my $q = $book->query( 'find_author',
124             replace => { fields => 'class,title,author' },
125             bind => { author => 'Lance Parkin' }
126             );
127              
128             # sql = select class,title,author from books where author = ?
129             # args = 'Lance Parkin'
130              
131             In all instances, if the SQL template requested does not exist or has no
132             definition, then an error will be thrown.
133              
134             Consult L for what you can then do with your
135             returned object.
136              
137             For reference: the bind hashref argument, if it is given, is given to the
138             query object's C and then C methods.
139              
140             =cut
141              
142             sub query {
143 7     7 1 49 my ($self,$id,@args) = @_;
144              
145 7 50       19 $self->store(3,"->query IN") if($self->debug);
146              
147 7         28 my $map = $self->data($id);
148 7 100       251 croak "No mapping for '$id'" unless($map);
149 6         13 my $sql;
150              
151 6 50       27 if($self->debug) {
152 0         0 $self->store(4,"->query id=[$id]");
153 0         0 $self->store(4,"->query map=[$map]");
154             }
155              
156 6 50       20 if(ref $map eq 'HASH') {
157 0 0 0     0 croak "No SQL content for '$id'." unless exists $map->{sql}
158             and defined $map->{sql};
159 0         0 $sql = $map->{sql};
160             } else {
161 6         12 $sql = $map; # we assume sql string only
162             }
163              
164 6 100       21 unshift @args, 'bind' if(scalar(@args) == 1); # default is to bind parameters
165              
166 6 50       21 if($self->debug) {
167 0         0 $self->store(4,"->query BEFORE methods");
168 0         0 $self->store(4,"->query sql=[$sql]");
169 0         0 $self->store(4,"->query args=[".$self->dumper(\@args)."]");
170             }
171              
172 6         10 my (%args,$params,@order);
173 6         18 while(@args) {
174             # go backwards in case there are duplicate keys
175 6         23 my $args = pop @args;
176 6         12 my $method = pop @args;
177              
178 6         24 for(keys %$args) {
179 6         24 $args{$_}->{method} = $method;
180 6         28 $args{$_}->{value} = $args->{$_};
181             }
182              
183 6 100       35 $params = $args if($method eq 'bind');
184             }
185              
186 6         33 my $delim_RE = $self->delimiters();
187 6         62 $sql =~ s{$delim_RE}[
188             {
189 8 100 100     11 if(defined $args{$1} && $args{$1}->{method} eq 'replace') {
  8         57  
190 2         16 $args{$1}->{value};
191             } else {
192 6         21 push @order, $1;
193 6         26 "?"
194             }
195             };
196             ]egx;
197              
198 6 50       21 if($self->debug) {
199 0         0 $self->store(4,'->query AFTER methods');
200 0         0 $self->store(4,"->query sql=[$sql]");
201 0         0 $self->store(4,'->query order=['.join(',',@order).']');
202 0         0 $self->store(4,'->query params=['.$self->dumper($params).']');
203             }
204              
205 6         36 my $q = Data::Phrasebook::SQL::Query->new(
206             sql => $sql,
207             order => \@order,
208             dbh => $self->dbh,
209             );
210 6 100       35 $q->args( $q->order_args( $params ) ) if($params);
211 6         46 return $q;
212             }
213              
214             1;
215              
216             __END__