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 |