line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
StoredHash::ISA - Allow Object to be-a StoredHash by automatically inheriting persistence abilities. |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 DESCRIPTION |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
StoredHash::ISA allows to create an IS-A (ISA in Perl lingo) relationship between any object class |
8
|
|
|
|
|
|
|
and StoredHash persister. This allows you to call StoredHash methods directly via instance |
9
|
|
|
|
|
|
|
(or as Class methods where appropriate). |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
Because StoredHash::ISA bases persistence operations on class introspection, the persisted |
12
|
|
|
|
|
|
|
objects must belong to a class package and not be "plain" HASHes (You'd use StoredHash). |
13
|
|
|
|
|
|
|
Even when some methods are overloaded to work as Instance or class methods, the Objects |
14
|
|
|
|
|
|
|
must be blessed. |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Using StoredHash::ISA as a base class allows you to use following persistence methods |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=over 4 |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=item * insert() - as instance method |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=item * update() - as instance method |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=item * load() - as class method |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=item * loadset() - as class method |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=item * delete() - as instance method - or class method |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=item * exists() - as class method |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=item * reload() - StoredHash::ISA custom instance method to reload instance from db |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=back |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=cut |
37
|
|
|
|
|
|
|
# Stripped |
38
|
|
|
|
|
|
|
# insert (or class method) |
39
|
|
|
|
|
|
|
# update (or class method) |
40
|
|
|
|
|
|
|
# load (or instance method to "reload") |
41
|
|
|
|
|
|
|
# exists (or instance method) |
42
|
|
|
|
|
|
|
=pod |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
The ways of using methods (class vs. instance) above. |
45
|
|
|
|
|
|
|
Perl generally allows class methods (i.e. non-instance methods) to be called with two syntaxes |
46
|
|
|
|
|
|
|
(with major underlying differences): |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
ThePack::a_method() |
49
|
|
|
|
|
|
|
# And |
50
|
|
|
|
|
|
|
ThePack-> a_method() |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
All StoredHash::ISA class methods (as listed above) need to be called using ThePack-> a_method() (this is related to |
53
|
|
|
|
|
|
|
giving framework a hint about objects type). |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head1 SYNOPSIS |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Package wanting to be-a persister: |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
{ |
60
|
|
|
|
|
|
|
package Justanother::Object; |
61
|
|
|
|
|
|
|
# Inherit persister methods |
62
|
|
|
|
|
|
|
# our @ISA = ('StoredHash::ISA'); # Or more by more modern style ... |
63
|
|
|
|
|
|
|
use base ('StoredHash::ISA'); |
64
|
|
|
|
|
|
|
# Must declare |
65
|
|
|
|
|
|
|
our $shp = {'table' => 'another', 'pkey' => ['id'], 'autoid' => 1,} |
66
|
|
|
|
|
|
|
# Custom functionality ... methods as usual |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
using the class ... |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
my $o = Justanother::Object->new('prop' => 'The Value',); |
73
|
|
|
|
|
|
|
my $id = $o->insert(); |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Load object |
76
|
|
|
|
|
|
|
my $o = Justanother::Object->load([46]); |
77
|
|
|
|
|
|
|
# Load related children (blessed automatically) |
78
|
|
|
|
|
|
|
my $o->{'items'} = Justanother::Object::Children->loadset({'parent' => 46}); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Setting up Your inheriting class-package for persistence |
81
|
|
|
|
|
|
|
{ |
82
|
|
|
|
|
|
|
package Justanother::Object; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
our $shp = {'table' => 'anotherobj', ...}; |
85
|
|
|
|
|
|
|
use base 'StoredHash::ISA'; # Same as our @ISA = ('StoredHash::ISA'); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=cut |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# package Justanother::Object; |
91
|
|
|
|
|
|
|
# At import Tweak (bless) our $shp of requesting class |
92
|
|
|
|
|
|
|
# use Storedhash; |
93
|
|
|
|
|
|
|
# use Storedhash::ISA; |
94
|
|
|
|
|
|
|
# our @ISA = ('StoredHash::ISA'); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# This only puts one more burden on the application - hashes must always be blessed hashes - |
97
|
|
|
|
|
|
|
# not plain |
98
|
|
|
|
|
|
|
# unblessed ones. On the other hasn when they are retrieved from DB with autoconnected methods: |
99
|
|
|
|
|
|
|
# - |
100
|
|
|
|
|
|
|
# - |
101
|
|
|
|
|
|
|
# They will always be automatically blessed. |
102
|
|
|
|
|
|
|
# The scenario that you have to watch for is when getting a raw hash from Desktop app or Web form in |
103
|
|
|
|
|
|
|
# unblessed, form - it must be blessed to class before calling methods via it. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# DEV: |
107
|
|
|
|
|
|
|
# Whatever way the persistence is implemented The StoredHash or StoredHash::ISA Must somehow get to |
108
|
|
|
|
|
|
|
# know what persister to use |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# Using original StoredHash methods (Benefit-no new classes): |
111
|
|
|
|
|
|
|
# sub insert { |
112
|
|
|
|
|
|
|
# my ($p, $h) = @_; |
113
|
|
|
|
|
|
|
# if (($c = ref($p)) ne 'StoredHash') { |
114
|
|
|
|
|
|
|
# $h = $p; # Make Calling abject THE hash |
115
|
|
|
|
|
|
|
# # Lookup persister from "Class Table" |
116
|
|
|
|
|
|
|
# $p = $StoredHash::clt->{$c}; |
117
|
|
|
|
|
|
|
# # OR Class itself !!! |
118
|
|
|
|
|
|
|
# $p = ${"$c"}::shp; |
119
|
|
|
|
|
|
|
#} |
120
|
|
|
|
|
|
|
# ... |
121
|
|
|
|
|
|
|
#} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Implement _relevant_methods of |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#our @ISA |
126
|
|
|
|
|
|
|
package StoredHash::ISA; |
127
|
2
|
|
|
2
|
|
7213
|
use StoredHash; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
56
|
|
128
|
|
|
|
|
|
|
# blessed gets the ... |
129
|
2
|
|
|
2
|
|
8
|
use Scalar::Util('reftype','blessed'); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
98
|
|
130
|
2
|
|
|
2
|
|
7
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
54
|
|
131
|
2
|
|
|
2
|
|
8
|
use warnings; |
|
2
|
|
|
|
|
13
|
|
|
2
|
|
|
|
|
55
|
|
132
|
|
|
|
|
|
|
|
133
|
2
|
|
|
2
|
|
6
|
use Data::Dumper; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
285
|
|
134
|
|
|
|
|
|
|
our $debug = 0; |
135
|
|
|
|
|
|
|
our $VERSION = '0.30'; |
136
|
|
|
|
|
|
|
$Data::Dumper::Indent = 1; |
137
|
|
|
|
|
|
|
$Data::Dumper::Terse = 1; |
138
|
|
|
|
|
|
|
# Cache Mapping from classes to persister (to avoid lookup to the class itself) |
139
|
|
|
|
|
|
|
# The internal import-time boot() -method registers classes in here. |
140
|
|
|
|
|
|
|
my $clt = {}; |
141
|
|
|
|
|
|
|
our @methods = ('insert','update','delete','load','loadset','exists',); |
142
|
|
|
|
|
|
|
# Safe methods (no 'delete' and 'exists') |
143
|
|
|
|
|
|
|
our @safemethods = ('insert','update','load','loadset',); |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# Perl standard import method for StoredHash::ISA. |
146
|
|
|
|
|
|
|
# This is auto-triggered when class loads StoredHash::ISA by "use StoredHash::ISA;". |
147
|
|
|
|
|
|
|
# This calls boot() to carry out some of the setup. |
148
|
|
|
|
|
|
|
sub import { |
149
|
2
|
|
|
2
|
|
12
|
my ($cl) = @_; |
150
|
2
|
|
|
|
|
12
|
my @ci = caller(0); |
151
|
2
|
50
|
|
|
|
11
|
if ($debug) {print(STDERR Dumper(\@ci));} |
|
0
|
|
|
|
|
0
|
|
152
|
2
|
|
|
2
|
|
9
|
no strict 'refs'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
1335
|
|
153
|
|
|
|
|
|
|
# Grab $shp from callers package |
154
|
|
|
|
|
|
|
# TODO: Convert to symbol table lookup |
155
|
2
|
|
|
|
|
4
|
my $ssym = "$ci[0]\:\:shp"; |
156
|
2
|
|
|
|
|
2
|
my $shp = ${$ssym}; # eval('$'.$ci[0].'::shp'); # |
|
2
|
|
|
|
|
6
|
|
157
|
|
|
|
|
|
|
#DEBUG:print("#$ssym#\n");print(Dumper($shp)); |
158
|
|
|
|
|
|
|
#if (!$shp) {$shp = '';} # undef does not work for strict/warnings |
159
|
|
|
|
|
|
|
# TODO: Use reftype() |
160
|
2
|
100
|
|
|
|
7
|
if (!$shp) {die("No persister info for package '$ci[0]'");} |
|
1
|
|
|
|
|
14
|
|
161
|
1
|
50
|
|
|
|
6
|
if (reftype($shp) ne 'HASH') {die("Persister info for package '$ci[0]' NOT in a HASH ($shp)");} |
|
0
|
|
|
|
|
0
|
|
162
|
|
|
|
|
|
|
#StoredHash::validate($shp); # Throws errors |
163
|
1
|
|
|
|
|
2
|
boot($shp, $ci[0]); # 'class' => |
164
|
1
|
50
|
|
|
|
2
|
if ($debug) {print(Dumper($shp));} |
|
0
|
|
|
|
|
0
|
|
165
|
1
|
50
|
|
|
|
24
|
if ($debug) {print("CLT ".Dumper($clt));} |
|
0
|
|
|
|
|
0
|
|
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
#=head2 boot($shp, $class) |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# Bootstrap StoredHash configuration embedded into the class loading the StoredHash::ISA. |
171
|
|
|
|
|
|
|
# |
172
|
|
|
|
|
|
|
#=item * Make sure the StoredHash config-declaration (with 'table', 'pkey' ...) is blessed to StoredHash |
173
|
|
|
|
|
|
|
#=item * Attach / import methods to original class |
174
|
|
|
|
|
|
|
#=item * Register class to class-to-persister mapping table maintained here. |
175
|
|
|
|
|
|
|
#=cut |
176
|
|
|
|
|
|
|
sub boot { |
177
|
1
|
|
|
1
|
0
|
1
|
my ($shp, $c) = @_; # %c |
178
|
1
|
50
|
|
|
|
3
|
if (!blessed($shp)) {bless($shp, 'StoredHash');} |
|
1
|
|
|
|
|
2
|
|
179
|
1
|
|
|
|
|
5
|
$shp->{'class'} = $c; # Force class = $class |
180
|
|
|
|
|
|
|
# Methods OR safemethods |
181
|
|
|
|
|
|
|
# NOTE: This should be optional as @ISA method dispatching takes care of this. |
182
|
1
|
|
|
|
|
2
|
map({eval("*${c}::$_ = \\&StoredHash::ISA::$_");} @methods); # $c{'class'} |
|
6
|
|
|
|
|
238
|
|
183
|
1
|
|
|
|
|
3
|
$clt->{$c} = $shp; # $c{'class'} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head1 METHODS |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Implementations as distinct instance methods |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head2 my ($id) = $e->insert(%opts) |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Insert an instance of a class to database. |
194
|
|
|
|
|
|
|
Return id(s) as a array / list (real array that is). |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
197
|
|
|
|
|
|
|
sub insert { |
198
|
0
|
|
|
0
|
1
|
|
my ($h, %c) = @_; |
199
|
0
|
|
|
|
|
|
my $c; |
200
|
|
|
|
|
|
|
# Called as class method. Allow this somewhat ugly overloading ? |
201
|
0
|
0
|
|
|
|
|
if (reftype($h) ne 'HASH') { |
|
0
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
|
($c, $h, %c) = @_; |
203
|
|
|
|
|
|
|
#die("StoredHash::ISA: Only works with hash Objects"); |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
else {$c = blessed($h);} |
206
|
0
|
|
|
|
|
|
my $p = $clt->{$c}; |
207
|
|
|
|
|
|
|
# Ensure this is a StoredHash $p->isa('StoredHash'); |
208
|
0
|
0
|
|
|
|
|
if (!$p) {die("Persister not resolved for '$c'");} |
|
0
|
|
|
|
|
|
|
209
|
0
|
|
|
|
|
|
return $p->insert($h, %c); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
# OLD: |
212
|
|
|
|
|
|
|
# Probe caller() to to insert / update |
213
|
|
|
|
|
|
|
# Swap the roles of $p and $h |
214
|
|
|
|
|
|
|
# TODO: Allow Class / Inst |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head2 $entry->update($ids) |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Update entry in database. Allows using explicit 'attrs' to minimize attributes to be updated. |
219
|
|
|
|
|
|
|
Return true value on success. Throw exception on failure. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=cut |
222
|
|
|
|
|
|
|
sub update { |
223
|
0
|
|
|
0
|
1
|
|
my ($h, $ids, %c) = @_; |
224
|
0
|
0
|
|
|
|
|
if (reftype($h) ne 'HASH') {die("StoredHash::ISA: Only works with hash Objects");} |
|
0
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# Allow entry to contain IDs ? See reload() for example. |
226
|
0
|
0
|
|
|
|
|
if (!$ids) {} |
227
|
0
|
0
|
|
|
|
|
if (reftype($ids) ne 'ARRAY') {die("ID not in an ARRAY");} |
|
0
|
|
|
|
|
|
|
228
|
0
|
|
|
|
|
|
my $c = blessed($h); |
229
|
0
|
|
|
|
|
|
my $p = $clt->{$c}; |
230
|
0
|
|
|
|
|
|
$p->update($h, $ids, %c); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head2 $entry->delete($ids) |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Delete an instance of an entry from DB. |
236
|
|
|
|
|
|
|
Note that as the persisted version ceases to exist, probably the runtime instance should as well. |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
$entry->delete($ids) |
239
|
|
|
|
|
|
|
undef($entry); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |
242
|
|
|
|
|
|
|
# TODO: Allow to work as Class or instance method: MyType->delete(); |
243
|
|
|
|
|
|
|
# TODO: |
244
|
|
|
|
|
|
|
sub delete { |
245
|
0
|
|
|
0
|
1
|
|
my ($h, $ids, %c) = @_; |
246
|
0
|
|
|
|
|
|
my $c; |
247
|
0
|
|
|
|
|
|
my $isinst = reftype($h) eq 'HASH'; |
248
|
|
|
|
|
|
|
# Support instance BUT w/o $ids: $e->delete() |
249
|
|
|
|
|
|
|
#TODO:if ($isinst && !$ids) {$ids = embedded_ids($p, $e);} |
250
|
|
|
|
|
|
|
# Support Class method call: MyType->delete($ids). Re-shuffle stack params slightly. |
251
|
|
|
|
|
|
|
# param $_[0] (class) must be found in the class table. |
252
|
|
|
|
|
|
|
#TODO:if (!$isinst && $clt->{$_[0]}) {$c = $h;goto ANYDELETE;} |
253
|
0
|
0
|
|
|
|
|
if (!$isinst) {die("No (hash based) instance (and not a class call)");} |
|
0
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
$c = blessed($h); # Declared above to allow stack |
256
|
0
|
|
|
|
|
|
ANYDELETE: |
257
|
|
|
|
|
|
|
# Do this validation late (mainly for case Class call) |
258
|
0
|
0
|
|
|
|
|
if (reftype($ids) ne 'ARRAY') {die("ID(s) not in an ARRAY");} |
259
|
0
|
|
|
|
|
|
my $p = $clt->{$c}; |
260
|
|
|
|
|
|
|
##TODO: if (!$ids) {$ids = embedded_ids($p, $e);} |
261
|
0
|
|
|
|
|
|
$p->delete($h, $ids, %c); |
262
|
|
|
|
|
|
|
# Ok as Enforced ? |
263
|
0
|
0
|
|
|
|
|
if ($isinst) {$_[0] = undef;} |
|
0
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=head2 $e = MyType->load($ids) |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
Class Method to load an entry of particular type from DB. |
269
|
|
|
|
|
|
|
Return (blessed) entry. |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=cut |
272
|
|
|
|
|
|
|
# TODO: Consider the usage instance method to "reload") |
273
|
|
|
|
|
|
|
sub load { |
274
|
0
|
|
|
0
|
1
|
|
my ($c, $ids, %c) = @_; |
275
|
|
|
|
|
|
|
#if (reftype($c) eq 'HASH') {} |
276
|
0
|
|
|
|
|
|
my $p = $clt->{$c}; |
277
|
0
|
|
|
|
|
|
my $e = $p->load($ids, %c); |
278
|
|
|
|
|
|
|
# Is this redundant - entry already blessed ? |
279
|
0
|
|
|
|
|
|
return bless($e, $c); |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
=head2 $e->reload($ids) |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
Reload entry instance from database. |
284
|
|
|
|
|
|
|
$ids is optional as long as entry contains the id attribute values. |
285
|
|
|
|
|
|
|
Return (blessed) entry. |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=cut |
288
|
|
|
|
|
|
|
# TODO: Define the behaviour for setting $_[0] in callstack |
289
|
|
|
|
|
|
|
sub reload { |
290
|
0
|
|
|
0
|
1
|
|
my ($e, $ids, %c) = @_; |
291
|
0
|
|
|
|
|
|
my $c = blessed($e); |
292
|
0
|
0
|
|
|
|
|
if (!$c) {die("Not a blessed object");} |
|
0
|
|
|
|
|
|
|
293
|
0
|
|
|
|
|
|
my $p = $clt->{$c}; |
294
|
|
|
|
|
|
|
# No explicit ID, must be in the entry. Discover them. |
295
|
0
|
0
|
|
|
|
|
if (!$ids) { |
296
|
0
|
|
|
|
|
|
my @pkv = $p->pkeyvals($e); |
297
|
0
|
|
|
|
|
|
my @pka = $p->pkeys(); |
298
|
0
|
0
|
|
|
|
|
if (@pkv ne @pka) {die("ID attrs / vals - not matching");} |
|
0
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
$ids = \@pkv; # Use "discovered" IDs |
300
|
|
|
|
|
|
|
#TODO: $ids = embedded_ids($p, $e); |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
# This would not overwrite callers instance (assigning to $_[0] will) |
303
|
0
|
|
|
|
|
|
$e = $p->load($ids, %c); |
304
|
0
|
|
|
|
|
|
bless($e, $c); |
305
|
0
|
|
|
|
|
|
$_[0] = $e; # Optional "replace in stack" ? |
306
|
0
|
|
|
|
|
|
return($e); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head2 MyType->loadset($filter, $sortattrs, %opts) |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
Class method to load a set of entries for a class from the database. |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=cut |
314
|
|
|
|
|
|
|
sub loadset { |
315
|
0
|
|
|
0
|
1
|
|
my ($c, $wf, $o) = @_; |
316
|
0
|
|
|
|
|
|
my $p = $clt->{$c}; |
317
|
0
|
0
|
|
|
|
|
if (!$p) {die("No persister for class '$c'");} |
|
0
|
|
|
|
|
|
|
318
|
0
|
|
|
|
|
|
my $arr = $p->loadset($wf, $o); |
319
|
|
|
|
|
|
|
# Test autobless config (for class) |
320
|
0
|
|
|
|
|
|
my $abv = "$c\:\:noautobless"; |
321
|
2
|
|
|
2
|
|
28
|
no strict ('refs'); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
346
|
|
322
|
|
|
|
|
|
|
# no auto bless - return unblessed |
323
|
0
|
0
|
|
|
|
|
if (${$abv}) {return($arr);} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
return [map({ bless($_, $c); } @$arr)]; |
|
0
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=head2 MyType->exists($ids) |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Class method to test if an instance exists in database. |
330
|
|
|
|
|
|
|
Return true for "does exist", false for "not". |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=cut |
333
|
|
|
|
|
|
|
sub exists { |
334
|
0
|
|
|
0
|
1
|
|
my ($c, $ids, %c) = @_; |
335
|
0
|
|
|
|
|
|
my $p = $clt->{$c}; |
336
|
0
|
|
|
|
|
|
$p->exists($ids, %c); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
#=head2 $ids = embedded_ids($shp, $e) |
340
|
|
|
|
|
|
|
#Try to discover (DB) id(s) for methods that allow leaving out $ids from parameters. |
341
|
|
|
|
|
|
|
#The discovery must be prefect to be valid. |
342
|
|
|
|
|
|
|
#Return $ids (as arrayref), throw exception on any failures. |
343
|
|
|
|
|
|
|
#=cut |
344
|
|
|
|
|
|
|
sub embedded_ids { |
345
|
0
|
|
|
0
|
0
|
|
my ($p, $e) = @_; |
346
|
0
|
|
|
|
|
|
my @pkv = $p->pkeyvals($e); |
347
|
0
|
|
|
|
|
|
my @pka = $p->pkeys(); |
348
|
0
|
0
|
|
|
|
|
if (grep({!$_;} @pkv)) {die("ID:s cannot be empty or have a non-true value.");} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
349
|
0
|
0
|
|
|
|
|
if (@pkv ne @pka) {die("ID attrs / vals - not matching");} |
|
0
|
|
|
|
|
|
|
350
|
0
|
|
|
|
|
|
return \@pkv; # Use "discovered" IDs |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
1; |