| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package PGObject::Simple; |
|
2
|
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
16182
|
use 5.010; |
|
|
3
|
|
|
|
|
9
|
|
|
4
|
3
|
|
|
3
|
|
16
|
use strict; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
62
|
|
|
5
|
3
|
|
|
3
|
|
14
|
use warnings; |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
88
|
|
|
6
|
3
|
|
|
3
|
|
16
|
use Carp; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
169
|
|
|
7
|
3
|
|
|
3
|
|
1213
|
use PGObject; |
|
|
3
|
|
|
|
|
11212
|
|
|
|
3
|
|
|
|
|
15
|
|
|
8
|
3
|
|
|
3
|
|
839
|
use parent 'Exporter'; |
|
|
3
|
|
|
|
|
430
|
|
|
|
3
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
PGObject::Simple - Minimalist stored procedure mapper based on LedgerSMB's DBObject |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 VERSION |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Version 3.0.1 |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=cut |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our $VERSION = 3.000001; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use PGObject::Simple; |
|
25
|
|
|
|
|
|
|
my $obj = PGObject::Simple->new(%myhash); |
|
26
|
|
|
|
|
|
|
$obj->set_dbh($dbh); # Database connection |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
To call a stored procedure with enumerated arguments. |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
my @results = $obj->call_procedure( |
|
31
|
|
|
|
|
|
|
funcname => $funcname, |
|
32
|
|
|
|
|
|
|
funcschema => $funcname, |
|
33
|
|
|
|
|
|
|
args => [$arg1, $arg2, $arg3], |
|
34
|
|
|
|
|
|
|
); |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
You can add something like a running total as well: |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my @results = $obj->call_procedure( |
|
39
|
|
|
|
|
|
|
funcname => $funcname, |
|
40
|
|
|
|
|
|
|
funcschema => $funcname, |
|
41
|
|
|
|
|
|
|
args => [$arg1, $arg2, $arg3], |
|
42
|
|
|
|
|
|
|
running_funcs => [{agg => 'sum(amount)', alias => 'total'}], |
|
43
|
|
|
|
|
|
|
); |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
To call a stored procedure with named arguments from a hashref. This is |
|
46
|
|
|
|
|
|
|
typically done when mapping object properties in to stored procedure arguments. |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
my @results = $obj->call_dbmethod( |
|
49
|
|
|
|
|
|
|
funcname => $funcname, |
|
50
|
|
|
|
|
|
|
funcschema => $funcname, |
|
51
|
|
|
|
|
|
|
running_funcs => [{agg => 'sum(amount)', alias => 'total'}], |
|
52
|
|
|
|
|
|
|
); |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
To call a stored procedure with named arguments from a hashref with overrides. |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
my @results = $obj->call_dbmethod( |
|
57
|
|
|
|
|
|
|
funcname => 'customer_save', |
|
58
|
|
|
|
|
|
|
funcschema => 'public', |
|
59
|
|
|
|
|
|
|
running_funcs => [{agg => 'sum(amount)', alias => 'total'}], |
|
60
|
|
|
|
|
|
|
args => { id => undef }, # force to create new! |
|
61
|
|
|
|
|
|
|
); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head1 EXPORTS |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
We now allow various calls to be exported. We recommend using the tags. |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 One-at-a-time Exports |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=over |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=item call_dbmethod |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=item call_procedure |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=item set_dbh |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=item _set_funcprefix |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=item _set_funcschema |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=item _set_registry |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=back |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=head2 Export Tags |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
Below are the export tags listed including the leading ':' used to invoke them. |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=over |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=item :mapper |
|
93
|
|
|
|
|
|
|
call_dbmethod, call_procedure, and set_dbh |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=item :full |
|
96
|
|
|
|
|
|
|
All methods that can be exported at once. |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=back |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
our @EXPORT_OK = qw(call_dbmethod call_procedure set_dbh associate dbh |
|
103
|
|
|
|
|
|
|
_set_funcprefix |
|
104
|
|
|
|
|
|
|
_set_funcschema _set_registry); |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
our %EXPORT_TAGS = (mapper => [qw(call_dbmethod call_procedure set_dbh dbh)], |
|
107
|
|
|
|
|
|
|
full => \@EXPORT_OK); |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
PGObject::Simple a top-half object system for PGObject which is simple and |
|
112
|
|
|
|
|
|
|
inspired by (and a subset functionally speaking of) the simple stored procedure |
|
113
|
|
|
|
|
|
|
object method system of LedgerSMB 1.3. The framework discovers stored procedure |
|
114
|
|
|
|
|
|
|
APIs and dispatches to them and can therefore be a base for application-specific |
|
115
|
|
|
|
|
|
|
object models and much more. |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
PGObject::Simple is designed to be light-weight and yet robust glue between your |
|
118
|
|
|
|
|
|
|
object model and the RDBMS's stored procedures. It works by looking up the |
|
119
|
|
|
|
|
|
|
stored procedure arguments, stripping them of the conventional prefix 'in_', and |
|
120
|
|
|
|
|
|
|
mapping what is left to object property names. Properties can be |
|
121
|
|
|
|
|
|
|
overridden by passing in a hashrefs in the args named argument. Named arguments |
|
122
|
|
|
|
|
|
|
there will be used in place of object properties. |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
This system is quite flexible, perhaps too much so, and it relies on the |
|
125
|
|
|
|
|
|
|
database encapsulating its own logic behind self-documenting stored procedures |
|
126
|
|
|
|
|
|
|
using consistent conventions. No function which is expected to be discovered can |
|
127
|
|
|
|
|
|
|
be overloaded, and all arguments must be named for their object properties. For |
|
128
|
|
|
|
|
|
|
this reason the use of this module fundamentally changes the contract of the |
|
129
|
|
|
|
|
|
|
stored procedure from that of a fixed number of arguments in fixed types |
|
130
|
|
|
|
|
|
|
contract to one where the name must be unique and the stored procedures must be |
|
131
|
|
|
|
|
|
|
coded to the application's interface. This inverts the way we typically think |
|
132
|
|
|
|
|
|
|
about stored procedures and makes them much more application friendly. |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head2 new |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
This constructs a new object. Basically it copies the incoming hash (one level |
|
139
|
|
|
|
|
|
|
deep) and then blesses it. If the hash passed in has a dbh member, the dbh |
|
140
|
|
|
|
|
|
|
is set to that. This does not set the function prefix, as this is assumed to |
|
141
|
|
|
|
|
|
|
be done implicitly by subclasses. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=cut |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub new { |
|
146
|
2
|
|
|
2
|
1
|
25
|
my ($self) = shift @_; |
|
147
|
2
|
|
|
|
|
10
|
my %args = @_; |
|
148
|
2
|
|
|
|
|
3
|
my $ref = {}; |
|
149
|
2
|
|
|
|
|
11
|
$ref->{$_} = $args{$_} for keys %args; |
|
150
|
2
|
|
|
|
|
5
|
bless ($ref, $self); |
|
151
|
2
|
|
|
|
|
12
|
$ref->set_dbh($ref->{dbh}); |
|
152
|
2
|
|
|
|
|
9
|
$ref->_set_funcprefix($ref->{_funcprefix}); |
|
153
|
2
|
|
|
|
|
8
|
$ref->_set_funcschema($ref->{_funcschema}); |
|
154
|
2
|
|
|
|
|
6
|
$ref->_set_registry($ref->{_registry}); |
|
155
|
2
|
50
|
|
|
|
8
|
$ref->associate($self) if ref $self; |
|
156
|
2
|
|
|
|
|
7
|
return $ref; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=head2 set_dbh($dbh) |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Sets the database handle (needs DBD::Pg 2.0 or later) to $dbh |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=cut |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub set_dbh { |
|
166
|
4
|
|
|
4
|
1
|
430
|
my ($self, $dbh) = @_; |
|
167
|
4
|
|
|
|
|
12
|
$self->{_dbh} = $dbh; |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head2 dbh |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Returns the database handle for the object. |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=cut |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub dbh { |
|
177
|
4
|
|
|
4
|
1
|
11
|
my ($self) = @_; |
|
178
|
4
|
|
66
|
|
|
22
|
return ($self->{_dbh} or $self->{_DBH}); |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=head2 associate($pgobject) |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Sets the db handle to that from the $pgobject. |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
=cut |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub associate { |
|
188
|
1
|
|
|
1
|
1
|
3
|
my ($self, $other) = @_; |
|
189
|
1
|
|
|
|
|
3
|
$self->set_dbh($other->dbh); |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=head2 _set_funcprefix |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
This sets the default funcprefix for future calls. The funcprefix can still be |
|
195
|
|
|
|
|
|
|
overridden by passing in an explicit '' in a call. This is used to "claim" a |
|
196
|
|
|
|
|
|
|
certain set of stored procedures in the database for use by an object. |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
It is semi-private, intended to be called by subclasses directly, perhaps in |
|
199
|
|
|
|
|
|
|
constructors, but not from outside the object. |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=cut |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub _set_funcprefix { |
|
204
|
2
|
|
|
2
|
|
6
|
my ($self, $funcprefix) = @_; |
|
205
|
2
|
|
|
|
|
3
|
$self->{_func_prefix} = $funcprefix; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head2 _set_funcschema |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
This sets the default funcschema for future calls. This is overwridden by |
|
211
|
|
|
|
|
|
|
per-call arguments, (PGObject::Util::DBMethod provides for such overrides on a |
|
212
|
|
|
|
|
|
|
per-method basis). |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub _set_funcschema { |
|
217
|
2
|
|
|
2
|
|
5
|
my ($self, $funcschema) = @_; |
|
218
|
2
|
|
|
|
|
5
|
$self->{_func_schema} = $funcschema; |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head2 _set_registry |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
This sets the registry for future calls. The idea here is that this allows for |
|
224
|
|
|
|
|
|
|
application object model wrappers to set which registry they are using, both for |
|
225
|
|
|
|
|
|
|
predictability and ensuring that interoperability is possible. |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=cut |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub _set_registry { |
|
230
|
2
|
|
|
2
|
|
6
|
my ($self, $registry) = @_; |
|
231
|
2
|
|
|
|
|
5
|
$self->{_registry} = $registry; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=head2 call_dbmethod |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Does a straight-forward mapping (as described below) to the stored procedure |
|
237
|
|
|
|
|
|
|
arguments. Stored procedure arguments are looked up, a leading 'in_' is |
|
238
|
|
|
|
|
|
|
stripped off where it exists, and the remaining string mapped back to an |
|
239
|
|
|
|
|
|
|
object property. The $args{args} hashref can be used to override arguments by |
|
240
|
|
|
|
|
|
|
name. Unknown properties are handled simply by passing a NULL in, so the |
|
241
|
|
|
|
|
|
|
stored procedures should be prepared to handle these. |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
As with call_procedure below, this returns a single hashref when called in a |
|
244
|
|
|
|
|
|
|
scalar context, and a list of hashrefs when called in a list context. |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
NEW IN 2.0: We now give preference to functions of the same name over |
|
247
|
|
|
|
|
|
|
properties. So $obj->foo() will be used before $obj->{foo}. This enables |
|
248
|
|
|
|
|
|
|
better data encapsulation. |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=cut |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub _arg_defaults { |
|
253
|
0
|
|
|
0
|
|
|
my ($self, %args) = @_; |
|
254
|
0
|
|
|
|
|
|
local $@; |
|
255
|
0
|
0
|
|
|
|
|
if (ref $self) { |
|
256
|
0
|
|
0
|
|
|
|
$args{dbh} ||= eval { $self->dbh } ; |
|
|
0
|
|
|
|
|
|
|
|
257
|
0
|
|
0
|
|
|
|
$args{funcprefix} //= eval { $self->funcprefix } ; |
|
|
0
|
|
|
|
|
|
|
|
258
|
0
|
|
0
|
|
|
|
$args{funcschema} //= eval { $self->funcschema } ; |
|
|
0
|
|
|
|
|
|
|
|
259
|
0
|
|
0
|
|
|
|
$args{funcprefix} //= $self->{_func_prefix}; |
|
260
|
0
|
|
0
|
|
|
|
$args{funcschema} //= $self->{_func_schema}; |
|
261
|
0
|
|
0
|
|
|
|
$args{funcprefix} //= eval {$self->_get_prefix() }; |
|
|
0
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
} else { |
|
263
|
|
|
|
|
|
|
# see if we have package-level reader/factories |
|
264
|
0
|
|
0
|
|
|
|
$args{dbh} ||= "$self"->dbh; # if eval {"$self"->dbh}; |
|
265
|
0
|
0
|
0
|
|
|
|
$args{funcschema} //= "$self"->funcschema if eval {"$self"->funcschema}; |
|
|
0
|
|
|
|
|
|
|
|
266
|
0
|
0
|
0
|
|
|
|
$args{funcprefix} //= "$self"->funcprefix if eval {"$self"->funcprefix}; |
|
|
0
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
} |
|
268
|
0
|
|
0
|
|
|
|
$args{funcprefix} //= ''; |
|
269
|
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
return %args |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub _self_to_arg { # refactored from map call, purely internal |
|
274
|
0
|
|
|
0
|
|
|
my ($self, $args, $argname) = @_; |
|
275
|
0
|
|
|
|
|
|
my $db_arg; |
|
276
|
0
|
|
|
|
|
|
$argname =~ s/^in_//; |
|
277
|
0
|
|
|
|
|
|
local $@; |
|
278
|
0
|
0
|
0
|
|
|
|
if (ref $self and $argname){ |
|
279
|
0
|
0
|
|
|
|
|
if (eval { $self->can($argname) } ) { |
|
|
0
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
|
eval { $db_arg = $self->can($argname)->($self) }; |
|
|
0
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
} else { |
|
282
|
0
|
|
|
|
|
|
$db_arg = $self->{$argname}; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
} |
|
285
|
0
|
0
|
|
|
|
|
$db_arg = $args->{args}->{$argname} if exists $args->{args}->{$argname}; |
|
286
|
0
|
0
|
|
|
|
|
$db_arg = $db_arg->to_db if eval {$db_arg->can('to_db')}; |
|
|
0
|
|
|
|
|
|
|
|
287
|
0
|
0
|
|
|
|
|
$db_arg = { type => 'bytea', value => $db_arg} if $_->{type} eq 'bytea'; |
|
288
|
|
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
|
return $db_arg; |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub call_dbmethod { |
|
293
|
0
|
|
|
0
|
1
|
|
my ($self) = shift @_; |
|
294
|
0
|
|
|
|
|
|
my %args = @_; |
|
295
|
0
|
0
|
|
|
|
|
croak 'No function name provided' unless $args{funcname}; |
|
296
|
0
|
|
|
|
|
|
%args = _arg_defaults($self, %args); |
|
297
|
0
|
|
|
|
|
|
my $info = PGObject->function_info(%args); |
|
298
|
|
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
my $arglist = []; |
|
300
|
0
|
|
|
|
|
|
@{$arglist} = map { _self_to_arg($self, \%args, $_->{name}) } |
|
|
0
|
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
|
@{$info->{args}}; |
|
|
0
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
$args{args} = $arglist; |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# The conditional return is necessary since the object may carry a registry |
|
305
|
|
|
|
|
|
|
# --CT |
|
306
|
0
|
0
|
|
|
|
|
return $self->call_procedure(%args) if ref $self; |
|
307
|
0
|
|
|
|
|
|
return __PACKAGE__->call_procedure(%args); |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head2 call_procedure |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
This is a lightweight wrapper around PGObject->call_procedure which merely |
|
313
|
|
|
|
|
|
|
passes the currently attached db connection in. We use the previously set |
|
314
|
|
|
|
|
|
|
funcprefix and dbh by default but other values can be passed in to override the |
|
315
|
|
|
|
|
|
|
default object's values. |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
This returns a single hashref when called in a scalar context, and a list of |
|
318
|
|
|
|
|
|
|
hashrefs when called in a list context. When called in a scalar context it |
|
319
|
|
|
|
|
|
|
simply returns the single first row returned. |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=cut |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub call_procedure { |
|
324
|
0
|
|
|
0
|
1
|
|
my ($self, %args) = @_; |
|
325
|
0
|
|
|
|
|
|
%args = _arg_defaults($self, %args); |
|
326
|
0
|
0
|
|
|
|
|
croak 'No DB handle provided' unless $args{dbh}; |
|
327
|
0
|
|
|
|
|
|
my @rows = PGObject->call_procedure(%args); |
|
328
|
0
|
0
|
|
|
|
|
return shift @rows unless wantarray; |
|
329
|
0
|
|
|
|
|
|
return @rows; |
|
330
|
|
|
|
|
|
|
} |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head1 WRITING CLASSES WITH PGObject::Simple |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
Unlike PGObject, which is only loosely tied to the functionality in question |
|
335
|
|
|
|
|
|
|
and presumes that relevant information will be passed over a functional |
|
336
|
|
|
|
|
|
|
interface, PGObject is a specific framework for object-oriented coding in Perl. |
|
337
|
|
|
|
|
|
|
It can therefore be used alone or with other modules to provide quite a bit of |
|
338
|
|
|
|
|
|
|
functionality. |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
A PGObject::Simple object is a blessed hashref with no gettors or setters. This |
|
341
|
|
|
|
|
|
|
is thus ideal for cases where you are starting and just need some quick mappings |
|
342
|
|
|
|
|
|
|
of stored procedures to hashrefs. You reference properties simply with the |
|
343
|
|
|
|
|
|
|
$object->{property} syntax. There is very little encapsulation in objects, and |
|
344
|
|
|
|
|
|
|
very little abstraction except when it comes to the actual stored procedure |
|
345
|
|
|
|
|
|
|
interfaces. In essence, PGObject::Simple generally assumes that the actual |
|
346
|
|
|
|
|
|
|
data structure is essentially a public interface between the database and |
|
347
|
|
|
|
|
|
|
whatever else is going on with the application. |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
The general methods can then wrap call_procedure and call_dbmethod calls, |
|
350
|
|
|
|
|
|
|
mapping out to stored procedures in the database. |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Stored procedures must be written to relatively exacting specifications. |
|
353
|
|
|
|
|
|
|
Arguments must be named, with names prefixed optionally with 'in_' (if the |
|
354
|
|
|
|
|
|
|
property name starts with 'in_' properly one must also prefix it). |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
An example of a simple stored procedure might be: |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION customer_get(in_id int) returns customer |
|
359
|
|
|
|
|
|
|
RETURNS setof customer language sql as $$ |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
select * from customer where id = $1; |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
$$; |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
This stored procedure could then be called with any of: |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
$obj->call_dbmethod( |
|
368
|
|
|
|
|
|
|
funcname => 'customer_get', |
|
369
|
|
|
|
|
|
|
); # retrieve the customer with the $obj->{id} id |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
$obj->call_dbmethod( |
|
372
|
|
|
|
|
|
|
funcname => 'customer_get', |
|
373
|
|
|
|
|
|
|
args => {id => 3 }, |
|
374
|
|
|
|
|
|
|
); # retrieve the customer with the id of 3 regardless of $obj->{id} |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
$obj->call_procedure( |
|
377
|
|
|
|
|
|
|
funcname => 'customer_get', |
|
378
|
|
|
|
|
|
|
args => [3], |
|
379
|
|
|
|
|
|
|
); |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head1 AUTHOR |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
Chris Travers, C<< >> |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head1 BUGS |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
Please report any bugs or feature requests to C, or through |
|
388
|
|
|
|
|
|
|
the web interface at L. I will be notified, and then you'll |
|
389
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
=head1 SUPPORT |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
perldoc PGObject::Simple |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
You can also look for information at: |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=over 4 |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
L |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
L |
|
412
|
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=item * CPAN Ratings |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
L |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=item * Search CPAN |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
L |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=back |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
Copyright 2013-2017 Chris Travers. |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
Redistribution and use in source and compiled forms with or without |
|
432
|
|
|
|
|
|
|
modification, are permitted provided that the following conditions are met: |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=over |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=item |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
Redistributions of source code must retain the above |
|
439
|
|
|
|
|
|
|
copyright notice, this list of conditions and the following disclaimer as the |
|
440
|
|
|
|
|
|
|
first lines of this file unmodified. |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=item |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
Redistributions in compiled form must reproduce the above copyright |
|
445
|
|
|
|
|
|
|
notice, this list of conditions and the following disclaimer in the |
|
446
|
|
|
|
|
|
|
source code, documentation, and/or other materials provided with the |
|
447
|
|
|
|
|
|
|
distribution. |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=back |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND |
|
452
|
|
|
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
453
|
|
|
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
454
|
|
|
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR |
|
455
|
|
|
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
456
|
|
|
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
457
|
|
|
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
|
458
|
|
|
|
|
|
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
459
|
|
|
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
460
|
|
|
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=cut |
|
463
|
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
1; # End of PGObject::Simple |