File Coverage

blib/lib/PGObject/Composite.pm
Criterion Covered Total %
statement 20 98 20.4
branch 0 30 0.0
condition 0 15 0.0
subroutine 7 28 25.0
pod 10 10 100.0
total 37 181 20.4


line stmt bran cond sub pod time code
1             package PGObject::Composite;
2              
3 1     1   13635 use 5.010;
  1         4  
4 1     1   4 use strict;
  1         2  
  1         25  
5 1     1   4 use warnings FATAL => 'all';
  1         5  
  1         53  
6              
7 1     1   6 use Carp;
  1         2  
  1         57  
8 1     1   407 use PGObject;
  1         6348  
  1         6  
9 1     1   402 use PGObject::Type::Composite; # needed to import routines
  1         3414  
  1         6  
10 1     1   68 use parent 'Exporter', 'PGObject::Type::Composite';
  1         2  
  1         3  
11              
12             our @EXPORT_OK = qw(call_procedure to_db from_db call_ebmethod
13             _get_dbh _get_funcschema _get_funcprefix _get_fypeschema
14             _get_typename default_dbh default_schema default_prefix);
15             our %EXPORT_TAGS = (all => \@EXPORT_OK,
16             mapper => [qw{call_procedure to_db from_db call_ebmethod
17             default_dbh default_schema default_prefix}],
18             );
19              
20             =head1 NAME
21              
22             PGObject::Composite - Composite Type Mapper for PGObject
23              
24             =head1 VERSION
25              
26             Version 1.0.1
27              
28             =cut
29              
30             our $VERSION = 1.000001;
31              
32              
33             =head1 SYNOPSIS
34              
35             This module provides a more object-oriented type of interface for writing
36             stored procedures for PostgreSQL than the Simple mapper. The Composite mapper
37             assumes that the object calling the call_dbmethod function usually wants its
38             type on the first argument. Thus we provide an extra function where this is
39             not the case (call_dbfunction).
40              
41             So we given a cumposite type:
42              
43             CREATE TYPE foo AS (bar int, baz text);
44              
45             and a stored procedure:
46              
47             CREATE OR REPLACE FUNCTION int(foo) returns int language sql as $$
48             SELECT length($1.baz) + $1.bar;
49             $$;
50              
51             We can have a package:
52              
53             package mycomposite;
54             use PGObject::Composite;
55             sub new {
56             my $pkg = shift;
57             bless shift, $pkg;
58             }
59              
60             sub to_int {
61             my $self = shift;
62             my ($ref) = $shelf->call_dbmethod(funcname => 'int');
63             return shift values %$ref;
64             }
65              
66             =head1 SUBROUTINES/METHODS
67              
68             =head2 new
69              
70             This constructs a new object. Basically it copies the incoming hash (one level
71             deep) and then blesses it. If the hash passed in has a dbh member, the dbh
72             is set to that. This does not set the function prefix, as this is assumed to
73             be done implicitly by subclasses.
74              
75             =cut
76              
77             sub new {
78 0     0 1   my ($self) = shift @_;
79 0           my %args = @_;
80 0           my $ref = {};
81 0           $ref->{$_} = $args{$_} for keys %args;
82 0           bless ($ref, $self);
83 0           $ref->set_dbh($ref->{dbh});
84 0           $ref->_set_funcprefix($ref->{_funcprefix});
85 0           $ref->_set_funcschema($ref->{_funcschema});
86 0           $ref->_set_registry($ref->{_registry});
87 0 0         $ref->associate($self) if ref $self;
88 0           return $ref;
89             }
90              
91             sub _set_funcprefix {
92 0     0     my ($self, $prefix) = @_;
93 0           $self->{_funcprefix} = $prefix;
94             }
95              
96             sub _set_funcschema {
97 0     0     my ($self, $schema) = @_;
98 0           $self->{_funcschema} = $schema;
99             }
100              
101             sub _set_registry {
102 0     0     my ($self, $registry) = @_;
103 0           $self->{_registry} = $registry;
104             }
105              
106             =head2 set_dbh
107              
108             Sets the database handle
109              
110             =cut
111              
112             sub set_dbh {
113 0     0 1   my ($self, $dbh) = @_;
114 0           $self->{_dbh} = $dbh;
115             }
116              
117             sub _set_dbh {
118 0     0     my ($self, $dbh) = @_;
119 0           $self->set_dbh($dbh);
120             }
121              
122             =head2 dbh
123              
124             returns the dbh of the object
125              
126             =cut
127              
128             sub dbh {
129 0     0 1   my ($self) = @_;
130 0           return $self->_get_dbh;
131             }
132              
133             sub _get_dbh {
134 0     0     my ($self) = @_;
135 0 0 0       return $self->{_dbh} if ref $self and $self->{_dbh};
136 0 0         return $self->default_dbh if ref $self;
137 0           return "$self"->default_dbh;
138             }
139              
140             =head2 associate
141              
142             Assocates the current object with another PGObject-based class
143              
144             =cut
145              
146             sub associate {
147 0     0 1   my ($self, $other) = @_;
148 0           $self->set_dbh($other->dbh);
149             }
150              
151             =head2 default_dbh
152              
153             returns the dbh used by default. Subclasses must override.
154              
155             =cut
156              
157             sub default_dbh {
158 0     0 1   croak 'Must override default dbh factory';
159             }
160              
161             sub _get_funcschema {
162 0     0     my ($self) = @_;
163 0 0 0       return $self->{_funcschema} if ref $self and $self->{_funcschema};
164 0 0         return $self->default_schema if ref $self;
165 0           return "$self"->default_schema;
166             }
167              
168             =head2 default_schema
169              
170             returns the schema used by default. defaalt is 'public'
171              
172             =cut
173              
174 0     0 1   sub default_schema { 'public' }
175              
176             sub _get_funcprefix {
177 0     0     my ($self) = @_;
178 0 0 0       return $self->{_funcprefix} if ref $self and $self->{_funcprefix};
179 0           return $self->default_prefix;
180 0           return "$self"->default_prefix;
181             }
182              
183             sub _get_schema {
184 0     0     my ($self) = @_;
185 0 0 0       return $self->{_funcprefix} if ref $self and $self->{_funcprefix};
186 0           return $self->default_schema;
187 0           return "$self"->default_schema;
188             }
189              
190             sub _set_schema {
191 0     0     my ($self, $schema);
192 0           $self->{_schema} = $schema;
193             }
194              
195             =head2 default_prefix
196              
197             returns the prefix used by default. Default is empty string
198              
199             =cut
200              
201 0     0 1   sub default_prefix { '' }
202              
203             sub _get_registry {
204 0     0     my ($self) = @_;
205 0 0 0       return $self->{_registry} if ref $self and $self->{_registry};
206 0 0         return $self->default_registry if ref $self;
207 0           return "$self"->default_registry;
208             }
209              
210             =head2 default_registry
211              
212             Returns the registry used by default. Default is 'default'
213              
214             =cut
215              
216 0     0 1   sub default_registry { 'default' }
217              
218             =head2 call_dbmethod
219              
220             Calls a mapped method with the current object as the argument named "self."
221              
222             This allows for stored procedurs to differentiate what is related to a related
223             type and what is not.
224              
225             =cut
226              
227             sub _build_args {
228 0     0     my ($self, $args) = @_;
229 0           delete $args->{$_} for qw(typename typeschema); # invariants
230 0           my %args;
231             %args = (map {
232 0           my $f = "_get_$_";
  0            
233 0 0         $_ => (ref $self ? $self->$f() : "$self"->$f() )
234             }
235             qw(funcschema dbh funcprefix registry typename typeschema));
236 0 0         %args = (%args, %$args) if ref $args;
237 0           return %args;
238             }
239              
240             sub call_dbmethod {
241 0     0 1   my $self = shift;
242 0           my %args = @_;
243 0           %args = _build_args($self, \%args);
244              
245             my $funcinfo = PGObject->function_info(
246             %args, (argtype1 => $args{typename},
247             argschema => $args{typeschema})
248 0           );
249 0           my @dbargs = (map { my $name = $_->{name};
250 0           $name =~ s/^in_//i;
251 0 0         $name eq 'self'? $self : $args{args}->{$name} ;
252 0           } @{$funcinfo->{args}});
  0            
253 0           my @rows = PGObject->call_procedure(%args, ( args => \@dbargs ));
254 0 0         return shift @rows unless wantarray;
255 0           return @rows;
256             }
257              
258             =head2 call_procedure
259              
260             Maps to PGObject::call_procedure with appropriate defaults.
261              
262             =cut
263              
264             sub call_procedure {
265 0     0 1   my ($self) = shift @_;
266 0           my %args = @_;
267 0           %args = _build_args($self, \%args);
268              
269 0 0         croak 'No DB handle provided' unless $args{dbh};
270 0           my @rows = PGObject->call_procedure(%args);
271 0 0         return shift @rows unless wantarray;
272 0           return @rows;
273             }
274              
275             =head1 INTERFACES TO OVERRIDE
276              
277             =head2 _get_schema
278              
279             Defaults to public. This is the type's schema
280              
281             =head2 _get_funcschema
282              
283             defaults to public.
284              
285             =head2 _get_typename
286              
287             The name of the composite type. Must be set.
288              
289             =head2 _get_dbh
290              
291             The database connection to use. Must be set.
292              
293             =head1 AUTHOR
294              
295             Chris Travers, C<< >>
296              
297             =head1 BUGS
298              
299             Please report any bugs or feature requests to C, or through
300             the web interface at L. I will be notified, and then you'll
301             automatically be notified of progress on your bug as I make changes.
302              
303              
304              
305              
306             =head1 SUPPORT
307              
308             You can find documentation for this module with the perldoc command.
309              
310             perldoc PGObject::Composite
311              
312              
313             You can also look for information at:
314              
315             =over 4
316              
317             =item * RT: CPAN's request tracker (report bugs here)
318              
319             L
320              
321             =item * AnnoCPAN: Annotated CPAN documentation
322              
323             L
324              
325             =item * CPAN Ratings
326              
327             L
328              
329             =item * Search CPAN
330              
331             L
332              
333             =back
334              
335              
336             =head1 ACKNOWLEDGEMENTS
337              
338              
339             =head1 LICENSE AND COPYRIGHT
340              
341             Copyright 2014 Chris Travers.
342              
343             This program is distributed under the (Revised) BSD License:
344             L
345              
346             Redistribution and use in source and binary forms, with or without
347             modification, are permitted provided that the following conditions
348             are met:
349              
350             * Redistributions of source code must retain the above copyright
351             notice, this list of conditions and the following disclaimer.
352              
353             * Redistributions in binary form must reproduce the above copyright
354             notice, this list of conditions and the following disclaimer in the
355             documentation and/or other materials provided with the distribution.
356              
357             * Neither the name of Chris Travers's Organization
358             nor the names of its contributors may be used to endorse or promote
359             products derived from this software without specific prior written
360             permission.
361              
362             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
363             "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
364             LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
365             A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
366             OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
367             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
368             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
369             DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
370             THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
371             (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
372             OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
373              
374              
375             =cut
376              
377             1; # End of PGObject::Composite