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