| 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; |