File Coverage

blib/lib/PGObject/Composite.pm
Criterion Covered Total %
statement 47 102 46.0
branch 4 32 12.5
condition 1 18 5.5
subroutine 16 29 55.1
pod 10 10 100.0
total 78 191 40.8


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