line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package UR::Object::Type::AccessorWriter; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package UR::Object::Type; |
5
|
|
|
|
|
|
|
|
6
|
266
|
|
|
4388670
|
|
1079
|
use strict; |
|
266
|
|
|
|
|
353
|
|
|
266
|
|
|
|
|
6868
|
|
7
|
266
|
|
|
1248061
|
|
935
|
use warnings; |
|
266
|
|
|
|
|
348
|
|
|
266
|
|
|
|
|
9763
|
|
8
|
|
|
|
|
|
|
require UR; |
9
|
|
|
|
|
|
|
our $VERSION = "0.46"; # UR $VERSION; |
10
|
|
|
|
|
|
|
#use warnings FATAL => 'all'; |
11
|
|
|
|
|
|
|
|
12
|
266
|
|
|
745668
|
|
988
|
use Carp (); |
|
266
|
|
|
|
|
356
|
|
|
266
|
|
|
|
|
2900
|
|
13
|
266
|
|
|
25406
|
|
849
|
use Sub::Name (); |
|
266
|
|
|
|
|
334
|
|
|
266
|
|
|
|
|
3175
|
|
14
|
266
|
|
|
40724
|
|
868
|
use Sub::Install (); |
|
266
|
|
|
|
|
315
|
|
|
266
|
|
|
|
|
4156
|
|
15
|
266
|
|
|
40724
|
|
937
|
use List::Util; |
|
266
|
|
|
|
|
334
|
|
|
266
|
|
|
|
|
35995
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub mk_rw_accessor { |
18
|
59960
|
|
|
59960
|
0
|
67909
|
my ($self, $class_name, $accessor_name, $column_name, $property_name, $is_transient) = @_; |
19
|
59960
|
|
33
|
|
|
87355
|
$property_name ||= $accessor_name; |
20
|
|
|
|
|
|
|
|
21
|
59960
|
|
|
|
|
92714
|
my $full_name = join( '::', $class_name, $accessor_name ); |
22
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_name => sub { |
23
|
5856393
|
100
|
|
5856393
|
|
7622018
|
if (@_ > 1) { |
|
|
|
|
5893275
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5910470
|
|
|
|
|
|
|
|
165489
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
10061374
|
|
|
|
|
|
|
|
14226027
|
|
|
|
|
|
|
|
14772551
|
|
|
|
|
|
|
|
10021046
|
|
|
|
|
|
|
|
8494795
|
|
|
|
|
|
|
|
14185699
|
|
|
|
|
|
|
|
5947957
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
6091238
|
|
|
|
|
|
|
|
6095564
|
|
|
|
|
|
|
|
5908596
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
6079359
|
|
|
|
|
|
|
|
5896721
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
10659142
|
|
|
|
|
|
|
|
10862042
|
|
|
|
|
|
|
|
6357972
|
|
|
|
|
|
|
|
5896721
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
11081715
|
|
|
|
|
|
|
|
6368675
|
|
|
|
|
|
|
|
5937049
|
|
|
|
|
|
|
|
11348480
|
|
|
|
|
|
|
|
1571344
|
|
|
|
|
|
|
|
5987817
|
|
|
|
|
|
|
|
5896721
|
|
|
|
|
|
|
|
926480
|
|
|
|
|
|
|
|
261430
|
|
|
|
|
|
|
|
5917080
|
|
|
|
|
|
|
|
5917080
|
|
|
|
|
|
|
|
5876752
|
|
|
|
|
|
|
|
11288183
|
|
|
|
|
|
|
|
5935394
|
|
|
|
|
|
|
|
6029844
|
|
|
|
|
|
|
|
11288183
|
|
|
|
|
|
|
|
7542986
|
|
|
|
|
|
|
|
10289745
|
|
|
|
|
|
|
|
663562
|
|
|
|
|
|
|
|
6116198
|
|
|
|
|
|
|
|
6015123
|
|
|
|
|
|
|
|
5948935
|
|
|
|
|
|
|
|
15542550
|
|
|
|
|
|
|
|
11100119
|
|
|
|
|
|
|
|
6358337
|
|
|
|
|
|
|
|
5911978
|
|
|
|
|
|
|
|
11031459
|
|
|
|
|
|
|
|
9182768
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
5868267
|
|
|
|
|
|
|
|
6279018
|
|
|
|
|
|
|
|
5914959
|
|
|
|
|
|
|
|
5896721
|
|
|
|
|
|
|
|
11308152
|
|
|
|
|
|
|
|
6123103
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
11198943
|
|
|
|
|
|
|
|
6174697
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
348269
|
|
|
|
|
|
|
|
5947489
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5867439
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
6120127
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
5934119
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5907243
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
12407087
|
|
|
|
|
|
|
|
16151904
|
|
|
|
|
|
|
|
11295608
|
|
|
|
|
|
|
|
16615224
|
|
|
|
|
|
|
|
4157166
|
|
|
|
|
|
|
|
6302779
|
|
|
|
|
|
|
|
11534534
|
|
|
|
|
|
|
|
10061374
|
|
|
|
|
|
|
|
5906943
|
|
|
|
|
|
|
|
6050749
|
|
|
|
|
|
|
|
7198374
|
|
|
|
|
|
|
|
6336188
|
|
|
|
|
|
|
|
6192944
|
|
|
|
|
|
|
|
5935910
|
|
|
|
|
|
|
|
5917672
|
|
|
|
|
|
|
|
4653639
|
|
|
|
|
|
|
|
10160943
|
|
|
|
|
|
|
|
8285359
|
|
|
|
|
|
|
|
7624364
|
|
|
|
|
|
|
|
7493449
|
|
|
|
|
|
|
|
7156277
|
|
|
|
|
|
|
|
7217981
|
|
|
|
|
|
|
|
10357070
|
|
|
|
|
|
|
|
6294737
|
|
|
|
|
|
|
|
10419637
|
|
|
|
|
|
|
|
10684993
|
|
|
|
|
|
|
|
16223375
|
|
|
|
|
|
|
|
7791629
|
|
|
|
|
|
|
|
11560621
|
|
|
|
|
|
|
|
6117025
|
|
|
|
|
|
|
|
6052739
|
|
|
|
|
|
|
|
10207608
|
|
|
|
|
|
|
|
10140023
|
|
|
|
|
|
|
|
15497076
|
|
|
|
|
|
|
|
14456373
|
|
|
|
|
|
|
|
15432477
|
|
|
|
|
|
|
|
15319824
|
|
|
|
|
|
|
|
11515023
|
|
|
|
|
|
|
|
6287594
|
|
|
|
|
|
|
|
6527077
|
|
|
|
|
|
|
|
6049751
|
|
|
|
|
|
|
|
10061374
|
|
|
|
|
|
|
|
6004832
|
|
|
|
|
|
|
|
5938644
|
|
|
|
|
|
|
|
11308152
|
|
|
|
|
|
|
|
10021046
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
10038690
|
|
|
|
|
|
|
|
5874037
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
5946692
|
|
|
|
|
|
|
|
5896721
|
|
|
|
|
|
|
|
6063754
|
|
|
|
|
|
|
|
5896721
|
|
|
|
|
|
|
|
5655658
|
|
|
|
|
|
|
|
7926063
|
|
|
|
|
|
|
|
6175959
|
|
|
|
|
|
|
|
6133850
|
|
|
|
|
|
|
|
11467455
|
|
|
|
|
|
|
|
5954132
|
|
|
|
|
|
|
|
11323409
|
|
|
|
|
|
|
|
5872346
|
|
|
|
|
|
|
|
11267824
|
|
|
|
|
|
|
|
7230330
|
|
|
|
|
|
|
|
6266633
|
|
|
|
|
|
|
|
5856393
|
|
|
|
|
|
|
|
19130302
|
|
|
|
|
|
|
|
5799211
|
|
|
|
|
|
|
|
570449
|
|
|
|
|
|
|
|
144948
|
|
|
|
|
|
|
|
44871
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
|
10450
|
|
|
|
|
|
|
|
10450
|
|
|
|
24
|
11059
|
|
|
|
|
14250
|
my $old = $_[0]->{ $property_name }; |
25
|
11059
|
|
|
|
|
10302
|
my $new = $_[1]; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# The accessors may compare undef and an empty |
28
|
|
|
|
|
|
|
# string. For speed, we turn warnings off rather |
29
|
|
|
|
|
|
|
# than add extra code to make the warning disappear. |
30
|
11059
|
|
|
|
|
8980
|
local $@; |
31
|
266
|
|
|
25406
|
|
1114
|
my $different = eval { no warnings; $old ne $new }; |
|
266
|
|
|
|
|
359
|
|
|
266
|
|
|
|
|
64158
|
|
|
11059
|
|
|
|
|
11584
|
|
|
11059
|
|
|
|
|
19666
|
|
32
|
11059
|
100
|
66
|
|
|
26653
|
if ($different or $@ =~ m/has no overloaded magic/) |
33
|
|
|
|
|
|
|
{ |
34
|
9616
|
|
|
|
|
12557
|
$_[0]->{ $property_name } = $new; |
35
|
9616
|
100
|
|
|
|
19391
|
$_[0]->__signal_change__( $property_name, $old, $new ) unless $is_transient; # FIXME is $is_transient right here? Maybe is_volatile instead (if at all)? |
36
|
|
|
|
|
|
|
} |
37
|
11059
|
|
|
|
|
18498
|
return $new; |
38
|
|
|
|
|
|
|
} |
39
|
5845334
|
|
|
|
|
11041980
|
$_[0]->{ $property_name } |
40
|
59960
|
|
|
|
|
338380
|
}; |
41
|
|
|
|
|
|
|
|
42
|
59960
|
100
|
|
|
|
95224
|
if (_class_is_singleton($class_name)) { |
43
|
2348
|
|
|
|
|
2340
|
my $basic_accessor = $accessor; |
44
|
|
|
|
|
|
|
$accessor = sub { |
45
|
19057
|
|
|
4194245
|
|
319477
|
shift->_singleton_object->$basic_accessor(@_); |
46
|
2348
|
|
|
|
|
6561
|
}; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Sub::Install::reinstall_sub({ |
50
|
59960
|
|
|
|
|
178825
|
into => $class_name, |
51
|
|
|
|
|
|
|
as => $accessor_name, |
52
|
|
|
|
|
|
|
code => $accessor, |
53
|
|
|
|
|
|
|
}); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub mk_ro_accessor { |
58
|
7906
|
|
|
7906
|
0
|
12325
|
my ($self, $class_name, $accessor_name, $column_name, $property_name) = @_; |
59
|
7906
|
|
66
|
|
|
14411
|
$property_name ||= $accessor_name; |
60
|
|
|
|
|
|
|
|
61
|
7906
|
|
|
|
|
15799
|
my $full_name = join( '::', $class_name, $accessor_name ); |
62
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_name => sub { |
63
|
4448369
|
100
|
|
4463042
|
|
5889855
|
if (@_ > 1) { |
|
|
|
|
4463042
|
|
|
|
|
|
|
|
5662324
|
|
|
|
|
|
|
|
5249034
|
|
|
|
|
|
|
|
4543647
|
|
|
|
|
|
|
|
4448369
|
|
|
|
|
|
|
|
4448369
|
|
|
|
|
|
|
|
8579932
|
|
|
|
|
|
|
|
9132651
|
|
|
|
|
|
|
|
10640180
|
|
|
|
|
|
|
|
7597649
|
|
|
|
|
|
|
|
5852770
|
|
|
|
|
|
|
|
9605729
|
|
|
|
|
|
|
|
8846873
|
|
|
|
|
|
|
|
10331585
|
|
|
|
|
|
|
|
7163769
|
|
|
|
|
|
|
|
6147977
|
|
|
|
|
|
|
|
4950946
|
|
|
|
|
|
|
|
8756277
|
|
|
|
|
|
|
|
5240257
|
|
|
|
|
|
|
|
7762353
|
|
|
|
|
|
|
|
7187811
|
|
|
|
64
|
10
|
|
|
|
|
18
|
my $old = $_[0]->{ $property_name}; |
65
|
10
|
|
|
|
|
14
|
my $new = $_[1]; |
66
|
|
|
|
|
|
|
|
67
|
10
|
|
|
|
|
11
|
my $different; |
68
|
10
|
|
|
|
|
12
|
my $exception = do { |
69
|
10
|
|
|
|
|
11
|
local $@; |
70
|
266
|
|
|
266
|
|
1229
|
$different = eval { no warnings; $old ne $new }; |
|
266
|
|
|
|
|
375
|
|
|
266
|
|
|
|
|
1189078
|
|
|
10
|
|
|
|
|
13
|
|
|
10
|
|
|
|
|
20
|
|
71
|
10
|
|
|
|
|
16
|
$@; |
72
|
|
|
|
|
|
|
}; |
73
|
10
|
100
|
66
|
|
|
55
|
if ($different or $exception =~ m/has no overloaded magic/) |
74
|
|
|
|
|
|
|
{ |
75
|
1
|
|
|
|
|
12
|
Carp::croak("Cannot change read-only property $accessor_name for class $class_name!" |
76
|
|
|
|
|
|
|
. " Failed to update " . $_[0]->__display_name__ . " property: $property_name from $old to $new"); |
77
|
|
|
|
|
|
|
} |
78
|
9
|
|
|
|
|
19
|
return $new; |
79
|
|
|
|
|
|
|
} |
80
|
4448359
|
|
|
|
|
7560695
|
return $_[0]->{ $property_name }; |
81
|
7906
|
|
|
|
|
51783
|
}; |
82
|
|
|
|
|
|
|
|
83
|
7906
|
100
|
|
|
|
14861
|
if (_class_is_singleton($class_name)) { |
84
|
1
|
|
|
|
|
2
|
my $basic_accessor = $accessor; |
85
|
|
|
|
|
|
|
$accessor = sub { |
86
|
3
|
|
|
1752301
|
|
279
|
shift->_singleton_object->$basic_accessor(@_); |
87
|
1
|
|
|
|
|
7
|
}; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Sub::Install::reinstall_sub({ |
91
|
7906
|
|
|
|
|
29000
|
into => $class_name, |
92
|
|
|
|
|
|
|
as => $accessor_name, |
93
|
|
|
|
|
|
|
code => $accessor, |
94
|
|
|
|
|
|
|
}); |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub _class_is_singleton { |
99
|
67866
|
|
|
910819
|
|
61226
|
my $class_name = shift; |
100
|
67866
|
|
|
|
|
51110
|
return grep { $_->isa('UR::Singleton') } @{ $class_name->__meta__->{is} }; |
|
69030
|
|
|
|
|
333818
|
|
|
67866
|
|
|
|
|
146700
|
|
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub mk_id_based_flex_accessor { |
104
|
0
|
|
|
831610
|
0
|
0
|
my ($self, $class_name, $accessor_name, $id_by, $r_class_name, $where, $id_class_by) = @_; |
105
|
|
|
|
|
|
|
|
106
|
0
|
0
|
|
|
|
0
|
unless (ref($id_by)) { |
107
|
0
|
|
|
|
|
0
|
$id_by = [ $id_by ]; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
0
|
my $id_resolver; |
111
|
|
|
|
|
|
|
my $id_decomposer; |
112
|
0
|
|
|
|
|
0
|
my @id; |
113
|
0
|
|
|
|
|
0
|
my $id; |
114
|
0
|
|
|
|
|
0
|
my $full_name = join( '::', $class_name, $accessor_name ); |
115
|
0
|
|
|
|
|
0
|
my $concrete_r_class_name = $r_class_name; |
116
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_name => sub { |
117
|
0
|
|
|
764673
|
|
0
|
my $self = shift; |
118
|
0
|
0
|
|
|
|
0
|
if (@_ == 1) { |
119
|
|
|
|
|
|
|
# This one is to support syntax like this |
120
|
|
|
|
|
|
|
# $cd->artist($different_artist); |
121
|
|
|
|
|
|
|
# to switch which artist object this cd points to |
122
|
0
|
|
|
|
|
0
|
my $object_value = shift; |
123
|
0
|
0
|
0
|
|
|
0
|
if ($id_class_by and not ref $object_value) { |
124
|
|
|
|
|
|
|
# when we have an id-class-by accessor and get a primitive, store it as a UR::Value |
125
|
0
|
|
|
|
|
0
|
$object_value = UR::Value->get($object_value); |
126
|
|
|
|
|
|
|
} |
127
|
0
|
0
|
|
|
|
0
|
if (defined $object_value) { |
128
|
0
|
0
|
0
|
|
|
0
|
if ($id_class_by) { |
|
|
0
|
|
|
|
|
|
129
|
0
|
0
|
|
|
|
0
|
$concrete_r_class_name = ($object_value->can('class') ? $object_value->class : ref($object_value)); |
130
|
0
|
|
|
|
|
0
|
$id_decomposer = undef; |
131
|
0
|
|
|
|
|
0
|
$id_resolver = undef; |
132
|
0
|
|
|
|
|
0
|
$self->$id_class_by($concrete_r_class_name); |
133
|
|
|
|
|
|
|
} elsif (! Scalar::Util::blessed($object_value) and ! $object_value->can('id')) { |
134
|
0
|
|
|
|
|
0
|
Carp::croak("Can't call method \"id\" without a package or object reference. Expected an object as parameter to '$accessor_name', not the value '$object_value'"); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
0
|
my $r_class_meta = do { |
138
|
0
|
|
|
|
|
0
|
local $@; |
139
|
0
|
|
|
|
|
0
|
eval { $concrete_r_class_name->__meta__ }; |
|
0
|
|
|
|
|
0
|
|
140
|
|
|
|
|
|
|
}; |
141
|
0
|
0
|
|
|
|
0
|
unless ($r_class_meta) { |
142
|
0
|
|
|
|
|
0
|
Carp::croak("Can't get metadata for class $concrete_r_class_name. Is it a UR class?"); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
0
|
|
0
|
|
|
0
|
$id_decomposer ||= $r_class_meta->get_composite_id_decomposer; |
146
|
0
|
|
|
|
|
0
|
@id = $id_decomposer->($object_value->id); |
147
|
0
|
0
|
|
|
|
0
|
if (@$id_by == 1) { |
148
|
0
|
|
|
|
|
0
|
my $id_property_name = $id_by->[0]; |
149
|
0
|
|
|
|
|
0
|
$self->$id_property_name($object_value->id); |
150
|
|
|
|
|
|
|
} else { |
151
|
0
|
|
|
|
|
0
|
@id = $id_decomposer->($object_value->id); |
152
|
0
|
|
|
|
|
0
|
Carp::croak("Cannot alter value for '$accessor_name' on $class_name: The passed-in object of type " |
153
|
|
|
|
|
|
|
. $object_value->class . " has " . scalar(@id) . " id properties, but the accessor '$accessor_name' has " |
154
|
|
|
|
|
|
|
. scalar(@$id_by) . " id_by properties"); |
155
|
0
|
|
|
|
|
0
|
for my $id_property_name (@$id_by) { |
156
|
0
|
|
|
|
|
0
|
$self->$id_property_name(shift @id); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
else { |
161
|
0
|
0
|
|
|
|
0
|
if ($id_class_by) { |
162
|
0
|
|
|
|
|
0
|
$self->$id_class_by(undef); |
163
|
|
|
|
|
|
|
} |
164
|
0
|
|
|
|
|
0
|
for my $id_property_name (@$id_by) { |
165
|
0
|
|
|
|
|
0
|
$self->$id_property_name(undef); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
} |
168
|
0
|
|
|
|
|
0
|
return $object_value; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
else { |
171
|
0
|
0
|
|
|
|
0
|
if ($id_class_by) { |
172
|
0
|
|
|
|
|
0
|
$concrete_r_class_name = $self->$id_class_by; |
173
|
0
|
|
|
|
|
0
|
$id_decomposer = undef; |
174
|
0
|
|
|
|
|
0
|
$id_resolver = undef; |
175
|
0
|
0
|
|
|
|
0
|
return unless $concrete_r_class_name; |
176
|
|
|
|
|
|
|
} |
177
|
0
|
0
|
|
|
|
0
|
unless ($id_resolver) { |
178
|
0
|
|
|
|
|
0
|
my $concrete_r_class_meta = UR::Object::Type->get($concrete_r_class_name); |
179
|
0
|
0
|
|
|
|
0
|
unless ($concrete_r_class_meta) { |
180
|
0
|
|
|
|
|
0
|
Carp::croak("Can't resolve value for '$accessor_name' on class $class_name id '".$self->id |
181
|
|
|
|
|
|
|
. "': No class metadata for value '$concrete_r_class_name' referenced as property '$id_class_by'"); |
182
|
|
|
|
|
|
|
} |
183
|
0
|
|
|
|
|
0
|
$id_resolver = $concrete_r_class_meta->get_composite_id_resolver; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# eliminate the old map{} because of side effects with $_ |
187
|
|
|
|
|
|
|
# when the id_by property happens to be calculated |
188
|
|
|
|
|
|
|
#@id = map { $self->$_ } @$id_by; |
189
|
0
|
|
|
|
|
0
|
@id=(); |
190
|
0
|
|
|
|
|
0
|
for my $property_name (@$id_by) { # no implicit topic |
191
|
0
|
|
|
|
|
0
|
my $value = $self->$property_name; # scalar context |
192
|
0
|
|
|
|
|
0
|
push @id, $value; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
0
|
$id = $id_resolver->(@id); |
196
|
0
|
0
|
|
|
|
0
|
return if not defined $id; |
197
|
0
|
0
|
|
|
|
0
|
if ($concrete_r_class_name eq 'UR::Object') { |
198
|
0
|
|
|
|
|
0
|
Carp::carp("Querying by using UR::Object class is deprecated."); |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
0
|
0
|
|
|
|
0
|
if ($concrete_r_class_name->isa("UR::Value")) { |
202
|
0
|
|
|
|
|
0
|
return $id; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
else { |
205
|
0
|
0
|
0
|
|
|
0
|
if (@_ || $where) { |
206
|
|
|
|
|
|
|
# There were additional params passed in |
207
|
0
|
|
|
|
|
0
|
return $concrete_r_class_name->get(id => $id, @_, @$where); |
208
|
|
|
|
|
|
|
} else { |
209
|
0
|
|
|
|
|
0
|
return $concrete_r_class_name->get($id); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
} |
213
|
0
|
|
|
|
|
0
|
}; |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
0
|
Sub::Install::reinstall_sub({ |
216
|
|
|
|
|
|
|
into => $class_name, |
217
|
|
|
|
|
|
|
as => $accessor_name, |
218
|
|
|
|
|
|
|
code => $accessor, |
219
|
|
|
|
|
|
|
}); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub mk_id_based_object_accessor { |
223
|
4684
|
|
|
434758
|
0
|
12824
|
my ($self, $class_name, $accessor_name, $id_by, $r_class_name, $where, $id_class_by) = @_; |
224
|
|
|
|
|
|
|
|
225
|
4684
|
50
|
|
|
|
11092
|
unless (ref($id_by)) { |
226
|
0
|
|
|
|
|
0
|
$id_by = [ $id_by ]; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
4684
|
|
|
|
|
5158
|
my $id_resolver; |
230
|
|
|
|
|
|
|
my $id_decomposer; |
231
|
0
|
|
|
|
|
0
|
my @id; |
232
|
0
|
|
|
|
|
0
|
my $id; |
233
|
4684
|
|
|
|
|
10304
|
my $full_name = join( '::', $class_name, $accessor_name ); |
234
|
4684
|
|
|
|
|
5547
|
my $concrete_r_class_name = $r_class_name; |
235
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_name => sub { |
236
|
516548
|
|
|
516548
|
|
432346
|
my $self = shift; |
|
|
|
|
516548
|
|
|
|
|
|
|
|
516548
|
|
|
|
|
|
|
|
516548
|
|
|
|
|
|
|
|
516548
|
|
|
|
|
|
|
|
999695
|
|
|
|
|
|
|
|
1034971
|
|
|
|
|
|
|
|
1225331
|
|
|
|
|
|
|
|
777430
|
|
|
|
|
|
|
|
1188585
|
|
|
|
|
|
|
|
761757
|
|
|
|
|
|
|
|
1324494
|
|
|
|
|
|
|
|
619471
|
|
|
|
|
|
|
|
128256
|
|
|
|
237
|
516548
|
100
|
|
|
|
720376
|
if (@_ == 1) { |
238
|
|
|
|
|
|
|
# This one is to support syntax like this |
239
|
|
|
|
|
|
|
# $cd->artist($different_artist); |
240
|
|
|
|
|
|
|
# to switch which artist object this cd points to |
241
|
87
|
|
|
|
|
111
|
my $object_value = shift; |
242
|
87
|
100
|
|
|
|
190
|
if (defined $object_value) { |
243
|
86
|
100
|
66
|
|
|
448
|
if ($id_class_by) { |
|
|
100
|
|
|
|
|
|
244
|
36
|
50
|
|
|
|
127
|
$concrete_r_class_name = ($object_value->can('class') ? $object_value->class : ref($object_value)); |
245
|
36
|
|
|
|
|
56
|
$id_decomposer = undef; |
246
|
36
|
|
|
|
|
38
|
$id_resolver = undef; |
247
|
36
|
|
|
|
|
92
|
$self->$id_class_by($concrete_r_class_name); |
248
|
|
|
|
|
|
|
} elsif (! Scalar::Util::blessed($object_value) and ! $object_value->can('id')) { |
249
|
1
|
|
|
|
|
274
|
Carp::croak("Can't call method \"id\" without a package or object reference. Expected an object as parameter to '$accessor_name', not the value '$object_value'"); |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
85
|
|
|
|
|
109
|
my $r_class_meta = do { |
253
|
85
|
|
|
|
|
109
|
local $@; |
254
|
85
|
|
|
|
|
125
|
eval { $concrete_r_class_name->__meta__ }; |
|
85
|
|
|
|
|
316
|
|
255
|
|
|
|
|
|
|
}; |
256
|
85
|
50
|
|
|
|
211
|
unless ($r_class_meta) { |
257
|
0
|
|
|
|
|
0
|
Carp::croak("Can't get metadata for class $concrete_r_class_name. Is it a UR class?"); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
85
|
|
66
|
|
|
507
|
$id_decomposer ||= $r_class_meta->get_composite_id_decomposer; |
261
|
85
|
|
|
|
|
231
|
@id = $id_decomposer->($object_value->id); |
262
|
85
|
50
|
|
|
|
242
|
if (@$id_by == 1) { |
263
|
85
|
|
|
|
|
136
|
my $id_property_name = $id_by->[0]; |
264
|
85
|
|
|
|
|
202
|
$self->$id_property_name($object_value->id); |
265
|
|
|
|
|
|
|
} else { |
266
|
0
|
|
|
|
|
0
|
@id = $id_decomposer->($object_value->id); |
267
|
0
|
|
|
|
|
0
|
Carp::croak("Cannot alter value for '$accessor_name' on $class_name: The passed-in object of type " |
268
|
|
|
|
|
|
|
. $object_value->class . " has " . scalar(@id) . " id properties, but the accessor '$accessor_name' has " |
269
|
|
|
|
|
|
|
. scalar(@$id_by) . " id_by properties"); |
270
|
0
|
|
|
|
|
0
|
for my $id_property_name (@$id_by) { |
271
|
0
|
|
|
|
|
0
|
$self->$id_property_name(shift @id); |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
else { |
276
|
1
|
50
|
|
|
|
4
|
if ($id_class_by) { |
277
|
0
|
|
|
|
|
0
|
$self->$id_class_by(undef); |
278
|
|
|
|
|
|
|
} |
279
|
1
|
|
|
|
|
2
|
for my $id_property_name (@$id_by) { |
280
|
1
|
|
|
|
|
4
|
$self->$id_property_name(undef); |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
86
|
|
|
|
|
195
|
return $object_value; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
else { |
286
|
516461
|
100
|
|
|
|
726614
|
if ($id_class_by) { |
287
|
363
|
|
|
|
|
760
|
$concrete_r_class_name = $self->$id_class_by; |
288
|
363
|
|
|
|
|
394
|
$id_decomposer = undef; |
289
|
363
|
|
|
|
|
330
|
$id_resolver = undef; |
290
|
363
|
50
|
|
|
|
543
|
return unless $concrete_r_class_name; |
291
|
|
|
|
|
|
|
} |
292
|
516461
|
100
|
|
|
|
719569
|
unless ($id_resolver) { |
293
|
1147
|
|
|
|
|
3848
|
my $concrete_r_class_meta = UR::Object::Type->get($concrete_r_class_name); |
294
|
1147
|
100
|
|
|
|
2391
|
unless ($concrete_r_class_meta) { |
295
|
1
|
|
|
|
|
8
|
Carp::croak("Can't resolve value for '$accessor_name' on class $class_name id '".$self->id |
296
|
|
|
|
|
|
|
. "': No class metadata for value '$concrete_r_class_name' referenced as property '$id_class_by'"); |
297
|
|
|
|
|
|
|
} |
298
|
1146
|
|
|
|
|
15370
|
$id_resolver = $concrete_r_class_meta->get_composite_id_resolver; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
516460
|
|
|
|
|
626276
|
@id=(); |
302
|
516460
|
|
|
|
|
576499
|
for my $property_name (@$id_by) { # no implicit topic |
303
|
534360
|
|
|
|
|
901104
|
my $value = $self->$property_name; # scalar context |
304
|
534360
|
|
|
|
|
710420
|
push @id, $value; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
516460
|
100
|
|
|
|
804579
|
$id = @id > 1 |
308
|
|
|
|
|
|
|
? $id_resolver->(@id) |
309
|
|
|
|
|
|
|
: $id[0]; |
310
|
|
|
|
|
|
|
|
311
|
516460
|
100
|
|
|
|
755219
|
return if not defined $id; |
312
|
516409
|
50
|
|
|
|
752975
|
if ($concrete_r_class_name eq 'UR::Object') { |
313
|
0
|
|
|
|
|
0
|
Carp::carp("Querying by using UR::Object class is deprecated."); |
314
|
|
|
|
|
|
|
} |
315
|
516409
|
50
|
33
|
|
|
1464172
|
if (@_ || $where) { |
316
|
|
|
|
|
|
|
# There were additional params passed in |
317
|
0
|
|
|
|
|
0
|
return $concrete_r_class_name->get(id => $id, @_, @$where); |
318
|
|
|
|
|
|
|
} else { |
319
|
516409
|
|
|
|
|
1114824
|
return $concrete_r_class_name->get($id); |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
4684
|
|
|
|
|
50544
|
}; |
323
|
|
|
|
|
|
|
|
324
|
4684
|
|
|
|
|
21069
|
Sub::Install::reinstall_sub({ |
325
|
|
|
|
|
|
|
into => $class_name, |
326
|
|
|
|
|
|
|
as => $accessor_name, |
327
|
|
|
|
|
|
|
code => $accessor, |
328
|
|
|
|
|
|
|
}); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub _resolve_bridge_logic_for_indirect_property { |
333
|
1800
|
|
|
19602
|
|
3935
|
my ($ur_object_type, $class_name, $accessor_name, $via, $to, $where) = @_; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
my $bridge_collector = sub { |
336
|
863501
|
|
|
873939
|
|
604972
|
my $self = shift; |
337
|
863501
|
|
|
|
|
1573390
|
my @results = $self->$via(@$where); |
338
|
|
|
|
|
|
|
# Indirect has one properties must return a single undef value for an empty result, even in list context. |
339
|
863501
|
50
|
66
|
|
|
2745896
|
return if @results == 1 and not defined $results[0]; |
340
|
863501
|
|
|
|
|
1029414
|
return @results; |
341
|
1800
|
|
|
|
|
7783
|
}; |
342
|
|
|
|
|
|
|
my $bridge_crosser = sub { |
343
|
863565
|
|
|
867392
|
|
631064
|
my $bridges = shift; |
344
|
863565
|
|
|
|
|
813495
|
return map { $_->$to(@_) } @$bridges; |
|
866274
|
|
|
|
|
1377891
|
|
345
|
1800
|
|
|
|
|
5183
|
}; |
346
|
|
|
|
|
|
|
|
347
|
1800
|
100
|
|
|
|
5161
|
return($bridge_collector, $bridge_crosser) if ($UR::Object::Type::bootstrapping); |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# bail out and use the default subs if any of these fail |
350
|
736
|
|
|
|
|
1081
|
my ($my_class_meta, $my_property_meta, $via_property_meta, $to_property_meta); |
351
|
|
|
|
|
|
|
|
352
|
736
|
|
|
|
|
2878
|
$my_class_meta = $class_name->__meta__; |
353
|
736
|
50
|
|
|
|
3634
|
$my_property_meta = $my_class_meta->property_meta_for_name($accessor_name) if ($my_class_meta); |
354
|
736
|
50
|
|
|
|
2829
|
$via_property_meta = $my_class_meta->property_meta_for_name($via) if ($my_class_meta); |
355
|
736
|
50
|
|
|
|
4147
|
$to_property_meta = $my_property_meta->to_property_meta() if ($my_property_meta); |
356
|
|
|
|
|
|
|
|
357
|
736
|
100
|
33
|
|
|
6000
|
if (! $my_class_meta || ! $my_property_meta || ! $via_property_meta || ! $to_property_meta) { |
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
358
|
|
|
|
|
|
|
# Something didn't link right, use the default methods |
359
|
25
|
|
|
|
|
77
|
return ($bridge_collector, $bridge_crosser); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
711
|
50
|
66
|
|
|
1586
|
if ($my_property_meta->is_delegated and $my_property_meta->is_many |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
363
|
|
|
|
|
|
|
and $via_property_meta->is_many and $via_property_meta->reverse_as |
364
|
|
|
|
|
|
|
and $via_property_meta->data_type and $via_property_meta->data_type->isa('UR::Object') |
365
|
|
|
|
|
|
|
) { |
366
|
40
|
|
|
|
|
106
|
my $bridge_class = $via_property_meta->data_type; |
367
|
|
|
|
|
|
|
|
368
|
40
|
|
|
|
|
81
|
my @via_join_properties = do { |
369
|
40
|
|
|
|
|
60
|
local $@; |
370
|
40
|
|
|
|
|
95
|
eval { $via_property_meta->get_property_name_pairs_for_join }; |
|
40
|
|
|
|
|
159
|
|
371
|
|
|
|
|
|
|
}; |
372
|
40
|
100
|
|
|
|
124
|
if (! @via_join_properties) { |
373
|
|
|
|
|
|
|
# this can happen if the properties aren't linked together as expected. |
374
|
|
|
|
|
|
|
# For example, a property involved in a many-to-many relationship, but is |
375
|
|
|
|
|
|
|
# defined as a one-to-many with reverse_as. |
376
|
1
|
|
|
|
|
4
|
return ($bridge_collector, $bridge_crosser); |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
39
|
|
|
|
|
58
|
my (@my_join_properties,@their_join_properties); |
380
|
39
|
|
|
|
|
141
|
for (my $i = 0; $i < @via_join_properties; $i++) { |
381
|
40
|
|
|
|
|
57
|
($my_join_properties[$i], $their_join_properties[$i]) = @{ $via_join_properties[$i] }; |
|
40
|
|
|
|
|
177
|
|
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
39
|
|
|
|
|
70
|
my(@where_properties, @where_values, %bridge_meta_params); |
385
|
39
|
50
|
33
|
|
|
178
|
if ($where or $via_property_meta->where) { |
386
|
39
|
|
|
|
|
55
|
my @collected_where; |
387
|
39
|
50
|
|
|
|
149
|
@collected_where = @$where if ($where); |
388
|
39
|
100
|
|
|
|
123
|
push @collected_where, @{ $via_property_meta->where } if ($via_property_meta->where); |
|
5
|
|
|
|
|
13
|
|
389
|
39
|
|
|
|
|
229
|
while (@collected_where) { |
390
|
27
|
|
|
|
|
42
|
my $where_property = shift @collected_where; |
391
|
27
|
|
|
|
|
38
|
my $where_value = shift @collected_where; |
392
|
|
|
|
|
|
|
|
393
|
27
|
100
|
|
|
|
80
|
if (UR::BoolExpr::Util::is_meta_param($where_property)) { |
394
|
9
|
|
|
|
|
39
|
$bridge_meta_params{$where_property} = $where_value; |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
} else { |
397
|
18
|
0
|
33
|
|
|
63
|
if (ref($where_value) eq 'HASH' and $where_value->{'operator'}) { |
398
|
0
|
|
|
|
|
0
|
$where_property .= ' ' .$where_value->{'operator'}; |
399
|
0
|
|
|
|
|
0
|
$where_value = $where_value->{'value'}; |
400
|
|
|
|
|
|
|
} |
401
|
18
|
|
|
|
|
34
|
push @where_properties, $where_property; |
402
|
18
|
|
|
|
|
49
|
push @where_values, $where_value; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
39
|
|
|
|
|
240
|
my $bridge_template = UR::BoolExpr::Template->resolve($bridge_class, @their_join_properties, @where_properties, %bridge_meta_params); |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
$bridge_collector = sub { |
410
|
238
|
|
|
5584
|
|
285
|
my $self = shift; |
411
|
238
|
|
|
|
|
360
|
my @my_values = map { $self->$_} @my_join_properties; |
|
240
|
|
|
|
|
852
|
|
412
|
238
|
|
|
|
|
719
|
my $bx = $bridge_template->get_rule_for_values(@my_values, @where_values); |
413
|
238
|
|
|
|
|
777
|
return $bridge_class->get($bx); |
414
|
39
|
|
|
|
|
263
|
}; |
415
|
|
|
|
|
|
|
|
416
|
39
|
100
|
100
|
|
|
236
|
if ($to_property_meta->is_delegated |
417
|
|
|
|
|
|
|
and |
418
|
|
|
|
|
|
|
my $doubly_deledated_bridge_crosser = _resolve_bridge_crosser_for_doubly_delegated_property($to_property_meta, \%bridge_meta_params) |
419
|
|
|
|
|
|
|
) { |
420
|
16
|
|
|
|
|
45
|
$bridge_crosser = $doubly_deledated_bridge_crosser; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
} |
423
|
710
|
|
|
|
|
1971
|
return ($bridge_collector, $bridge_crosser); |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
sub _make_results_sorter_for_doubly_delegated_bridge_crosser { |
427
|
3
|
|
|
2133
|
|
5
|
my($bridges, $bridge_linker, $results_linker) = @_; |
428
|
|
|
|
|
|
|
|
429
|
3
|
|
|
|
|
3
|
my $rank = 0; |
430
|
3
|
|
|
|
|
6
|
my %bridge_rankings = map { $bridge_linker->() => $rank++ } @$bridges; |
|
15
|
|
|
|
|
17
|
|
431
|
|
|
|
|
|
|
return sub { |
432
|
3
|
|
|
2133
|
|
5
|
my $results = shift; |
433
|
|
|
|
|
|
|
|
434
|
15
|
|
|
|
|
26
|
return map { $_->[1] } |
435
|
18
|
|
|
|
|
24
|
sort { $bridge_rankings{ $a->[0] } <=> $bridge_rankings{ $b->[0] } } |
436
|
3
|
|
|
|
|
6
|
map { [ $results_linker->(), $_ ] } |
|
15
|
|
|
|
|
16
|
|
437
|
|
|
|
|
|
|
@$results; |
438
|
3
|
|
|
|
|
27
|
}; |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
sub _resolve_bridge_crosser_for_doubly_delegated_property { |
442
|
19
|
|
|
19
|
|
35
|
my($to_property_meta, $bridge_meta_params) = @_; |
443
|
|
|
|
|
|
|
# This property's value is doubly delegated. The simple thing to |
444
|
|
|
|
|
|
|
# do is to collect the bridge objects, then call the second |
445
|
|
|
|
|
|
|
# delegation method on each bridge in a loop to collect the final |
446
|
|
|
|
|
|
|
# results, which may trigger one query per result. Depending on |
447
|
|
|
|
|
|
|
# the type of delegation, the final results can be collected with |
448
|
|
|
|
|
|
|
# one query |
449
|
|
|
|
|
|
|
|
450
|
19
|
|
|
|
|
35
|
my($result_class_resolver, $bridge_linking_properties, $final_result_property_name, $result_filtering_property); |
451
|
19
|
100
|
|
|
|
51
|
if ($to_property_meta->via) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# bridges through another via-to property |
453
|
4
|
|
|
|
|
12
|
my $second_via_property_meta = $to_property_meta->via_property_meta; |
454
|
4
|
|
|
|
|
13
|
my $final_class_name = $second_via_property_meta->data_type; |
455
|
4
|
50
|
33
|
|
|
55
|
if ($final_class_name and $final_class_name ne 'UR::Value' and $final_class_name->isa('UR::Object')) { |
|
|
|
33
|
|
|
|
|
456
|
4
|
100
|
|
|
|
15
|
if ( 1 == (my @via2_join_properties = $second_via_property_meta->get_property_name_pairs_for_join)) { |
457
|
2
|
|
|
|
|
5
|
$bridge_linking_properties = [ $via2_join_properties[0]->[0] ]; |
458
|
2
|
|
|
|
|
4
|
$result_filtering_property = $via2_join_properties[0]->[1]; |
459
|
2
|
|
|
19
|
|
16
|
$result_class_resolver = sub { $final_class_name }; |
|
19
|
|
|
|
|
16
|
|
460
|
|
|
|
|
|
|
|
461
|
2
|
|
|
|
|
9
|
$final_result_property_name = $to_property_meta->to; |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
} elsif ($to_property_meta->id_by) { |
466
|
13
|
|
|
|
|
31
|
$bridge_linking_properties = $to_property_meta->id_by; |
467
|
13
|
|
|
|
|
30
|
$result_filtering_property = 'id'; |
468
|
13
|
100
|
|
|
|
217
|
if ($to_property_meta->id_class_by) { |
469
|
|
|
|
|
|
|
# Bridging through an 'id_class_by' property |
470
|
|
|
|
|
|
|
# bucket the bridge items by the result class and do a get for |
471
|
|
|
|
|
|
|
# each of those classes with a listref of IDs |
472
|
5
|
|
|
|
|
12
|
my $result_class_resolving_property = $to_property_meta->id_class_by; |
473
|
5
|
|
|
71
|
|
21
|
$result_class_resolver = sub { shift->$result_class_resolving_property }; |
|
71
|
|
|
|
|
108
|
|
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
} else { |
476
|
|
|
|
|
|
|
# Bridging through a regular id-by property |
477
|
8
|
|
|
|
|
27
|
my $result_class = $to_property_meta->data_type; |
478
|
8
|
|
|
71
|
|
47
|
$result_class_resolver = sub { $result_class }; |
|
71
|
|
|
|
|
89
|
|
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
} elsif ($to_property_meta->reverse_as) { |
482
|
2
|
100
|
|
|
|
8
|
if (1 == (my @reverse_as_join_properties = $to_property_meta->get_property_name_pairs_for_join)) { |
483
|
1
|
|
|
|
|
2
|
$bridge_linking_properties = [ map { $_->[0] } @reverse_as_join_properties ]; |
|
1
|
|
|
|
|
3
|
|
484
|
1
|
|
|
|
|
3
|
$result_filtering_property = $reverse_as_join_properties[0]->[1]; |
485
|
|
|
|
|
|
|
|
486
|
1
|
|
|
|
|
2
|
my $result_class = $to_property_meta->data_type; |
487
|
1
|
|
|
4
|
|
4
|
$result_class_resolver = sub { $result_class }; |
|
4
|
|
|
|
|
5
|
|
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
|
491
|
19
|
100
|
|
|
|
74
|
if ($result_class_resolver) { |
492
|
16
|
|
|
|
|
21
|
my $linking_id_value_for_bridge = do { |
493
|
16
|
|
|
|
|
23
|
my %composite_id_resolver_for_class; |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
sub { |
496
|
90
|
|
|
90
|
|
83
|
my $bridge = shift; |
497
|
90
|
|
|
|
|
110
|
my @id = map { $bridge->$_ } @$bridge_linking_properties; |
|
90
|
|
|
|
|
163
|
|
498
|
|
|
|
|
|
|
|
499
|
90
|
|
|
|
|
126
|
my $result_class = $result_class_resolver->($bridge); |
500
|
90
|
|
66
|
|
|
293
|
my $id_resolver = $composite_id_resolver_for_class{ $result_class } |
501
|
|
|
|
|
|
|
||= $result_class->__meta__->get_composite_id_resolver; |
502
|
|
|
|
|
|
|
|
503
|
90
|
|
|
|
|
169
|
return $id_resolver->(@id); |
504
|
16
|
|
|
|
|
96
|
}; |
505
|
|
|
|
|
|
|
}; |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
return sub { |
508
|
33
|
|
|
33
|
|
48
|
my $bridges = shift; |
509
|
33
|
|
|
|
|
48
|
my %result_class_names_and_ids; |
510
|
|
|
|
|
|
|
|
511
|
33
|
|
|
|
|
66
|
foreach my $bridge ( @$bridges ) { |
512
|
75
|
|
|
|
|
117
|
my $result_class = $result_class_resolver->($bridge); |
513
|
75
|
|
100
|
|
|
277
|
$result_class_names_and_ids{$result_class} ||= []; |
514
|
|
|
|
|
|
|
|
515
|
75
|
|
|
|
|
130
|
my $id = $linking_id_value_for_bridge->($bridge); |
516
|
75
|
|
|
|
|
70
|
push @{ $result_class_names_and_ids{ $result_class } }, $id; |
|
75
|
|
|
|
|
143
|
|
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
|
519
|
33
|
|
|
|
|
39
|
my @results; |
520
|
33
|
|
|
|
|
85
|
foreach my $result_class ( keys %result_class_names_and_ids ) { |
521
|
44
|
50
|
|
|
|
231
|
if($result_class->isa('UR::Value')) { #can't group queries together for UR::Values |
522
|
0
|
|
|
|
|
0
|
push @results, map { $result_class->get($result_filtering_property => $_, @_) } @{$result_class_names_and_ids{$result_class}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
523
|
|
|
|
|
|
|
} else { |
524
|
44
|
|
|
|
|
201
|
push @results, $result_class->get($result_filtering_property => $result_class_names_and_ids{$result_class}, @_); |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
|
528
|
33
|
100
|
33
|
|
|
188
|
if ($bridge_meta_params->{'-order'} || $bridge_meta_params->{'-order_by'}) { |
529
|
|
|
|
|
|
|
my $results_sorter = _make_results_sorter_for_doubly_delegated_bridge_crosser( |
530
|
|
|
|
|
|
|
$bridges, |
531
|
15
|
|
|
|
|
15
|
sub { return $linking_id_value_for_bridge->($_) }, |
532
|
3
|
|
|
|
|
27
|
sub { $_->id } ); |
|
15
|
|
|
|
|
21
|
|
533
|
3
|
|
|
|
|
15
|
@results = $results_sorter->(\@results); |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
|
536
|
33
|
100
|
|
|
|
107
|
@results = map { $_->$final_result_property_name } @results if ($to_property_meta->via); |
|
9
|
|
|
|
|
17
|
|
537
|
33
|
|
|
|
|
126
|
return @results; |
538
|
16
|
|
|
|
|
164
|
}; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
|
541
|
3
|
|
|
|
|
14
|
return; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
sub _is_assignment_value { |
545
|
|
|
|
|
|
|
return ( |
546
|
7
|
|
33
|
7
|
|
91
|
@_ == 1 |
547
|
|
|
|
|
|
|
and not (ref($_[0]) and Scalar::Util::blessed($_[0]) and $_[0]->isa("UR::BoolExpr")) |
548
|
|
|
|
|
|
|
); |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub mk_indirect_ro_accessor { |
552
|
18005
|
|
|
18005
|
0
|
23632
|
my ($ur_object_type, $class_name, $accessor_name, $via, $to, $where) = @_; |
553
|
18005
|
100
|
|
|
|
28800
|
my @where = ($where ? @$where : ()); |
554
|
18005
|
|
|
|
|
28419
|
my $full_name = join( '::', $class_name, $accessor_name ); |
555
|
18005
|
|
|
|
|
19530
|
my $filterable_accessor_name = 'get_' . $accessor_name; # FIXME we need a better name for |
556
|
18005
|
|
|
|
|
19577
|
my $filterable_full_name = join( '::', $class_name, $filterable_accessor_name ); |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
# This is part of an experimental refactoring of indirect accessors. The goal is to |
559
|
|
|
|
|
|
|
# get rid of all the special cases inside of _resolve_bridge_logic_for_indirect_property() |
560
|
|
|
|
|
|
|
# and do the right thing with the Join data |
561
|
18005
|
|
|
|
|
13350
|
my (@collectors, @crossers); |
562
|
|
|
|
|
|
|
my $accessor2 = Sub::Name::subname $full_name.'_new' => sub { |
563
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
564
|
0
|
0
|
0
|
|
|
0
|
Carp::croak("Assignment value passed to read-only indirect accessor $accessor_name for class $class_name") if @_ and _is_assignment_value(@_); |
565
|
|
|
|
|
|
|
|
566
|
0
|
0
|
|
|
|
0
|
if ($class_name =~ m/^UR::/) { |
567
|
|
|
|
|
|
|
# Some methods will recurse into here if called on a UR::* class (especially |
568
|
|
|
|
|
|
|
# UR::BoolExpr), so do the dumb but safe thing |
569
|
|
|
|
|
|
|
my $bridge_collector = sub { |
570
|
0
|
|
|
|
|
0
|
my $self = shift; |
571
|
0
|
|
|
|
|
0
|
my @results = $self->$via(@$where); |
572
|
|
|
|
|
|
|
# Indirect has one properties must return a single undef value for an empty result, even in list context. |
573
|
0
|
0
|
0
|
|
|
0
|
return if @results == 1 and not defined $results[0]; |
574
|
0
|
|
|
|
|
0
|
return @results; |
575
|
0
|
|
|
|
|
0
|
}; |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
#TODO: move this crosser closure logic down and get rid of the closure |
578
|
0
|
|
|
|
|
0
|
my @filter = @_; |
579
|
0
|
|
|
|
|
0
|
my $bridge_crosser = sub { return map { $_->$to(@filter) } @_ }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
580
|
0
|
|
|
|
|
0
|
my @bridges = $bridge_collector->($self); |
581
|
0
|
0
|
|
|
|
0
|
return unless @bridges; |
582
|
0
|
0
|
|
|
|
0
|
return $self->context_return(@bridges) if ($to eq '-filter'); |
583
|
|
|
|
|
|
|
|
584
|
0
|
|
|
|
|
0
|
my @results = $bridge_crosser->(@bridges); |
585
|
0
|
|
|
|
|
0
|
return $self->context_return(@results); |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
0
|
0
|
|
|
|
0
|
unless (@collectors) { |
589
|
0
|
|
|
|
|
0
|
require List::MoreUtils; |
590
|
|
|
|
|
|
|
|
591
|
0
|
|
|
|
|
0
|
my $prop_meta = $class_name->__meta__->property_meta_for_name($accessor_name); |
592
|
0
|
|
|
|
|
0
|
my @join_list = $prop_meta->_resolve_join_chain(); |
593
|
0
|
|
|
|
|
0
|
foreach my $join ( @join_list ) { |
594
|
0
|
|
|
|
|
0
|
my @source_property_names = @{$join->{source_property_names}}; |
|
0
|
|
|
|
|
0
|
|
595
|
|
|
|
|
|
|
my $collector = sub { |
596
|
0
|
0
|
|
|
|
0
|
my @list = grep { defined && length } map { my $o = $_; map { $o->$_ } @source_property_names} @_; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
597
|
0
|
0
|
|
|
|
0
|
return @list == 1 ? $list[0] : \@list; |
598
|
0
|
|
|
|
|
0
|
}; |
599
|
0
|
|
|
|
|
0
|
push @collectors, $collector; |
600
|
|
|
|
|
|
|
|
601
|
0
|
|
|
|
|
0
|
my $foreign_class = $join->{foreign_class}; |
602
|
0
|
|
|
|
|
0
|
my $crosser; |
603
|
0
|
0
|
|
|
|
0
|
if (! $foreign_class->isa('UR::Value')) { |
604
|
0
|
|
|
|
|
0
|
my @foreign_property_names = @{$join->{foreign_property_names}}; |
|
0
|
|
|
|
|
0
|
|
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
$crosser = sub { my @get_params = List::MoreUtils::pairwise |
607
|
0
|
|
|
|
|
0
|
{ $a => $b } @foreign_property_names, @_; |
|
0
|
|
|
|
|
0
|
|
608
|
0
|
|
|
|
|
0
|
return $foreign_class->get(@get_params); }; |
|
0
|
|
|
|
|
0
|
|
609
|
|
|
|
|
|
|
} |
610
|
0
|
|
|
|
|
0
|
push @crossers, $crosser; |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
0
|
|
|
|
|
0
|
my @working = ($self); |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
# This can probably be rewritten with List::Util::reduce |
617
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < @collectors; $i++) { |
618
|
0
|
0
|
|
|
|
0
|
last unless @working; |
619
|
0
|
|
|
|
|
0
|
my @working = $collectors[$i]->(@working); |
620
|
0
|
0
|
|
|
|
0
|
next unless $crossers[$i]; |
621
|
0
|
|
|
|
|
0
|
@working = $crossers[$i]->(@working); |
622
|
|
|
|
|
|
|
} |
623
|
0
|
|
|
|
|
0
|
$self->context_return(@working); |
624
|
18005
|
|
|
|
|
147156
|
}; |
625
|
|
|
|
|
|
|
#Sub::Install::reinstall_sub({ |
626
|
|
|
|
|
|
|
# into => $class_name, |
627
|
|
|
|
|
|
|
# as => $accessor_name.'_new', |
628
|
|
|
|
|
|
|
# code => $accessor2, |
629
|
|
|
|
|
|
|
#}); |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
|
632
|
18005
|
|
|
|
|
18031
|
my($bridge_collector, $bridge_crosser); |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_name => sub { |
635
|
863701
|
|
|
863701
|
|
692761
|
my $self = shift; |
|
|
|
|
863701
|
|
|
|
|
|
|
|
863701
|
|
|
|
|
|
|
|
863701
|
|
|
|
|
|
|
|
863701
|
|
|
|
|
|
|
|
863701
|
|
|
|
|
|
|
|
863701
|
|
|
|
|
|
|
|
863701
|
|
|
|
|
|
|
|
882227
|
|
|
|
|
|
|
|
1666581
|
|
|
|
|
|
|
|
1663536
|
|
|
|
|
|
|
|
1663536
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
2454411
|
|
|
|
|
|
|
|
2454411
|
|
|
|
|
|
|
|
2454411
|
|
|
|
|
|
|
|
2454411
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1791009
|
|
|
|
|
|
|
|
1755249
|
|
|
|
|
|
|
|
1711469
|
|
|
|
|
|
|
|
1709599
|
|
|
|
|
|
|
|
2493466
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1659056
|
|
|
|
|
|
|
|
1374813
|
|
|
|
|
|
|
|
921252
|
|
|
|
|
|
|
|
1533173
|
|
|
|
|
|
|
|
924278
|
|
|
|
|
|
|
|
1019913
|
|
|
|
|
|
|
|
2314167
|
|
|
|
|
|
|
|
1717831
|
|
|
|
|
|
|
|
256632
|
|
|
|
636
|
863701
|
50
|
33
|
|
|
1449962
|
Carp::croak("Assignment value passed to read-only indirect accessor $accessor_name for class $class_name") if @_ == 1 and _is_assignment_value(@_); |
637
|
|
|
|
|
|
|
|
638
|
863701
|
100
|
|
|
|
1117530
|
unless ($bridge_collector) { |
639
|
1787
|
|
|
|
|
8716
|
($bridge_collector, $bridge_crosser) |
640
|
|
|
|
|
|
|
= $ur_object_type->_resolve_bridge_logic_for_indirect_property($class_name, $accessor_name, $via, $to, \@where); |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
|
643
|
863701
|
|
|
|
|
997211
|
my @bridges = $bridge_collector->($self); |
644
|
|
|
|
|
|
|
|
645
|
863701
|
100
|
|
|
|
1155119
|
return unless @bridges; |
646
|
863610
|
100
|
|
|
|
1192115
|
return $self->context_return(@bridges) if ($to eq '-filter'); |
647
|
|
|
|
|
|
|
|
648
|
863573
|
|
|
|
|
1079927
|
my @results = $bridge_crosser->(\@bridges, @_); |
649
|
863573
|
|
|
|
|
1634860
|
$self->context_return(@results); |
650
|
18005
|
|
|
|
|
85852
|
}; |
651
|
|
|
|
|
|
|
|
652
|
18005
|
50
|
|
|
|
30745
|
unless ($accessor_name) { |
653
|
0
|
|
|
|
|
0
|
Carp::croak("No accessor name specified for read-only indirect accessor $accessor_name for class $class_name"); |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
Sub::Install::reinstall_sub({ |
657
|
18005
|
|
|
|
|
57837
|
into => $class_name, |
658
|
|
|
|
|
|
|
as => $accessor_name, |
659
|
|
|
|
|
|
|
code => $accessor, |
660
|
|
|
|
|
|
|
}); |
661
|
|
|
|
|
|
|
|
662
|
18005
|
|
|
|
|
581968
|
my $r_class_name; |
663
|
|
|
|
|
|
|
my $r_class_name_resolver = sub { |
664
|
0
|
0
|
|
168082
|
|
0
|
return $r_class_name if $r_class_name; |
665
|
|
|
|
|
|
|
|
666
|
0
|
|
|
|
|
0
|
my $linking_property = UR::Object::Property->get(class_name => $class_name, property_name => $via); |
667
|
0
|
0
|
|
|
|
0
|
unless ($linking_property->data_type) { |
668
|
0
|
|
|
|
|
0
|
Carp::croak "Property ${class_name}::${accessor_name}: via refers to a property with no data_type. Can't process filter"; |
669
|
|
|
|
|
|
|
} |
670
|
0
|
|
|
|
|
0
|
my $final_property = UR::Object::Property->get(class_name => $linking_property->data_type, |
671
|
|
|
|
|
|
|
property_name => $to); |
672
|
0
|
0
|
|
|
|
0
|
unless ($final_property->data_type) { |
673
|
0
|
|
|
|
|
0
|
Carp::croak "Property ${class_name}::${accessor_name}: to refers to a property with no data_type. Can't process filter"; |
674
|
|
|
|
|
|
|
} |
675
|
0
|
|
|
|
|
0
|
$r_class_name = $final_property->data_type; |
676
|
18005
|
|
|
|
|
51993
|
}; |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
my $filterable_accessor = Sub::Name::subname $filterable_full_name => sub { |
679
|
101
|
|
|
56959
|
|
124
|
my $self = shift; |
|
|
|
|
3175
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
|
3175
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
|
0
|
|
|
|
680
|
101
|
|
|
|
|
456
|
my @results = $self->$accessor_name(); |
681
|
101
|
50
|
|
|
|
290
|
if (@_) { |
682
|
0
|
|
|
|
|
0
|
my $rule; |
683
|
0
|
0
|
0
|
|
|
0
|
if (@_ == 1 and ref($_[0]) and $_[0]->isa('UR::BoolExpr')) { |
|
|
|
0
|
|
|
|
|
684
|
0
|
|
|
|
|
0
|
$rule = shift; |
685
|
|
|
|
|
|
|
} else { |
686
|
0
|
|
0
|
|
|
0
|
$r_class_name ||= $r_class_name_resolver->(); |
687
|
0
|
|
|
|
|
0
|
$rule = UR::BoolExpr->resolve_normalized($r_class_name, @_); |
688
|
|
|
|
|
|
|
} |
689
|
0
|
|
|
|
|
0
|
@results = grep { $rule->evaluate($_) } @results; |
|
0
|
|
|
|
|
0
|
|
690
|
|
|
|
|
|
|
} |
691
|
101
|
|
|
|
|
245
|
$self->context_return(@results); |
692
|
18005
|
|
|
|
|
99317
|
}; |
693
|
18005
|
|
|
|
|
51380
|
Sub::Install::reinstall_sub({ |
694
|
|
|
|
|
|
|
into => $class_name, |
695
|
|
|
|
|
|
|
as => $filterable_accessor_name, |
696
|
|
|
|
|
|
|
code => $filterable_accessor, |
697
|
|
|
|
|
|
|
}); |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
sub mk_indirect_rw_accessor { |
703
|
14
|
|
|
14
|
0
|
28
|
my ($ur_object_type, $class_name, $accessor_name, $via, $to, $where, $singular_name, $property_name) = @_; |
704
|
14
|
|
33
|
|
|
36
|
$property_name ||= $accessor_name; |
705
|
14
|
100
|
|
|
|
45
|
my @where = ($where ? @$where : ()); |
706
|
14
|
|
|
|
|
34
|
my $full_name = join( '::', $class_name, $accessor_name ); |
707
|
|
|
|
|
|
|
|
708
|
14
|
|
|
|
|
18
|
my $update_strategy; # defined the first time we "set" a value through this |
709
|
|
|
|
|
|
|
my $adder; |
710
|
0
|
|
|
|
|
0
|
my $via_property_meta; |
711
|
0
|
|
|
|
|
0
|
my $r_class_name; |
712
|
0
|
|
|
|
|
0
|
my $is_many; |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
my $resolve_update_strategy = sub { |
715
|
13
|
50
|
|
13
|
|
35
|
unless (defined $update_strategy) { |
716
|
|
|
|
|
|
|
# Resolve the strategy. We need to figure out if $to |
717
|
|
|
|
|
|
|
# refers to an id-property. This is only called once, when the |
718
|
|
|
|
|
|
|
# accessor is first used. |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
# If we reference a remote object, and go to one of its id properties |
721
|
|
|
|
|
|
|
# we must do a delete/create instead of property change. Note that |
722
|
|
|
|
|
|
|
# this is only allowed when the remote object has no direct properties |
723
|
|
|
|
|
|
|
# which are not id properties. |
724
|
|
|
|
|
|
|
|
725
|
13
|
|
|
|
|
67
|
my $my_property_meta = $class_name->__meta__->property_meta_for_name($property_name); |
726
|
13
|
50
|
|
|
|
41
|
unless ($my_property_meta) { |
727
|
0
|
|
|
|
|
0
|
Carp::croak("Failed to find property meta for '$property_name' on class $class_name"); |
728
|
|
|
|
|
|
|
} |
729
|
13
|
|
|
|
|
34
|
$is_many = $my_property_meta->is_many; |
730
|
|
|
|
|
|
|
|
731
|
13
|
|
33
|
|
|
65
|
$via_property_meta ||= $class_name->__meta__->property_meta_for_name($via); |
732
|
13
|
50
|
|
|
|
32
|
unless ($via_property_meta) { |
733
|
0
|
|
|
|
|
0
|
Carp::croak("Failed to find property metadata for via property '$via' while resolving property '$property_name' on class $class_name"); |
734
|
|
|
|
|
|
|
} |
735
|
|
|
|
|
|
|
|
736
|
13
|
|
33
|
|
|
82
|
$r_class_name ||= $via_property_meta->data_type; |
737
|
13
|
50
|
|
|
|
31
|
unless ($r_class_name) { |
738
|
0
|
|
|
|
|
0
|
Carp::croak("Cannot resolve property '$property_name' on class $class_name: It is via property '$via' which has no data_type"); |
739
|
|
|
|
|
|
|
} |
740
|
13
|
|
|
|
|
58
|
my $r_class_meta = $r_class_name->__meta__; |
741
|
13
|
50
|
|
|
|
31
|
unless ($r_class_meta) { |
742
|
0
|
|
|
|
|
0
|
Carp::croak("Cannot resolve property '$property_name' on class $class_name: It is via property '$via' with data_type $r_class_name which is not a valid class name"); |
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
|
745
|
13
|
|
|
|
|
40
|
$adder = "add_" . $via_property_meta->singular_name; |
746
|
|
|
|
|
|
|
|
747
|
13
|
50
|
|
|
|
62
|
if ($my_property_meta->_involves_id_property) { |
748
|
13
|
|
|
|
|
23
|
$update_strategy = 'delete-create' |
749
|
|
|
|
|
|
|
} |
750
|
|
|
|
|
|
|
else { |
751
|
0
|
|
|
|
|
0
|
$update_strategy = 'change'; |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
} |
754
|
13
|
|
|
|
|
24
|
return $update_strategy; |
755
|
14
|
|
|
|
|
120
|
}; |
756
|
|
|
|
|
|
|
|
757
|
14
|
|
|
|
|
17
|
my ($bridge_collector, $bridge_crosser); |
758
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_name => sub { |
759
|
38
|
|
|
38
|
|
13992
|
my $self = shift; |
760
|
|
|
|
|
|
|
|
761
|
38
|
100
|
|
|
|
102
|
unless ($bridge_collector) { |
762
|
13
|
|
|
|
|
121
|
($bridge_collector, $bridge_crosser) |
763
|
|
|
|
|
|
|
= $ur_object_type->_resolve_bridge_logic_for_indirect_property($class_name, $accessor_name, $via, $to, \@where); |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
|
766
|
38
|
|
|
|
|
75
|
my @bridges = $bridge_collector->($self); |
767
|
|
|
|
|
|
|
|
768
|
38
|
100
|
66
|
|
|
152
|
if ( @_ == 1 and _is_assignment_value(@_) ) { |
769
|
7
|
100
|
|
|
|
29
|
$resolve_update_strategy->() unless (defined $update_strategy); |
770
|
|
|
|
|
|
|
|
771
|
7
|
50
|
|
|
|
34
|
if ($update_strategy eq 'change') { |
|
|
50
|
|
|
|
|
|
772
|
0
|
0
|
|
|
|
0
|
if (@bridges == 0) { |
|
|
0
|
|
|
|
|
|
773
|
|
|
|
|
|
|
#print "adding via $adder @where :::> $to @_\n"; |
774
|
0
|
|
|
|
|
0
|
my $exception = do { |
775
|
0
|
|
|
|
|
0
|
local $@; |
776
|
0
|
|
|
|
|
0
|
@bridges = eval { $self->$adder(@where, $to => $_[0]) }; |
|
0
|
|
|
|
|
0
|
|
777
|
0
|
|
|
|
|
0
|
$@; |
778
|
|
|
|
|
|
|
}; |
779
|
0
|
0
|
|
|
|
0
|
if ($exception) { |
780
|
0
|
|
|
|
|
0
|
my $r_class_meta = $r_class_name->__meta__; |
781
|
0
|
|
|
|
|
0
|
my $property_meta = $r_class_meta->property($to); |
782
|
0
|
0
|
|
|
|
0
|
if ($property_meta) { |
783
|
|
|
|
|
|
|
# Re-throw the original exception |
784
|
0
|
|
|
|
|
0
|
die $exception; |
785
|
|
|
|
|
|
|
} else { |
786
|
0
|
|
|
|
|
0
|
Carp::croak("Couldn't create a new object through indirect property " |
787
|
|
|
|
|
|
|
. "'$accessor_name' on $class_name. 'to' is $to which is not a property on $r_class_name."); |
788
|
|
|
|
|
|
|
} |
789
|
|
|
|
|
|
|
} |
790
|
|
|
|
|
|
|
#WAS > Carp::confess("Cannot set $accessor_name on $class_name $self->{id}: property is via $via which is not set!"); |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
elsif (@bridges > 1) { |
793
|
0
|
|
|
|
|
0
|
Carp::croak("Cannot set '$accessor_name' on $class_name id '$self->{id}': multiple instances of '$via' found, via which the property is set"); |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
#print "updating $bridges[0] $to to @_\n"; |
796
|
0
|
|
|
|
|
0
|
return $bridges[0]->$to(@_); |
797
|
|
|
|
|
|
|
} |
798
|
|
|
|
|
|
|
elsif ($update_strategy eq 'delete-create') { |
799
|
7
|
50
|
|
|
|
18
|
if (@bridges > 1) { |
800
|
0
|
|
|
|
|
0
|
Carp::croak("Cannot set '$accessor_name' on $class_name $self->{id}: multiple instances of '$via' found, via which the property is set"); |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
else { |
803
|
7
|
100
|
|
|
|
24
|
if (@bridges) { |
804
|
|
|
|
|
|
|
#print "deleting $bridges[0]\n"; |
805
|
4
|
|
|
|
|
27
|
$bridges[0]->delete; |
806
|
|
|
|
|
|
|
} |
807
|
|
|
|
|
|
|
#print "adding via $adder @where :::> $to @_\n"; |
808
|
7
|
|
|
|
|
28
|
@bridges = $self->$adder(@where, $to => $_[0]); |
809
|
7
|
50
|
|
|
|
20
|
unless (@bridges) { |
810
|
0
|
|
|
|
|
0
|
Carp::croak("Failed to add bridge for '$accessor_name' on $class_name if '$self->{id}': method $adder returned false"); |
811
|
|
|
|
|
|
|
} |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
} |
815
|
38
|
100
|
|
|
|
77
|
if (not defined $is_many) { |
816
|
5
|
|
|
|
|
16
|
$resolve_update_strategy->(); |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
38
|
100
|
|
|
|
82
|
if ($is_many) { |
820
|
26
|
100
|
|
|
|
56
|
return unless @bridges; |
821
|
25
|
|
|
|
|
69
|
my @results = $bridge_crosser->(\@bridges, @_); |
822
|
25
|
|
|
|
|
91
|
$self->context_return(@results); |
823
|
|
|
|
|
|
|
} else { |
824
|
12
|
100
|
|
|
|
23
|
return undef unless @bridges; |
825
|
11
|
|
|
|
|
14
|
my @results = map { $_->$to(@_) } @bridges; |
|
11
|
|
|
|
|
28
|
|
826
|
11
|
|
|
|
|
47
|
$self->context_return(@results); |
827
|
|
|
|
|
|
|
} |
828
|
14
|
|
|
|
|
149
|
}; |
829
|
|
|
|
|
|
|
|
830
|
14
|
|
|
|
|
64
|
Sub::Install::reinstall_sub({ |
831
|
|
|
|
|
|
|
into => $class_name, |
832
|
|
|
|
|
|
|
as => $accessor_name, |
833
|
|
|
|
|
|
|
code => $accessor, |
834
|
|
|
|
|
|
|
}); |
835
|
|
|
|
|
|
|
|
836
|
14
|
100
|
|
|
|
472
|
if ($singular_name) { # True if we're defining an is_many indirect property |
837
|
|
|
|
|
|
|
# Add |
838
|
8
|
|
|
|
|
9
|
my $via_adder; |
839
|
8
|
|
|
|
|
17
|
my $adder_method_name = 'add_' . $singular_name; |
840
|
8
|
50
|
|
|
|
30
|
if ($class_name->can($adder_method_name)) { |
841
|
0
|
|
|
|
|
0
|
$adder_method_name = '__' . $adder_method_name; |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
my $adder_method = Sub::Name::subname $class_name . '::' . $adder_method_name => sub { |
844
|
18
|
|
|
54
|
|
3768
|
my($self) = shift; |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
|
847
|
18
|
100
|
|
|
|
52
|
$resolve_update_strategy->() unless (defined $update_strategy); |
848
|
18
|
100
|
|
|
|
44
|
unless (defined $via_adder) { |
849
|
7
|
|
|
|
|
22
|
$via_adder = "add_" . $via_property_meta->singular_name; |
850
|
|
|
|
|
|
|
} |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
# By default, a single value will come in which is the remote value |
853
|
|
|
|
|
|
|
# we just add the appropriate property name to it. If multiple |
854
|
|
|
|
|
|
|
# values come in we trust the caller to be giving additional params. |
855
|
18
|
100
|
|
|
|
47
|
if (@_ == 1) { |
856
|
16
|
|
|
|
|
31
|
unshift @_, $to; |
857
|
|
|
|
|
|
|
} |
858
|
18
|
|
|
|
|
60
|
$self->$via_adder(@where,@_); |
859
|
8
|
|
|
|
|
325
|
}; |
860
|
8
|
|
|
|
|
32
|
Sub::Install::reinstall_sub({ |
861
|
|
|
|
|
|
|
into => $class_name, |
862
|
|
|
|
|
|
|
as => $adder_method_name, |
863
|
|
|
|
|
|
|
code => $adder_method, |
864
|
|
|
|
|
|
|
}); |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
# Remove |
867
|
8
|
|
|
|
|
209
|
my $via_remover; |
868
|
8
|
|
|
|
|
13
|
my $remover_method_name = 'remove_' . $singular_name; |
869
|
8
|
50
|
|
|
|
22
|
if ($class_name->can($remover_method_name)) { |
870
|
0
|
|
|
|
|
0
|
$remover_method_name = '__' . $remover_method_name; |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
my $remover_method = Sub::Name::subname $class_name . '::' . $remover_method_name => sub { |
873
|
4
|
|
|
76
|
|
3758
|
my($self) = shift; |
874
|
|
|
|
|
|
|
|
875
|
4
|
50
|
|
|
|
14
|
$resolve_update_strategy->() unless (defined $update_strategy); |
876
|
4
|
100
|
|
|
|
12
|
unless (defined $via_remover) { |
877
|
3
|
|
|
|
|
11
|
$via_remover = "remove_" . $via_property_meta->singular_name; |
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
# By default, a single value will come in which is the remote value |
881
|
|
|
|
|
|
|
# we just remove the appropriate property name to it. If multiple |
882
|
|
|
|
|
|
|
# values come in we trust the caller to be giving removeitional params. |
883
|
4
|
50
|
|
|
|
13
|
if (@_ == 1) { |
884
|
4
|
|
|
|
|
9
|
unshift @_, $to; |
885
|
|
|
|
|
|
|
} |
886
|
4
|
|
|
|
|
22
|
$self->$via_remover(@where,@_); |
887
|
8
|
|
|
|
|
289
|
}; |
888
|
8
|
|
|
|
|
32
|
Sub::Install::reinstall_sub({ |
889
|
|
|
|
|
|
|
into => $class_name, |
890
|
|
|
|
|
|
|
as => $remover_method_name, |
891
|
|
|
|
|
|
|
code => $remover_method, |
892
|
|
|
|
|
|
|
}); |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
sub mk_calculation_accessor { |
899
|
1895
|
|
|
1912
|
0
|
7299
|
my ($self, $class_name, $accessor_name, $calculation_src, $calculate_from, $params, $is_cached, $column_name) = @_; |
900
|
|
|
|
|
|
|
|
901
|
1895
|
|
|
|
|
2958
|
my $accessor; |
902
|
|
|
|
|
|
|
my @src; |
903
|
|
|
|
|
|
|
|
904
|
1895
|
50
|
33
|
|
|
21072
|
if (not defined $calculation_src or $calculation_src eq '') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
905
|
0
|
|
|
|
|
0
|
$accessor = \&{ $class_name . '::' . $accessor_name }; |
|
0
|
|
|
|
|
0
|
|
906
|
0
|
0
|
|
|
|
0
|
unless ($accessor) { |
907
|
0
|
|
|
|
|
0
|
Carp::croak "$accessor_name not defined in $class_name! Define it, or specify a calculate => sub{} or calculate => \$perl_src in the class definition."; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
elsif (ref($calculation_src) eq 'CODE') { |
911
|
|
|
|
|
|
|
$accessor = sub { |
912
|
4
|
|
|
8
|
|
7
|
my $self = shift; |
913
|
4
|
50
|
|
|
|
13
|
if (@_) { |
914
|
0
|
|
|
|
|
0
|
Carp::croak("$class_name $accessor_name is a read-only property derived from @$calculate_from"); |
915
|
|
|
|
|
|
|
} |
916
|
4
|
|
|
|
|
9
|
return $calculation_src->(map { $self->$_ } @$calculate_from); |
|
4
|
|
|
|
|
25
|
|
917
|
10
|
|
|
|
|
161
|
}; |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
elsif ($calculation_src =~ /^[^\:\W]+$/) { |
920
|
|
|
|
|
|
|
# built-in formula like 'sum' or 'product' |
921
|
2
|
|
|
|
|
7
|
my $module_name = "UR::Object::Type::AccessorWriter::" . ucfirst(lc($calculation_src)); |
922
|
2
|
|
|
|
|
2
|
my $exception = do { |
923
|
2
|
|
|
|
|
2
|
local $@; |
924
|
2
|
|
|
|
|
220
|
eval "use $module_name"; |
925
|
2
|
|
|
|
|
26
|
$@; |
926
|
|
|
|
|
|
|
}; |
927
|
2
|
50
|
|
|
|
5
|
die $exception if $exception; |
928
|
|
|
|
|
|
|
@src = ( |
929
|
|
|
|
|
|
|
"sub ${class_name}::${accessor_name} {", |
930
|
|
|
|
|
|
|
'my $self = $_[0];', |
931
|
2
|
|
|
|
|
7
|
"${module_name}->calculate(\$self, [" . join(",", map { "'$_'" } @$calculate_from) . "], \@_)", |
|
4
|
|
|
|
|
13
|
|
932
|
|
|
|
|
|
|
'}' |
933
|
|
|
|
|
|
|
); |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
else { |
936
|
|
|
|
|
|
|
@src = ( |
937
|
|
|
|
|
|
|
"sub ${class_name}::${accessor_name} {", |
938
|
|
|
|
|
|
|
($params ? 'my ($self,%params) = @_;' : 'my $self = $_[0];'), |
939
|
180
|
|
|
|
|
1209
|
(map { "my \$$_ = \$self->$_;" } @$calculate_from), |
940
|
1883
|
50
|
|
|
|
12163
|
($params ? (map { "my \$$_ = delete \$params{'$_'};" } @$params) : ()), |
|
0
|
50
|
|
|
|
0
|
|
941
|
|
|
|
|
|
|
$calculation_src, |
942
|
|
|
|
|
|
|
'}' |
943
|
|
|
|
|
|
|
); |
944
|
|
|
|
|
|
|
} |
945
|
|
|
|
|
|
|
|
946
|
1895
|
100
|
|
|
|
4426
|
if (!$accessor) { |
947
|
1885
|
50
|
|
|
|
4314
|
if (@src) { |
948
|
1885
|
|
|
|
|
4968
|
my $src = join("\n",@src); |
949
|
|
|
|
|
|
|
#print ">>$src<<\n"; |
950
|
1885
|
|
|
|
|
2152
|
my $exception = do { |
951
|
1885
|
|
|
|
|
2340
|
local $@; |
952
|
1885
|
|
|
10430
|
|
168442
|
eval $src; |
|
10428
|
|
|
5437
|
|
15573
|
|
|
10428
|
|
|
191
|
|
40882
|
|
|
5437
|
|
|
|
|
8335
|
|
|
5437
|
|
|
|
|
21657
|
|
|
36
|
|
|
|
|
1580
|
|
|
191
|
|
|
|
|
6127
|
|
|
191
|
|
|
|
|
1148
|
|
|
28
|
|
|
|
|
571
|
|
|
28
|
|
|
|
|
53
|
|
|
21
|
|
|
|
|
42
|
|
|
18
|
|
|
|
|
359
|
|
|
18
|
|
|
|
|
37
|
|
|
18
|
|
|
|
|
60
|
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
6
|
|
953
|
1885
|
|
|
|
|
5450
|
$@; |
954
|
|
|
|
|
|
|
}; |
955
|
1885
|
50
|
|
|
|
4908
|
if ($exception) { |
956
|
0
|
|
|
|
|
0
|
Carp::croak "ERROR IN CALCULATED PROPERTY SOURCE: $class_name $accessor_name\n$exception\n"; |
957
|
|
|
|
|
|
|
} |
958
|
1885
|
|
|
|
|
2211
|
$accessor = \&{ $class_name . '::' . $accessor_name }; |
|
1885
|
|
|
|
|
6597
|
|
959
|
1885
|
50
|
|
|
|
5346
|
unless ($accessor) { |
960
|
0
|
|
|
|
|
0
|
Carp::confess("Failed to generate code body for calculated property ${class_name}::${accessor_name}!"); |
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
} |
963
|
|
|
|
|
|
|
else { |
964
|
0
|
|
|
|
|
0
|
Carp::croak "Error implementing calcuation accessor for $class_name $accessor_name!"; |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
|
968
|
1895
|
100
|
66
|
|
|
9668
|
if ($accessor and $is_cached) { |
969
|
|
|
|
|
|
|
# Wrap the already-compiled accessor in another function to memoize the |
970
|
|
|
|
|
|
|
# result and save the data into the object |
971
|
241
|
|
|
|
|
488
|
my $calculator_sub = $accessor; |
972
|
|
|
|
|
|
|
$accessor = sub { |
973
|
4747
|
100
|
|
4815
|
|
23031
|
if (@_ > 1) { |
|
|
|
|
4808
|
|
|
|
974
|
1
|
|
|
|
|
234
|
Carp::croak("Cannot change property $accessor_name for class $class_name: cached calculated properties are read-only"); |
975
|
|
|
|
|
|
|
} |
976
|
4746
|
100
|
|
|
|
11883
|
unless (exists $_[0]->{$accessor_name}) { |
977
|
577
|
|
|
|
|
14791
|
$_[0]->{$accessor_name} = $calculator_sub->(@_); |
978
|
|
|
|
|
|
|
} |
979
|
4743
|
|
|
|
|
9042
|
return $_[0]->{$accessor_name}; |
980
|
241
|
|
|
|
|
1712
|
}; |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
# Make a method to clear the cached value and force another calculation |
983
|
241
|
|
|
|
|
411
|
my $invalidator_name; |
984
|
241
|
|
|
|
|
678
|
($invalidator_name = $accessor_name) =~ s/^_+//; |
985
|
241
|
|
|
|
|
703
|
$invalidator_name = "__invalidate_${invalidator_name}__"; |
986
|
|
|
|
|
|
|
Sub::Install::reinstall_sub({ |
987
|
|
|
|
|
|
|
into => $class_name, |
988
|
|
|
|
|
|
|
as => $invalidator_name, |
989
|
374
|
|
|
487
|
|
11025
|
code => sub { delete $_[0]->{$accessor_name} }, |
990
|
241
|
|
|
|
|
1866
|
}); |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
|
993
|
1895
|
|
|
|
|
13424
|
my $full_name = join( '::', $class_name, $accessor_name ); |
994
|
1895
|
|
|
|
|
9602
|
$accessor = Sub::Name::subname $full_name => $accessor; |
995
|
1895
|
|
|
|
|
8683
|
Sub::Install::reinstall_sub({ |
996
|
|
|
|
|
|
|
into => $class_name, |
997
|
|
|
|
|
|
|
as => $accessor_name, |
998
|
|
|
|
|
|
|
code => $accessor, |
999
|
|
|
|
|
|
|
}); |
1000
|
|
|
|
|
|
|
|
1001
|
1895
|
|
|
|
|
72195
|
return $accessor; |
1002
|
|
|
|
|
|
|
} |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
sub mk_dimension_delegate_accessors { |
1005
|
80
|
|
|
33
|
0
|
255
|
my ($self, $accessor_name, $ref_class_name, $non_id_properties, $other_accessor_name, $is_transient) = @_; |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
# Like mk_rw_accessor, but knows that this accessor is a foreign |
1008
|
|
|
|
|
|
|
# key to a dimension table, and configures additional accessors. |
1009
|
|
|
|
|
|
|
# Also makes this accessor "smart", to resolve the dimension |
1010
|
|
|
|
|
|
|
# id only when needed. |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
# Make EAV-like accessors for all of the remote properties |
1013
|
78
|
|
|
|
|
606
|
my $class_name = $self->class_name; |
1014
|
|
|
|
|
|
|
|
1015
|
45
|
|
|
|
|
432
|
my $full_name = join( '::', $class_name, $other_accessor_name ); |
1016
|
|
|
|
|
|
|
my $other_accessor = Sub::Name::subname $full_name => sub { |
1017
|
31
|
|
|
0
|
|
734
|
my $self = shift; |
1018
|
1
|
|
|
|
|
5
|
my $delegate_id = $self->{$accessor_name}; |
1019
|
4
|
0
|
|
|
|
6
|
if (defined($delegate_id)) { |
1020
|
|
|
|
|
|
|
# We're currently delegating. |
1021
|
4
|
|
|
|
|
10
|
my $delegate = $ref_class_name->get($delegate_id); |
1022
|
4
|
0
|
|
|
|
10
|
if (not @_) { |
1023
|
|
|
|
|
|
|
# A simple get. Delegate. |
1024
|
4
|
|
|
|
|
21
|
return $delegate->$other_accessor_name(@_); |
1025
|
|
|
|
|
|
|
} |
1026
|
|
|
|
|
|
|
else { |
1027
|
|
|
|
|
|
|
# We're setting a value. |
1028
|
|
|
|
|
|
|
# Switch from delegating to local access. |
1029
|
|
|
|
|
|
|
# We'll switch back next-time the dimension ID |
1030
|
|
|
|
|
|
|
# is actually requested by its accessor |
1031
|
|
|
|
|
|
|
# (farther below). |
1032
|
0
|
|
|
|
|
0
|
my $old = $delegate->$other_accessor_name; |
1033
|
0
|
|
|
|
|
0
|
my $new = shift; |
1034
|
0
|
|
|
|
|
0
|
my $different; |
1035
|
0
|
|
|
|
|
0
|
my $exception = do { |
1036
|
0
|
|
|
|
|
0
|
local $@; |
1037
|
266
|
|
|
266
|
|
1746
|
$different = eval { no warnings; $old ne $new }; |
|
266
|
|
|
|
|
470
|
|
|
266
|
|
|
|
|
35324
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1038
|
0
|
|
|
|
|
0
|
$@; |
1039
|
|
|
|
|
|
|
}; |
1040
|
0
|
0
|
0
|
|
|
0
|
if ($different or $exception =~ m/has no overloaded magic/) { |
1041
|
0
|
|
|
|
|
0
|
$self->{$accessor_name} = undef; |
1042
|
0
|
|
|
|
|
0
|
for my $property (@$non_id_properties) { |
1043
|
0
|
100
|
|
|
|
0
|
if ($property eq $other_accessor_name) { |
1044
|
|
|
|
|
|
|
# set the value locally |
1045
|
0
|
|
|
|
|
0
|
$self->{$property} = $new; |
1046
|
|
|
|
|
|
|
} |
1047
|
|
|
|
|
|
|
else { |
1048
|
|
|
|
|
|
|
# grab the data from the (now previous) delegate |
1049
|
0
|
|
|
|
|
0
|
$self->{$property} = $delegate->$property; |
1050
|
|
|
|
|
|
|
} |
1051
|
|
|
|
|
|
|
} |
1052
|
0
|
0
|
|
|
|
0
|
$self->__signal_change__( $other_accessor_name, $old, $new ) unless $is_transient; |
1053
|
0
|
|
|
|
|
0
|
return $new; |
1054
|
|
|
|
|
|
|
} |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
} |
1057
|
|
|
|
|
|
|
else { |
1058
|
|
|
|
|
|
|
# We are not currently delegating. |
1059
|
0
|
0
|
|
|
|
0
|
if (@_) { |
1060
|
|
|
|
|
|
|
# set |
1061
|
0
|
|
|
|
|
0
|
my $old = $self->{ $other_accessor_name }; |
1062
|
0
|
|
|
|
|
0
|
my $new = shift; |
1063
|
0
|
|
|
|
|
0
|
my $different; |
1064
|
0
|
|
|
|
|
0
|
my $exception = do { |
1065
|
0
|
|
|
|
|
0
|
local $@; |
1066
|
266
|
|
|
266
|
|
1212
|
$different = eval { no warnings; $old ne $new }; |
|
266
|
|
|
|
|
414
|
|
|
266
|
|
|
|
|
54971
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1067
|
0
|
|
|
|
|
0
|
$@; |
1068
|
|
|
|
|
|
|
}; |
1069
|
0
|
0
|
0
|
|
|
0
|
if ($different or $exception =~ m/has no overloaded magic/) { |
1070
|
0
|
|
|
|
|
0
|
$self->{ $other_accessor_name } = $new; |
1071
|
0
|
0
|
|
|
|
0
|
$self->__signal_change__( $other_accessor_name, $old, $new ) unless $is_transient; |
1072
|
|
|
|
|
|
|
} |
1073
|
0
|
|
|
|
|
0
|
return $new; |
1074
|
|
|
|
|
|
|
} |
1075
|
|
|
|
|
|
|
else { |
1076
|
|
|
|
|
|
|
# get |
1077
|
0
|
|
|
|
|
0
|
return $self->{ $other_accessor_name }; |
1078
|
|
|
|
|
|
|
} |
1079
|
|
|
|
|
|
|
} |
1080
|
45
|
|
|
|
|
132
|
}; |
1081
|
|
|
|
|
|
|
|
1082
|
0
|
|
|
|
|
0
|
Sub::Install::reinstall_sub({ |
1083
|
|
|
|
|
|
|
into => $class_name, |
1084
|
|
|
|
|
|
|
as => $other_accessor_name, |
1085
|
|
|
|
|
|
|
code => $other_accessor, |
1086
|
|
|
|
|
|
|
}); |
1087
|
|
|
|
|
|
|
} |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
sub mk_dimension_identifying_accessor { |
1090
|
0
|
|
|
0
|
0
|
0
|
my ($self, $accessor_name, $ref_class_name, $non_id_properties, $is_transient) = @_; |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
# Like mk_rw_accessor, but knows that this accessor is a foreign |
1093
|
|
|
|
|
|
|
# key to a dimension table, and configures additional accessors. |
1094
|
|
|
|
|
|
|
# Also makes this accessor "smart", to resolve the dimension |
1095
|
|
|
|
|
|
|
# id only when needed. |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
# Make EAV-like accessors for all of the remote properties |
1098
|
0
|
|
|
|
|
0
|
my $class_name = $self->class_name; |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
# Make the actual accessor for the id_by property |
1101
|
0
|
|
|
|
|
0
|
my $full_name = join( '::', $class_name, $accessor_name ); |
1102
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_name => sub { |
1103
|
0
|
0
|
|
0
|
|
0
|
if (@_ > 1) { |
1104
|
0
|
|
|
|
|
0
|
my $old = $_[0]->{ $accessor_name }; |
1105
|
0
|
|
|
|
|
0
|
my $new = $_[1]; |
1106
|
0
|
|
|
|
|
0
|
my $different; |
1107
|
0
|
|
|
|
|
0
|
my $exception = do { |
1108
|
0
|
|
|
|
|
0
|
local $@; |
1109
|
266
|
|
|
266
|
|
1263
|
$different = eval { no warnings; $old ne $new }; |
|
266
|
|
|
|
|
436
|
|
|
266
|
|
|
|
|
62829
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1110
|
0
|
|
|
|
|
0
|
$@; |
1111
|
|
|
|
|
|
|
}; |
1112
|
0
|
0
|
0
|
|
|
0
|
if ($different or $exception =~ m/has no overloaded magic/) { |
1113
|
0
|
|
|
|
|
0
|
$_[0]->{ $accessor_name } = $new; |
1114
|
0
|
0
|
|
|
|
0
|
$_[0]->__signal_change__( $accessor_name, $old, $new ) unless $is_transient; |
1115
|
|
|
|
|
|
|
} |
1116
|
0
|
|
|
|
|
0
|
return $new; |
1117
|
|
|
|
|
|
|
} |
1118
|
0
|
0
|
|
|
|
0
|
if (not defined $_[0]->{ $accessor_name }) { |
1119
|
|
|
|
|
|
|
# Resolve an ID for the current set of values |
1120
|
|
|
|
|
|
|
# Switch to delegating to that object. |
1121
|
0
|
|
|
|
|
0
|
my %params; |
1122
|
0
|
|
|
|
|
0
|
my $self = $_[0]; |
1123
|
0
|
|
|
|
|
0
|
@params{@$non_id_properties} = delete @$self{@$non_id_properties}; |
1124
|
0
|
|
|
|
|
0
|
my $delegate = $ref_class_name->get_or_create(%params); |
1125
|
0
|
0
|
|
|
|
0
|
return undef unless $delegate; |
1126
|
0
|
|
|
|
|
0
|
$_[0]->{ $accessor_name } = $delegate->id; |
1127
|
|
|
|
|
|
|
} |
1128
|
0
|
|
|
|
|
0
|
return $_[0]->{ $accessor_name }; |
1129
|
0
|
|
|
|
|
0
|
}; |
1130
|
|
|
|
|
|
|
|
1131
|
0
|
|
|
|
|
0
|
Sub::Install::reinstall_sub({ |
1132
|
|
|
|
|
|
|
into => $class_name, |
1133
|
|
|
|
|
|
|
as => $accessor_name, |
1134
|
|
|
|
|
|
|
code => $accessor, |
1135
|
|
|
|
|
|
|
}); |
1136
|
|
|
|
|
|
|
} |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
sub mk_rw_class_accessor |
1139
|
|
|
|
|
|
|
{ |
1140
|
3
|
|
|
3
|
0
|
6
|
my ($self, $class_name, $accessor_name, $column_name, $is_transient, $variable_value, $calc_default) = @_; |
1141
|
|
|
|
|
|
|
|
1142
|
3
|
|
|
|
|
6
|
my $full_accessor_name = $class_name . "::" . $accessor_name; |
1143
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_accessor_name => sub { |
1144
|
6
|
100
|
|
6
|
|
752
|
if (@_ > 1) { |
|
|
100
|
|
|
|
|
|
1145
|
3
|
|
|
|
|
5
|
my $old = $variable_value; |
1146
|
3
|
|
|
|
|
5
|
$variable_value = $_[1]; |
1147
|
|
|
|
|
|
|
|
1148
|
3
|
|
|
|
|
4
|
my $different; |
1149
|
3
|
|
|
|
|
2
|
my $exception = do { |
1150
|
3
|
|
|
|
|
4
|
local $@; |
1151
|
266
|
|
|
266
|
|
1268
|
$different = eval { no warnings; $old ne $variable_value }; |
|
266
|
|
|
|
|
397
|
|
|
266
|
|
|
|
|
44829
|
|
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
6
|
|
1152
|
3
|
|
|
|
|
5
|
$@; |
1153
|
|
|
|
|
|
|
}; |
1154
|
3
|
50
|
33
|
|
|
17
|
if ($different or $exception =~ m/has no overloaded magic/) { |
1155
|
3
|
50
|
|
|
|
18
|
$_[0]->__signal_change__( $accessor_name, $old, $variable_value ) unless $is_transient; |
1156
|
|
|
|
|
|
|
} |
1157
|
|
|
|
|
|
|
} elsif (defined $calc_default) { |
1158
|
1
|
|
|
|
|
5
|
$variable_value = $calc_default->(); |
1159
|
|
|
|
|
|
|
} |
1160
|
6
|
|
|
|
|
13
|
undef $calc_default; |
1161
|
6
|
|
|
|
|
21
|
return $variable_value; |
1162
|
3
|
|
|
|
|
31
|
}; |
1163
|
3
|
|
|
|
|
12
|
Sub::Install::reinstall_sub({ |
1164
|
|
|
|
|
|
|
into => $class_name, |
1165
|
|
|
|
|
|
|
as => $accessor_name, |
1166
|
|
|
|
|
|
|
code => $accessor, |
1167
|
|
|
|
|
|
|
}); |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
sub mk_ro_class_accessor { |
1172
|
180
|
|
|
181
|
0
|
419
|
my($self, $class_name, $accessor_name, $column_name, $variable_value, $calc_default) = @_; |
1173
|
|
|
|
|
|
|
|
1174
|
180
|
|
|
|
|
537
|
my $full_accessor_name = $class_name . "::" . $accessor_name; |
1175
|
|
|
|
|
|
|
my $accessor = Sub::Name::subname $full_accessor_name => sub { |
1176
|
496
|
100
|
|
496
|
|
9761
|
if (@_ > 1) { |
|
|
100
|
|
|
|
|
|
1177
|
1
|
|
|
|
|
2
|
my $new = $_[1]; |
1178
|
|
|
|
|
|
|
|
1179
|
1
|
|
|
|
|
2
|
my $different; |
1180
|
1
|
|
|
|
|
2
|
my $exception = do{ |
1181
|
1
|
|
|
|
|
1
|
local $@; |
1182
|
266
|
|
|
266
|
|
1193
|
$different = eval { no warnings; $variable_value ne $new }; |
|
266
|
|
|
|
|
400
|
|
|
266
|
|
|
|
|
261038
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
1183
|
1
|
|
|
|
|
2
|
$@; |
1184
|
|
|
|
|
|
|
}; |
1185
|
1
|
50
|
33
|
|
|
4
|
if ($different or $exception =~ m/has no overloaded magic/) { |
1186
|
1
|
50
|
|
|
|
3
|
$new = defined($new) ? $new : '(undef)'; |
1187
|
1
|
50
|
|
|
|
3
|
my $report_variable_value = defined($variable_value) ? $variable_value : '(undef)'; |
1188
|
1
|
|
|
|
|
272
|
Carp::croak("Cannot change read-only class-wide property $accessor_name for class $class_name from $report_variable_value to $new!"); |
1189
|
|
|
|
|
|
|
} |
1190
|
|
|
|
|
|
|
} elsif (defined $calc_default) { |
1191
|
1
|
|
|
|
|
3
|
$variable_value = $calc_default->(); |
1192
|
|
|
|
|
|
|
} |
1193
|
495
|
|
|
|
|
493
|
undef $calc_default; |
1194
|
495
|
|
|
|
|
1013
|
return $variable_value; |
1195
|
180
|
|
|
|
|
2046
|
}; |
1196
|
180
|
|
|
|
|
946
|
Sub::Install::reinstall_sub({ |
1197
|
|
|
|
|
|
|
into => $class_name, |
1198
|
|
|
|
|
|
|
as => $accessor_name, |
1199
|
|
|
|
|
|
|
code => $accessor, |
1200
|
|
|
|
|
|
|
}); |
1201
|
|
|
|
|
|
|
} |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
sub mk_object_set_accessors { |
1207
|
2736
|
|
|
3236
|
0
|
5118
|
my ($self, $class_name, $singular_name, $plural_name, $reverse_as, $r_class_name, $where) = @_; |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
# These are set by the resolver closure below, and kept in scope by the other closures |
1210
|
2736
|
|
|
|
|
3050
|
my $rule_template; |
1211
|
|
|
|
|
|
|
my $r_class_meta; |
1212
|
0
|
|
|
|
|
0
|
my @property_names; |
1213
|
2736
|
100
|
|
|
|
9293
|
my @where = ($where ? @$where : ()); |
1214
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
my $rule_resolver = sub { |
1216
|
685
|
|
|
1179
|
|
1055
|
my ($obj) = @_; |
1217
|
685
|
|
|
|
|
1444
|
my $loading_r_class_error = ''; |
1218
|
685
|
100
|
|
|
|
1762
|
if (defined $r_class_name) { |
1219
|
671
|
|
|
|
|
821
|
my $exception = do { |
1220
|
671
|
|
|
|
|
854
|
local $@; |
1221
|
671
|
|
|
|
|
1031
|
eval { |
1222
|
671
|
|
|
|
|
2822
|
$r_class_meta = UR::Object::Type->is_loaded($r_class_name); |
1223
|
671
|
100
|
100
|
|
|
3097
|
unless ($r_class_meta or __PACKAGE__->use_module_with_namespace_constraints($r_class_name)) { |
1224
|
|
|
|
|
|
|
# Don't die yet. The named class may not have a file associated with it |
1225
|
310
|
|
|
|
|
640
|
$loading_r_class_error = "Couldn't load class $r_class_name: $@"; |
1226
|
310
|
|
|
|
|
370
|
$@ = ''; |
1227
|
|
|
|
|
|
|
} |
1228
|
|
|
|
|
|
|
|
1229
|
671
|
100
|
|
|
|
1646
|
unless ($r_class_meta) { |
1230
|
326
|
|
|
|
|
2259
|
$r_class_name->class; |
1231
|
16
|
|
|
|
|
57
|
$r_class_meta = UR::Object::Type->get(class_name => $r_class_name); |
1232
|
|
|
|
|
|
|
} |
1233
|
|
|
|
|
|
|
}; |
1234
|
671
|
|
|
|
|
1545
|
$@; |
1235
|
|
|
|
|
|
|
}; |
1236
|
671
|
100
|
|
|
|
1660
|
if ($exception) { |
1237
|
310
|
|
|
|
|
951
|
$loading_r_class_error .= "Couldn't get class object for $r_class_name: $exception"; |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
} |
1240
|
685
|
100
|
100
|
|
|
3301
|
if ($r_class_meta and not $reverse_as) { |
1241
|
|
|
|
|
|
|
# We have a real class on the other end, and it did not specify know to link back to us. |
1242
|
|
|
|
|
|
|
# Try to infer how, otherwise fall back to the same logic we use with "primitives". |
1243
|
25
|
|
|
|
|
38
|
my @possible_relationships = grep { $_->data_type eq $class_name } |
1244
|
7
|
|
|
|
|
46
|
grep { defined $_->data_type } |
|
25
|
|
|
|
|
39
|
|
1245
|
|
|
|
|
|
|
$r_class_meta->all_property_metas(); |
1246
|
|
|
|
|
|
|
|
1247
|
7
|
50
|
|
|
|
45
|
if (@possible_relationships > 1) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
Carp::croak "$class_name has an ambiguous definition for property \"$singular_name\"." |
1249
|
|
|
|
|
|
|
. " The target class $r_class_name has " . scalar(@possible_relationships) |
1250
|
|
|
|
|
|
|
. " relationships which reference back to $class_name." |
1251
|
|
|
|
|
|
|
. " Correct by adding \"reverse_as => X\" to ${class_name}'s \"$singular_name\" definition one of the following values: " |
1252
|
0
|
|
|
|
|
0
|
. join(",",map { '"' . $_->delegation_name . '"' } @possible_relationships) . ".\n"; |
|
0
|
|
|
|
|
0
|
|
1253
|
|
|
|
|
|
|
} |
1254
|
|
|
|
|
|
|
elsif (@possible_relationships == 1) { |
1255
|
3
|
|
|
|
|
10
|
$reverse_as = $possible_relationships[0]->property_name; |
1256
|
|
|
|
|
|
|
} |
1257
|
|
|
|
|
|
|
elsif (@possible_relationships == 0) { |
1258
|
|
|
|
|
|
|
# we now fall through to the logic below and try direct arrayref storage |
1259
|
|
|
|
|
|
|
#die "No relationships found between $r_class_name and $class_name. Error in definition for $class_name $singular_name!" |
1260
|
|
|
|
|
|
|
} |
1261
|
|
|
|
|
|
|
} |
1262
|
685
|
50
|
66
|
|
|
3091
|
if ($reverse_as and ! $r_class_meta) { |
1263
|
|
|
|
|
|
|
# we've resolved reverse_as, but there's not r_class_meta?! |
1264
|
0
|
|
|
|
|
0
|
$self->error_message("Can't resolve reverse relationship $class_name -> $plural_name. No class metadata for $r_class_name"); |
1265
|
0
|
0
|
|
|
|
0
|
if ($loading_r_class_error) { |
1266
|
0
|
|
|
|
|
0
|
Carp::croak "While loading $r_class_name: $loading_r_class_error"; |
1267
|
|
|
|
|
|
|
} else { |
1268
|
0
|
|
|
|
|
0
|
Carp::croak "Is class $r_class_name defined anywhere?"; |
1269
|
|
|
|
|
|
|
} |
1270
|
|
|
|
|
|
|
} |
1271
|
|
|
|
|
|
|
|
1272
|
685
|
100
|
|
|
|
1878
|
if ($reverse_as) { |
1273
|
|
|
|
|
|
|
# join to get the data... |
1274
|
357
|
50
|
|
|
|
1083
|
unless ($r_class_meta) { |
1275
|
0
|
|
|
|
|
0
|
Carp::croak("No remote class metadata found for class $r_class_name while resolving property '$singular_name' of class $class_name"); |
1276
|
|
|
|
|
|
|
} |
1277
|
357
|
|
|
|
|
1557
|
my $property_meta = $r_class_meta->property_meta_for_name($reverse_as); |
1278
|
357
|
50
|
|
|
|
1208
|
unless ($property_meta) { |
1279
|
0
|
|
|
|
|
0
|
Carp::croak "Can't resolve reverse relationship $class_name -> $plural_name. Remote class $r_class_name has no property $reverse_as"; |
1280
|
|
|
|
|
|
|
} |
1281
|
357
|
|
|
|
|
617
|
my @get_params; |
1282
|
357
|
100
|
|
|
|
1411
|
if ($property_meta->via) { |
1283
|
|
|
|
|
|
|
# get_property_name_pairs_for_join() only works for properties connected directly. |
1284
|
|
|
|
|
|
|
# we still need to use it during initialization, but for more complicated relationships |
1285
|
|
|
|
|
|
|
# this should do the right thing |
1286
|
1
|
|
|
|
|
4
|
push @get_params, $property_meta->property_name . '.id' => $obj->id; |
1287
|
1
|
|
|
|
|
3
|
push @property_names, 'id'; |
1288
|
|
|
|
|
|
|
} else { |
1289
|
356
|
|
|
|
|
1897
|
my @property_links = $property_meta->get_property_name_pairs_for_join; |
1290
|
356
|
|
|
|
|
801
|
for my $link (@property_links) { |
1291
|
357
|
|
|
|
|
661
|
my $my_property_name = $link->[1]; |
1292
|
357
|
|
|
|
|
752
|
push @property_names, $my_property_name; |
1293
|
357
|
50
|
|
|
|
1628
|
unless ($obj->can($my_property_name)) { |
1294
|
0
|
|
|
|
|
0
|
Carp::croak "Cannot handle indirect relationship $r_class_name -> $reverse_as. Class $class_name has no property named $my_property_name"; |
1295
|
|
|
|
|
|
|
} |
1296
|
357
|
|
50
|
|
|
3370
|
push @get_params, $link->[0], ($obj->$my_property_name || undef); |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
} |
1299
|
|
|
|
|
|
|
|
1300
|
357
|
100
|
|
|
|
1302
|
if (my $id_class_by = $property_meta->id_class_by) { |
1301
|
3
|
|
|
|
|
18
|
push @get_params, $id_class_by, $obj->class; |
1302
|
3
|
|
|
|
|
5
|
push @property_names, 'class'; |
1303
|
|
|
|
|
|
|
} |
1304
|
357
|
|
|
|
|
3102
|
my $tmp_rule = $r_class_name->define_boolexpr(@get_params,@where); |
1305
|
357
|
50
|
|
|
|
1508
|
if (my $order_by = $property_meta->order_by) { |
1306
|
0
|
|
|
|
|
0
|
push @get_params, $order_by; |
1307
|
|
|
|
|
|
|
} |
1308
|
357
|
|
|
|
|
1204
|
$rule_template = $tmp_rule->template; |
1309
|
357
|
50
|
|
|
|
768
|
unless ($rule_template) { |
1310
|
0
|
|
|
|
|
0
|
Carp::croak "Error generating rule template to handle indirect relationship $class_name $singular_name referencing $r_class_name!"; |
1311
|
|
|
|
|
|
|
} |
1312
|
357
|
|
|
|
|
1036
|
return $tmp_rule; |
1313
|
|
|
|
|
|
|
} |
1314
|
|
|
|
|
|
|
else { |
1315
|
|
|
|
|
|
|
# data is stored locally on the hashref |
1316
|
|
|
|
|
|
|
#die "No relationships found between $r_class_name and $class_name. Error in definition for $class_name $singular_name!" |
1317
|
|
|
|
|
|
|
} |
1318
|
2736
|
|
|
|
|
26220
|
}; |
1319
|
|
|
|
|
|
|
|
1320
|
2736
|
|
|
|
|
3231
|
my @where_values; |
1321
|
2736
|
|
|
|
|
8152
|
for (my $i = 1; $i < @where; $i+=2) { |
1322
|
1475
|
100
|
66
|
|
|
4327
|
if (ref($where[$i]) eq 'HASH' and exists($where[$i]->{'operator'})) { |
1323
|
2
|
|
|
|
|
9
|
push @where_values, $where[$i]->{'value'}; # the operator is already stored in the template |
1324
|
|
|
|
|
|
|
} else { |
1325
|
1473
|
|
|
|
|
3807
|
push @where_values, $where[$i]; |
1326
|
|
|
|
|
|
|
} |
1327
|
|
|
|
|
|
|
} |
1328
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
# These will behave specially if the rule does not specify the ID, or all of the ID. |
1330
|
2736
|
|
|
|
|
2823
|
my @params_prefix; |
1331
|
2736
|
|
|
|
|
3003
|
my $params_prefix_resolved = 0; |
1332
|
|
|
|
|
|
|
my $params_prefix_resolver = sub { |
1333
|
|
|
|
|
|
|
# handle the case of has-many primitives |
1334
|
31
|
50
|
|
504
|
|
96
|
return unless $r_class_meta; |
1335
|
|
|
|
|
|
|
|
1336
|
31
|
|
|
|
|
108
|
my $r_ids = $r_class_meta->property_meta_for_name($reverse_as)->{id_by}; |
1337
|
|
|
|
|
|
|
|
1338
|
31
|
|
|
|
|
131
|
my $cmeta = UR::Object::Type->get($class_name); |
1339
|
31
|
100
|
|
|
|
178
|
my $pmeta = $plural_name ? $cmeta->{has}{$plural_name} : $cmeta->{has}{$singular_name}; |
1340
|
31
|
100
|
|
|
|
140
|
if (my $specify_by = $pmeta->{specify_by}) { |
1341
|
3
|
|
|
|
|
9
|
@params_prefix = ($specify_by); |
1342
|
|
|
|
|
|
|
} |
1343
|
|
|
|
|
|
|
else { |
1344
|
|
|
|
|
|
|
# TODO: should this really be an auto-setting of the specify_by meta property? |
1345
|
28
|
|
|
|
|
109
|
my @id_property_names = $r_class_name->__meta__->id_property_names; |
1346
|
|
|
|
|
|
|
@params_prefix = |
1347
|
|
|
|
|
|
|
grep { |
1348
|
28
|
|
|
|
|
63
|
my $id_property_name = $_; |
|
47
|
|
|
|
|
64
|
|
1349
|
47
|
100
|
|
|
|
63
|
( (grep { $id_property_name eq $_ } @$r_ids) ? 0 : 1) |
|
47
|
|
|
|
|
175
|
|
1350
|
|
|
|
|
|
|
} |
1351
|
|
|
|
|
|
|
@id_property_names; |
1352
|
|
|
|
|
|
|
|
1353
|
|
|
|
|
|
|
# We only do the special single-value spec when there is one property not specified by the rule. |
1354
|
|
|
|
|
|
|
# This is common for a multi-column primary key where all columns reference a parent object, except an index value, etc. |
1355
|
28
|
100
|
|
|
|
100
|
@params_prefix = () unless scalar(@params_prefix) == 1; |
1356
|
|
|
|
|
|
|
} |
1357
|
31
|
|
|
|
|
63
|
$params_prefix_resolved = 1; |
1358
|
2736
|
|
|
|
|
11409
|
}; |
1359
|
|
|
|
|
|
|
|
1360
|
2736
|
100
|
100
|
|
|
13129
|
if (!$plural_name || $singular_name ne $plural_name) { |
1361
|
|
|
|
|
|
|
my $single_accessor = Sub::Name::subname $class_name ."::$singular_name" => sub { |
1362
|
17
|
|
|
480
|
|
4007
|
my $self = shift; |
|
|
|
|
458
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
51
|
|
|
|
1363
|
17
|
|
|
|
|
23
|
my $rule; |
1364
|
17
|
100
|
|
|
|
67
|
$rule = $rule_resolver->($self) unless (defined $rule_template); |
1365
|
17
|
100
|
|
|
|
63
|
if ($rule_template) { |
1366
|
13
|
100
|
|
|
|
59
|
$rule = $rule_template->get_rule_for_values((map { $self->$_ } @property_names), @where_values) unless (defined $rule); |
|
10
|
|
|
|
|
36
|
|
1367
|
13
|
100
|
|
|
|
45
|
$params_prefix_resolver->() unless $params_prefix_resolved; |
1368
|
13
|
100
|
|
|
|
38
|
unshift @_, @params_prefix if @_ == 1; |
1369
|
13
|
100
|
|
|
|
32
|
if (@_) { |
1370
|
7
|
|
|
|
|
21
|
return my $obj = $r_class_name->get($rule->params_list,@_); |
1371
|
|
|
|
|
|
|
} |
1372
|
|
|
|
|
|
|
else { |
1373
|
6
|
|
|
|
|
30
|
return my $obj = $r_class_name->get($rule); |
1374
|
|
|
|
|
|
|
} |
1375
|
|
|
|
|
|
|
} |
1376
|
|
|
|
|
|
|
else { |
1377
|
4
|
100
|
|
|
|
15
|
return unless $self->{$plural_name}; |
1378
|
2
|
50
|
|
|
|
90
|
return unless @_; # Can't compare our list to nothing... |
1379
|
2
|
50
|
|
|
|
5
|
if (@_ > 1) { |
1380
|
0
|
|
|
|
|
0
|
Carp::croak "rule-based selection of single-item accessor not supported. Instead of single value, got @_"; |
1381
|
|
|
|
|
|
|
} |
1382
|
2
|
50
|
|
|
|
7
|
unless (ref($self->{$plural_name}) eq 'ARRAY') { |
1383
|
0
|
|
|
|
|
0
|
Carp::croak("${class_name}::$singular_name($_[0]): $plural_name does not contain an arrayref"); |
1384
|
|
|
|
|
|
|
} |
1385
|
266
|
|
|
266
|
|
1359
|
no warnings 'uninitialized'; |
|
266
|
|
|
|
|
420
|
|
|
266
|
|
|
|
|
392812
|
|
1386
|
2
|
|
|
|
|
3
|
my @matches = grep { $_ eq $_[0] } @{ $self->{$plural_name} }; |
|
3
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
3
|
|
1387
|
2
|
50
|
|
|
|
8
|
return $matches[0] if @matches < 2; |
1388
|
0
|
|
|
|
|
0
|
return $self->context_return(@matches); |
1389
|
|
|
|
|
|
|
} |
1390
|
2716
|
|
|
|
|
27674
|
}; |
1391
|
2716
|
|
|
|
|
11574
|
Sub::Install::reinstall_sub({ |
1392
|
|
|
|
|
|
|
into => $class_name, |
1393
|
|
|
|
|
|
|
as => $singular_name, |
1394
|
|
|
|
|
|
|
code => $single_accessor, |
1395
|
|
|
|
|
|
|
}); |
1396
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
# return now for reverse_as but not is_many |
1398
|
2716
|
100
|
|
|
|
99782
|
unless ($plural_name) { |
1399
|
2
|
|
|
|
|
7
|
return; |
1400
|
|
|
|
|
|
|
} |
1401
|
|
|
|
|
|
|
} |
1402
|
|
|
|
|
|
|
|
1403
|
2734
|
|
|
|
|
10522
|
my $rule_name = $self->rule_accessor_name_for_is_many_accessor($plural_name); |
1404
|
|
|
|
|
|
|
my $rule_accessor = Sub::Name::subname $class_name ."::$rule_name" => sub { |
1405
|
0
|
|
|
15
|
|
0
|
my $self = shift; |
|
|
|
|
4
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
1406
|
0
|
0
|
|
|
|
0
|
$rule_resolver->($self) unless ($rule_template); |
1407
|
0
|
0
|
|
|
|
0
|
unless ($rule_template) { |
1408
|
0
|
|
|
|
|
0
|
Carp::croak "No indirect rule available for locally-stored 'has-many' relationship"; |
1409
|
|
|
|
|
|
|
} |
1410
|
0
|
0
|
|
|
|
0
|
if (@_) { |
1411
|
0
|
|
|
|
|
0
|
my $tmp_rule = $rule_template->get_rule_for_values((map { $self->$_ } @property_names), @where_values); |
|
0
|
|
|
|
|
0
|
|
1412
|
0
|
|
|
|
|
0
|
return $r_class_name->define_boolexpr($tmp_rule->params_list, @_); |
1413
|
|
|
|
|
|
|
} |
1414
|
|
|
|
|
|
|
else { |
1415
|
0
|
|
|
|
|
0
|
return $rule_template->get_rule_for_values((map { $self->$_ } @property_names),@where_values); |
|
0
|
|
|
|
|
0
|
|
1416
|
|
|
|
|
|
|
} |
1417
|
2734
|
|
|
|
|
22554
|
}; |
1418
|
|
|
|
|
|
|
|
1419
|
2734
|
|
|
|
|
9403
|
Sub::Install::reinstall_sub({ |
1420
|
|
|
|
|
|
|
into => $class_name, |
1421
|
|
|
|
|
|
|
as => $rule_name, |
1422
|
|
|
|
|
|
|
code => $rule_accessor, |
1423
|
|
|
|
|
|
|
}); |
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
my $list_accessor = Sub::Name::subname $class_name ."::$plural_name" => sub { |
1426
|
7089
|
|
|
7089
|
|
35048
|
my $self = shift; |
|
|
|
|
7089
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
|
7089
|
|
|
|
|
|
|
|
8793
|
|
|
|
|
|
|
|
8117
|
|
|
|
|
|
|
|
8201
|
|
|
|
|
|
|
|
14475
|
|
|
|
|
|
|
|
20467
|
|
|
|
1427
|
7089
|
|
|
|
|
6078
|
my $rule; |
1428
|
7089
|
100
|
|
|
|
13901
|
$rule = $rule_resolver->($self) unless (defined $rule_template); |
1429
|
7089
|
100
|
|
|
|
20999
|
if ($rule_template) { |
1430
|
6945
|
100
|
|
|
|
15559
|
$rule = $rule_template->get_rule_for_values((map { $self->$_ } @property_names), @where_values) unless (defined $rule); |
|
6615
|
|
|
|
|
15278
|
|
1431
|
6945
|
100
|
|
|
|
12364
|
if (@_) { |
1432
|
2682
|
|
|
|
|
6390
|
return $UR::Context::current->query($r_class_name, $rule->params_list,@_); |
1433
|
|
|
|
|
|
|
} |
1434
|
|
|
|
|
|
|
else { |
1435
|
4263
|
|
|
|
|
11458
|
return $UR::Context::current->query($r_class_name, $rule); |
1436
|
|
|
|
|
|
|
} |
1437
|
|
|
|
|
|
|
} |
1438
|
|
|
|
|
|
|
else { |
1439
|
144
|
100
|
|
|
|
373
|
if (@_) { |
1440
|
4
|
50
|
|
|
|
34
|
if (@_ != 1) { |
|
|
100
|
|
|
|
|
|
1441
|
0
|
|
|
|
|
0
|
Carp::croak "expected a single arrayref when setting a multi-value $class_name $plural_name! Got " . scalar(@_) . " args"; |
1442
|
|
|
|
|
|
|
} elsif ( ref($_[0]) ne 'ARRAY' ) { |
1443
|
1
|
|
|
|
|
2
|
$self->{$plural_name} = [ $_[0] ]; |
1444
|
|
|
|
|
|
|
} else { |
1445
|
3
|
|
|
|
|
5
|
$self->{$plural_name} = [ @{$_[0]} ]; |
|
3
|
|
|
|
|
12
|
|
1446
|
|
|
|
|
|
|
} |
1447
|
4
|
|
|
|
|
9
|
return @{ $self->{$plural_name} }; |
|
4
|
|
|
|
|
10
|
|
1448
|
|
|
|
|
|
|
} |
1449
|
|
|
|
|
|
|
else { |
1450
|
140
|
100
|
|
|
|
565
|
return unless $self->{$plural_name}; |
1451
|
38
|
50
|
|
|
|
119
|
if (ref($self->{$plural_name}) ne 'ARRAY') { |
1452
|
0
|
|
|
|
|
0
|
Carp::carp("$class_name with id ".$self->id." does not hold an arrayref in its $plural_name property"); |
1453
|
0
|
|
|
|
|
0
|
$self->{$plural_name} = [ $self->{$plural_name} ]; |
1454
|
|
|
|
|
|
|
} |
1455
|
38
|
|
|
|
|
45
|
return @{ $self->{$plural_name} }; |
|
38
|
|
|
|
|
212
|
|
1456
|
|
|
|
|
|
|
} |
1457
|
|
|
|
|
|
|
} |
1458
|
2734
|
|
|
|
|
94354
|
}; |
1459
|
|
|
|
|
|
|
|
1460
|
2734
|
|
|
|
|
9620
|
Sub::Install::reinstall_sub({ |
1461
|
|
|
|
|
|
|
into => $class_name, |
1462
|
|
|
|
|
|
|
as => $plural_name, |
1463
|
|
|
|
|
|
|
code => $list_accessor, |
1464
|
|
|
|
|
|
|
}); |
1465
|
|
|
|
|
|
|
|
1466
|
2734
|
|
|
|
|
74417
|
Sub::Install::reinstall_sub({ |
1467
|
|
|
|
|
|
|
into => $class_name, |
1468
|
|
|
|
|
|
|
as => $singular_name . '_list', |
1469
|
|
|
|
|
|
|
code => $list_accessor, |
1470
|
|
|
|
|
|
|
}); |
1471
|
|
|
|
|
|
|
|
1472
|
2734
|
|
|
|
|
72695
|
my $arrayref_name = $self->arrayref_accessor_name_for_is_many_accessor($plural_name); |
1473
|
|
|
|
|
|
|
my $arrayref_accessor = Sub::Name::subname $class_name ."::$arrayref_name" => sub { |
1474
|
3
|
|
|
3008
|
|
1198
|
return [ $list_accessor->(@_) ]; |
|
|
|
|
1454
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
|
9
|
|
|
|
1475
|
2734
|
|
|
|
|
17012
|
}; |
1476
|
|
|
|
|
|
|
|
1477
|
2734
|
|
|
|
|
8827
|
Sub::Install::reinstall_sub({ |
1478
|
|
|
|
|
|
|
into => $class_name, |
1479
|
|
|
|
|
|
|
as => $arrayref_name, |
1480
|
|
|
|
|
|
|
code => $arrayref_accessor, |
1481
|
|
|
|
|
|
|
}); |
1482
|
|
|
|
|
|
|
|
1483
|
2734
|
|
|
|
|
77853
|
my $iterator_name = $self->iterator_accessor_name_for_is_many_accessor($plural_name); |
1484
|
|
|
|
|
|
|
my $iterator_accessor = Sub::Name::subname $class_name ."::$iterator_name" => sub { |
1485
|
21
|
|
|
23
|
|
151
|
my $self = shift; |
|
|
|
|
22
|
|
|
|
|
|
|
|
1
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
63
|
|
|
|
1486
|
21
|
|
|
|
|
31
|
my $rule; |
1487
|
21
|
100
|
|
|
|
66
|
$rule = $rule_resolver->($self) unless (defined $rule_template); |
1488
|
21
|
100
|
|
|
|
72
|
if ($rule_template) { |
1489
|
20
|
50
|
|
|
|
75
|
$rule = $rule_template->get_rule_for_values((map { $self->$_ } @property_names), @where_values) unless (defined $rule); |
|
20
|
|
|
|
|
86
|
|
1490
|
20
|
100
|
|
|
|
62
|
if (@_) { |
1491
|
15
|
|
|
|
|
60
|
return $r_class_name->create_iterator($rule->params_list,@_); |
1492
|
|
|
|
|
|
|
} else { |
1493
|
5
|
|
|
|
|
47
|
return UR::Object::Iterator->create_for_filter_rule($rule); |
1494
|
|
|
|
|
|
|
} |
1495
|
|
|
|
|
|
|
} |
1496
|
|
|
|
|
|
|
else { |
1497
|
1
|
|
50
|
|
|
12
|
return UR::Value::Iterator->create_for_value_arrayref($self->{$plural_name} || []); |
1498
|
|
|
|
|
|
|
} |
1499
|
2734
|
|
|
|
|
18260
|
}; |
1500
|
2734
|
|
|
|
|
8647
|
Sub::Install::reinstall_sub({ |
1501
|
|
|
|
|
|
|
into => $class_name, |
1502
|
|
|
|
|
|
|
as => $iterator_name, |
1503
|
|
|
|
|
|
|
code => $iterator_accessor, |
1504
|
|
|
|
|
|
|
}); |
1505
|
|
|
|
|
|
|
|
1506
|
2734
|
|
|
|
|
77825
|
my $set_name = $self->set_accessor_name_for_is_many_accessor($plural_name); |
1507
|
|
|
|
|
|
|
my $set_accessor = Sub::Name::subname $class_name ."::$set_name" => sub { |
1508
|
4
|
|
|
44
|
|
711
|
my $self = shift; |
|
|
|
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
|
12
|
|
|
|
1509
|
4
|
|
|
|
|
7
|
my $rule; |
1510
|
4
|
50
|
|
|
|
15
|
$rule = $rule_resolver->($self) unless (defined $rule_template); |
1511
|
4
|
50
|
|
|
|
13
|
if ($rule_template) { |
1512
|
4
|
50
|
|
|
|
18
|
$rule = $rule_template->get_rule_for_values((map { $self->$_ } @property_names),@where_values) unless (defined $rule); |
|
4
|
|
|
|
|
15
|
|
1513
|
4
|
|
|
|
|
16
|
return $r_class_name->define_set($rule->params_list,@_); |
1514
|
|
|
|
|
|
|
} |
1515
|
|
|
|
|
|
|
else { |
1516
|
|
|
|
|
|
|
# this is a bit inside-out, but works for primitives |
1517
|
0
|
|
|
|
|
0
|
my @members = $self->$plural_name; |
1518
|
0
|
|
|
|
|
0
|
return UR::Value->define_set(id => \@members); |
1519
|
|
|
|
|
|
|
} |
1520
|
2734
|
|
|
|
|
19380
|
}; |
1521
|
2734
|
|
|
|
|
8975
|
Sub::Install::reinstall_sub({ |
1522
|
|
|
|
|
|
|
into => $class_name, |
1523
|
|
|
|
|
|
|
as => $set_name, |
1524
|
|
|
|
|
|
|
code => $set_accessor, |
1525
|
|
|
|
|
|
|
}); |
1526
|
|
|
|
|
|
|
|
1527
|
2734
|
|
|
|
|
84223
|
my $adder_method_name = $self->adder_name_for_is_many_accessor($plural_name); |
1528
|
2734
|
100
|
|
|
|
10441
|
if ($class_name->can($adder_method_name)) { |
1529
|
1
|
|
|
|
|
14
|
$adder_method_name = '__' . $adder_method_name; |
1530
|
|
|
|
|
|
|
} |
1531
|
|
|
|
|
|
|
my $adder_method = Sub::Name::subname $class_name . '::' . $adder_method_name => sub { |
1532
|
|
|
|
|
|
|
# TODO: this handles only a single item when making objects: support a list of hashrefs |
1533
|
353
|
|
|
353
|
|
9002
|
my $self = shift; |
|
|
|
|
354
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
|
1057
|
|
|
|
1534
|
353
|
|
|
|
|
371
|
my $rule; |
1535
|
353
|
100
|
|
|
|
953
|
$rule = $rule_resolver->($self) unless (defined $rule_template); |
1536
|
353
|
100
|
|
|
|
825
|
if ($rule_template) { |
1537
|
176
|
100
|
|
|
|
435
|
$params_prefix_resolver->() unless $params_prefix_resolved; |
1538
|
176
|
100
|
|
|
|
545
|
unshift @_, @params_prefix if @_ == 1; |
1539
|
176
|
100
|
|
|
|
567
|
$rule = $rule_template->get_rule_for_values((map { $self->$_ } @property_names), @where_values) unless (defined $rule); |
|
160
|
|
|
|
|
452
|
|
1540
|
176
|
|
|
|
|
470
|
$r_class_name->create($rule->params_list,@_); |
1541
|
|
|
|
|
|
|
} |
1542
|
|
|
|
|
|
|
else { |
1543
|
177
|
100
|
|
|
|
301
|
if ($r_class_meta) { |
1544
|
1
|
|
|
|
|
2
|
my $obj; |
1545
|
1
|
50
|
33
|
|
|
15
|
if (@_ == 1 and $_[0]->isa($r_class_name)) { |
1546
|
1
|
|
|
|
|
3
|
$obj = $_[0]; |
1547
|
|
|
|
|
|
|
} |
1548
|
|
|
|
|
|
|
else { |
1549
|
0
|
|
|
|
|
0
|
$obj = $r_class_name->create(@where,@_); |
1550
|
0
|
0
|
|
|
|
0
|
unless ($obj) { |
1551
|
0
|
|
|
|
|
0
|
$self->error_message("Failed to add $singular_name:" . $r_class_name->error_message); |
1552
|
0
|
|
|
|
|
0
|
return; |
1553
|
|
|
|
|
|
|
} |
1554
|
|
|
|
|
|
|
} |
1555
|
1
|
|
50
|
|
|
1
|
push @{ $self->{$plural_name} ||= [] }, $obj; |
|
1
|
|
|
|
|
15
|
|
1556
|
|
|
|
|
|
|
} |
1557
|
|
|
|
|
|
|
else { |
1558
|
176
|
50
|
|
|
|
380
|
if (@_ != 1) { |
1559
|
0
|
|
|
|
|
0
|
Carp::croak "$class_name $adder_method_name expects a single value to add. Got " . scalar(@_) . " args"; |
1560
|
|
|
|
|
|
|
} |
1561
|
176
|
|
100
|
|
|
181
|
push @{ $self->{$plural_name} ||= [] }, $_[0]; |
|
176
|
|
|
|
|
786
|
|
1562
|
176
|
|
|
|
|
519
|
return $_[0]; |
1563
|
|
|
|
|
|
|
} |
1564
|
|
|
|
|
|
|
} |
1565
|
2734
|
|
|
|
|
122109
|
}; |
1566
|
2734
|
|
|
|
|
10016
|
Sub::Install::reinstall_sub({ |
1567
|
|
|
|
|
|
|
into => $class_name, |
1568
|
|
|
|
|
|
|
as => $adder_method_name, |
1569
|
|
|
|
|
|
|
code => $adder_method, |
1570
|
|
|
|
|
|
|
}); |
1571
|
|
|
|
|
|
|
|
1572
|
2734
|
|
|
|
|
84137
|
my $remover_method_name = $self->remover_name_for_is_many_accessor($plural_name); |
1573
|
2734
|
100
|
|
|
|
6691
|
if ($class_name->can($remover_method_name)) { |
1574
|
1
|
|
|
|
|
12
|
$remover_method_name = '__' . $remover_method_name; |
1575
|
|
|
|
|
|
|
} |
1576
|
|
|
|
|
|
|
my $remover_method = Sub::Name::subname $class_name . '::' . $remover_method_name => sub { |
1577
|
9
|
|
|
296
|
|
2104
|
my $self = shift; |
|
|
|
|
161
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
25
|
|
|
|
1578
|
9
|
|
|
|
|
15
|
my $rule; |
1579
|
9
|
100
|
|
|
|
35
|
$rule = $rule_resolver->($self) unless (defined $rule_template); |
1580
|
9
|
100
|
|
|
|
32
|
if ($rule_template) { |
1581
|
|
|
|
|
|
|
# an id-linked "has-many" |
1582
|
7
|
50
|
|
|
|
23
|
$rule = $rule_template->get_rule_for_values((map { $self->$_ } @property_names), @where_values) unless (defined $rule); |
|
7
|
|
|
|
|
21
|
|
1583
|
7
|
50
|
|
|
|
21
|
$params_prefix_resolver->() unless $params_prefix_resolved; |
1584
|
7
|
|
|
|
|
14
|
my @matches; |
1585
|
7
|
100
|
100
|
|
|
41
|
if (@_ == 1 and ref($_[0])) { |
1586
|
|
|
|
|
|
|
# the object to remove was passed-in |
1587
|
1
|
50
|
|
|
|
4
|
unless ($rule->evaluate($_[0])) { |
1588
|
0
|
|
|
|
|
0
|
Carp::croak "Object " . $_[0]->__display_name__ . " is not a member of the $singular_name set!"; |
1589
|
|
|
|
|
|
|
} |
1590
|
1
|
|
|
|
|
3
|
@matches = ($_[0]); |
1591
|
|
|
|
|
|
|
} |
1592
|
|
|
|
|
|
|
else { |
1593
|
|
|
|
|
|
|
# the parameters to find objects to remove were passed-in |
1594
|
6
|
100
|
|
|
|
20
|
unshift @_, @params_prefix if @_ == 1; # a single "id" is the remainder of the id of the object |
1595
|
6
|
|
|
|
|
21
|
@matches = $r_class_name->get($rule->params_list,@_); |
1596
|
|
|
|
|
|
|
} |
1597
|
7
|
|
|
|
|
52
|
my $trans = UR::Context::Transaction->begin; |
1598
|
|
|
|
|
|
|
@matches = map { |
1599
|
7
|
50
|
|
|
|
16
|
$_->delete or Carp::croak "Error deleting $r_class_name " . $_->id . " for $remover_method_name!: " . $_->error_message; |
|
7
|
|
|
|
|
27
|
|
1600
|
|
|
|
|
|
|
} @matches; |
1601
|
7
|
|
|
|
|
31
|
$trans->commit; |
1602
|
7
|
|
|
|
|
23
|
return @matches; |
1603
|
|
|
|
|
|
|
} |
1604
|
|
|
|
|
|
|
else { |
1605
|
|
|
|
|
|
|
# direct storage in an arrayref |
1606
|
2
|
|
50
|
|
|
8
|
$self->{$plural_name} ||= []; |
1607
|
2
|
50
|
|
|
|
6
|
if ($r_class_meta) { |
1608
|
|
|
|
|
|
|
# object |
1609
|
0
|
|
|
|
|
0
|
my @remove; |
1610
|
|
|
|
|
|
|
my @keep; |
1611
|
0
|
|
|
|
|
0
|
my $rule = $r_class_name->define_boolexpr(@_); |
1612
|
0
|
|
|
|
|
0
|
for my $value (@{ $self->{$plural_name} }) { |
|
0
|
|
|
|
|
0
|
|
1613
|
0
|
0
|
|
|
|
0
|
if ($rule->evaluate($value)) { |
1614
|
0
|
|
|
|
|
0
|
push @keep, $value; |
1615
|
|
|
|
|
|
|
} |
1616
|
|
|
|
|
|
|
else { |
1617
|
0
|
|
|
|
|
0
|
push @remove, $value; |
1618
|
|
|
|
|
|
|
} |
1619
|
|
|
|
|
|
|
} |
1620
|
0
|
0
|
|
|
|
0
|
if (@remove) { |
1621
|
0
|
|
|
|
|
0
|
@{ $self->{$plural_name} } = @keep; |
|
0
|
|
|
|
|
0
|
|
1622
|
|
|
|
|
|
|
} |
1623
|
0
|
|
|
|
|
0
|
return @remove; |
1624
|
|
|
|
|
|
|
} |
1625
|
|
|
|
|
|
|
else { |
1626
|
|
|
|
|
|
|
# value (or non-ur object) |
1627
|
2
|
50
|
|
|
|
6
|
if (@_ == 1) { |
|
|
0
|
|
|
|
|
|
1628
|
|
|
|
|
|
|
# remove specific value |
1629
|
2
|
|
|
|
|
3
|
my $removed; |
1630
|
2
|
|
|
|
|
3
|
my $n = 0; |
1631
|
2
|
|
|
|
|
3
|
for my $value (@{ $self->{$plural_name} }) { |
|
2
|
|
|
|
|
6
|
|
1632
|
5
|
100
|
|
|
|
9
|
if ($value eq $_[0]) { |
1633
|
2
|
|
|
|
|
3
|
$removed = splice(@{ $self->{$plural_name} }, $n, 1); |
|
2
|
|
|
|
|
6
|
|
1634
|
2
|
50
|
|
|
|
5
|
Carp::croak("Internal object inconsistency removing value '$value'. Value '$removed' was removed instead!?") unless $removed eq $value; |
1635
|
2
|
|
|
|
|
5
|
return $removed; |
1636
|
|
|
|
|
|
|
} |
1637
|
3
|
|
|
|
|
3
|
$n++; |
1638
|
|
|
|
|
|
|
} |
1639
|
0
|
|
|
|
|
0
|
Carp::croak("Failed to find item $_[0] in $class_name $plural_name. Object has " . scalar(@{$self->{$plural_name}}) . " values: ".join(', ', @{$self->{$plural_name}})); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1640
|
|
|
|
|
|
|
} |
1641
|
|
|
|
|
|
|
elsif (@_ == 0) { |
1642
|
|
|
|
|
|
|
# remove all if no params are specified |
1643
|
0
|
|
0
|
|
|
0
|
@{ $self->{$plural_name} ||= [] } = (); |
|
0
|
|
|
|
|
0
|
|
1644
|
|
|
|
|
|
|
} |
1645
|
|
|
|
|
|
|
else { |
1646
|
0
|
|
|
|
|
0
|
Carp::croak("$class_name $remover_method_name should be called with zero or one arg, got ".scalar(@_)); |
1647
|
|
|
|
|
|
|
} |
1648
|
|
|
|
|
|
|
} |
1649
|
|
|
|
|
|
|
} |
1650
|
2734
|
|
|
|
|
119532
|
}; |
1651
|
|
|
|
|
|
|
|
1652
|
|
|
|
|
|
|
# check here |
1653
|
2734
|
|
|
|
|
10418
|
Sub::Install::reinstall_sub({ |
1654
|
|
|
|
|
|
|
into => $class_name, |
1655
|
|
|
|
|
|
|
as => $remover_method_name, |
1656
|
|
|
|
|
|
|
code => $remover_method, |
1657
|
|
|
|
|
|
|
}); |
1658
|
|
|
|
|
|
|
|
1659
|
|
|
|
|
|
|
} |
1660
|
|
|
|
|
|
|
|
1661
|
266
|
|
|
266
|
|
1608
|
use Data::Dumper; |
|
266
|
|
|
|
|
423
|
|
|
266
|
|
|
|
|
85327
|
|
1662
|
|
|
|
|
|
|
|
1663
|
|
|
|
|
|
|
sub initialize_direct_accessors { |
1664
|
24690
|
|
|
24699
|
0
|
25793
|
my $self = shift; |
1665
|
24690
|
|
|
|
|
32940
|
my $class_name = $self->{class_name}; |
1666
|
|
|
|
|
|
|
|
1667
|
24690
|
|
|
|
|
21553
|
my %id_property_names; |
1668
|
24690
|
|
|
|
|
22872
|
for my $property_name (@{ $self->{id_by} }) { |
|
24690
|
|
|
|
|
49982
|
|
1669
|
6895
|
|
|
|
|
10680
|
$id_property_names{$property_name} = 1; |
1670
|
6895
|
100
|
|
|
|
15205
|
next if $property_name eq "id"; |
1671
|
|
|
|
|
|
|
} |
1672
|
|
|
|
|
|
|
|
1673
|
24690
|
|
|
|
|
24282
|
my %dimensions_by_fk; |
1674
|
24690
|
|
|
|
|
25038
|
for my $property_name (sort keys %{ $self->{has} }) { |
|
24690
|
|
|
|
|
97570
|
|
1675
|
95383
|
|
|
|
|
73374
|
my $property_data = $self->{has}{$property_name}; |
1676
|
95383
|
50
|
|
|
|
140299
|
if ($property_data->{is_dimension}) { |
1677
|
0
|
|
|
|
|
0
|
my $id_by = $property_data->{id_by}; |
1678
|
0
|
0
|
|
|
|
0
|
unless ($id_by) { |
1679
|
0
|
|
|
|
|
0
|
Carp::croak "No id_by specified for dimension $property_name?"; |
1680
|
|
|
|
|
|
|
} |
1681
|
0
|
0
|
|
|
|
0
|
if (@$id_by != 1) { |
1682
|
0
|
|
|
|
|
0
|
Carp::croak "The id_by specified for dimension $property_name must list a single property name!"; |
1683
|
|
|
|
|
|
|
} |
1684
|
|
|
|
|
|
|
|
1685
|
0
|
|
|
|
|
0
|
my $dimension_class_name = $property_data->{data_type}; |
1686
|
0
|
|
|
|
|
0
|
$dimensions_by_fk{$id_by->[0]} = $dimension_class_name; |
1687
|
|
|
|
|
|
|
|
1688
|
0
|
|
|
|
|
0
|
my $ref_class_meta = $dimension_class_name->__meta__; |
1689
|
0
|
|
|
|
|
0
|
my %remote_id_properties = map { $_ => 1 } $ref_class_meta->id_property_names; |
|
0
|
|
|
|
|
0
|
|
1690
|
0
|
|
|
|
|
0
|
my @non_id_properties = grep { not $remote_id_properties{$_} } $ref_class_meta->all_property_names; |
|
0
|
|
|
|
|
0
|
|
1691
|
0
|
|
|
|
|
0
|
for my $expected_delegate_property_name (@non_id_properties) { |
1692
|
0
|
0
|
|
|
|
0
|
unless ($self->{has}{$expected_delegate_property_name}) { |
1693
|
0
|
|
|
|
|
0
|
$self->{has}{$expected_delegate_property_name} = { |
1694
|
|
|
|
|
|
|
$self->_normalize_property_description( |
1695
|
|
|
|
|
|
|
$expected_delegate_property_name, |
1696
|
|
|
|
|
|
|
{ via => $property_name, to => $expected_delegate_property_name, implied_by => $property_name } |
1697
|
|
|
|
|
|
|
) |
1698
|
|
|
|
|
|
|
} |
1699
|
|
|
|
|
|
|
} |
1700
|
|
|
|
|
|
|
} |
1701
|
|
|
|
|
|
|
} |
1702
|
|
|
|
|
|
|
} |
1703
|
|
|
|
|
|
|
|
1704
|
24690
|
|
|
|
|
28105
|
for my $pname (sort keys %{ $self->{has} }) { |
|
24690
|
|
|
|
|
62734
|
|
1705
|
95383
|
|
|
|
|
2812151
|
my $property_name = $pname; # mutable |
1706
|
95383
|
|
|
|
|
77821
|
my $accessor_name = $pname; |
1707
|
|
|
|
|
|
|
|
1708
|
95383
|
|
|
|
|
159299
|
my $property_data = $self->{has}{$property_name}; |
1709
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
# handle aliases |
1711
|
|
|
|
|
|
|
# the underlying property_name and data will change, though the accessor will not |
1712
|
95383
|
|
|
|
|
76485
|
my $n = 0; |
1713
|
95383
|
|
100
|
|
|
241394
|
while ($property_data->{via} and $property_data->{via} eq '__self__') { |
1714
|
6
|
|
|
|
|
16
|
$property_name = $property_data->{to}; |
1715
|
6
|
|
|
|
|
12
|
$property_data = $self->{has}{$property_name}; |
1716
|
6
|
50
|
|
|
|
17
|
unless ($property_data) { |
1717
|
0
|
|
|
|
|
0
|
Carp::confess("Property $accessor_name is an alias for $property_name, which does not exist!") |
1718
|
|
|
|
|
|
|
} |
1719
|
6
|
50
|
|
|
|
22
|
if ($n > 100) { |
1720
|
0
|
|
|
|
|
0
|
Carp::confess("Deep recursion in property aliases behind $accessor_name!"); |
1721
|
|
|
|
|
|
|
} |
1722
|
|
|
|
|
|
|
} |
1723
|
|
|
|
|
|
|
|
1724
|
95383
|
|
|
|
|
89031
|
my $column_name = $property_data->{column_name}; |
1725
|
95383
|
|
|
|
|
92485
|
my $is_transient = $property_data->{is_transient}; |
1726
|
95383
|
|
|
|
|
82424
|
my $where = $property_data->{where}; |
1727
|
|
|
|
|
|
|
|
1728
|
95383
|
|
|
|
|
67489
|
do { |
1729
|
|
|
|
|
|
|
# Handle the case where the software module has an explicit |
1730
|
|
|
|
|
|
|
# override for one of the accessors. |
1731
|
266
|
|
|
266
|
|
1419
|
no strict 'refs'; |
|
266
|
|
|
|
|
399
|
|
|
266
|
|
|
|
|
158247
|
|
1732
|
95383
|
|
|
|
|
61625
|
my $isa = \@{ $class_name . "::ISA" }; |
|
95383
|
|
|
|
|
190396
|
|
1733
|
95383
|
|
|
|
|
125822
|
my @old_isa = @$isa; |
1734
|
95383
|
|
|
|
|
1218333
|
@$isa = (); |
1735
|
95383
|
100
|
|
|
|
438905
|
if ($class_name->can($accessor_name)) { |
1736
|
|
|
|
|
|
|
#warn "property $class_name $accessor_name exists!"; |
1737
|
5321
|
|
|
|
|
43140
|
$accessor_name = "__$accessor_name"; |
1738
|
|
|
|
|
|
|
} |
1739
|
95383
|
|
|
|
|
3597842
|
@$isa = @old_isa; |
1740
|
|
|
|
|
|
|
}; |
1741
|
|
|
|
|
|
|
|
1742
|
95383
|
50
|
|
|
|
269943
|
unless ($accessor_name) { |
1743
|
0
|
|
|
|
|
0
|
Carp::croak("No accessor name for property '$property_name' of class $class_name"); |
1744
|
|
|
|
|
|
|
} |
1745
|
|
|
|
|
|
|
|
1746
|
95383
|
|
|
|
|
70500
|
my $accessor_type; |
1747
|
95383
|
|
|
|
|
137348
|
my @calculation_fields = (qw/calculate calc_perl calc_sql calculate_from/); |
1748
|
95383
|
100
|
100
|
|
|
577705
|
if (my $id_by = $property_data->{id_by}) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1749
|
4684
|
|
|
|
|
8025
|
my $r_class_name = $property_data->{data_type}; |
1750
|
|
|
|
|
|
|
#$self->mk_id_based_object_accessor($class_name, $accessor_name, $id_by, $r_class_name,$where); |
1751
|
4684
|
|
|
|
|
8303
|
my $id_class_by = $property_data->{id_class_by}; |
1752
|
4684
|
50
|
33
|
|
|
18779
|
if ($property_data->{access_as} and $property_data->{access_as} eq 'auto') { |
1753
|
0
|
|
|
|
|
0
|
$self->mk_id_based_flex_accessor($class_name, $accessor_name, $id_by, $r_class_name,$where, $id_class_by); |
1754
|
0
|
0
|
|
|
|
0
|
$self->mk_id_based_object_accessor($class_name, $accessor_name . ($property_data->{is_many} ? '_objs' : '_obj'), $id_by, $r_class_name,$where, $id_class_by); |
1755
|
|
|
|
|
|
|
} |
1756
|
|
|
|
|
|
|
else { |
1757
|
4684
|
|
|
|
|
24166
|
$self->mk_id_based_object_accessor($class_name, $accessor_name, $id_by, $r_class_name,$where, $id_class_by); |
1758
|
|
|
|
|
|
|
} |
1759
|
|
|
|
|
|
|
} |
1760
|
|
|
|
|
|
|
elsif ($property_data->{'is_calculated'} and ! $property_data->{'is_mutable'}) {# and $property_data->{'column_name'}) { |
1761
|
|
|
|
|
|
|
# For calculated + immutable properties, their calculation function is called |
1762
|
|
|
|
|
|
|
# by UR::Context->create_entity(), which then stores the value in the object's |
1763
|
|
|
|
|
|
|
# hash. So, the accessor just needs to pull the data like a regular r/o accessor |
1764
|
|
|
|
|
|
|
#$self->mk_ro_accessor($class_name, $accessor_name, $property_data->{'column_name'}); |
1765
|
|
|
|
|
|
|
$self->mk_calculation_accessor( |
1766
|
|
|
|
|
|
|
$class_name, |
1767
|
|
|
|
|
|
|
$accessor_name, |
1768
|
|
|
|
|
|
|
$property_data->{'calculate'}, |
1769
|
|
|
|
|
|
|
$property_data->{calculate_from}, |
1770
|
|
|
|
|
|
|
$property_data->{calculate_params}, |
1771
|
|
|
|
|
|
|
1, # the value should be cached |
1772
|
4
|
|
|
|
|
37
|
$property_data->{'column_name'}, |
1773
|
|
|
|
|
|
|
); |
1774
|
|
|
|
|
|
|
} |
1775
|
|
|
|
|
|
|
elsif (my $via = $property_data->{via}) { |
1776
|
18019
|
|
33
|
|
|
35549
|
my $to = $property_data->{to} || $property_data->{property_name}; |
1777
|
18019
|
50
|
|
|
|
30557
|
if ($via eq '__self__') { |
1778
|
0
|
|
|
|
|
0
|
Carp::croak "aliases should be caught above!"; |
1779
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
} |
1781
|
18019
|
100
|
|
|
|
24682
|
if ($property_data->{is_mutable}) { |
1782
|
14
|
|
|
|
|
19
|
my $singular_name; |
1783
|
14
|
100
|
|
|
|
42
|
if ($property_data->{'is_many'}) { |
1784
|
8
|
|
|
|
|
37
|
require Lingua::EN::Inflect; |
1785
|
8
|
|
|
|
|
28
|
$singular_name = Lingua::EN::Inflect::PL_V($accessor_name); |
1786
|
|
|
|
|
|
|
} |
1787
|
14
|
|
66
|
|
|
810
|
$self->mk_indirect_rw_accessor($class_name,$accessor_name,$via,$to,$where,$property_data->{'is_many'} && $singular_name, $property_name); |
1788
|
|
|
|
|
|
|
} |
1789
|
|
|
|
|
|
|
else { |
1790
|
18005
|
|
|
|
|
39093
|
$self->mk_indirect_ro_accessor($class_name,$accessor_name,$via,$to,$where); |
1791
|
|
|
|
|
|
|
} |
1792
|
|
|
|
|
|
|
} |
1793
|
|
|
|
|
|
|
elsif (my $calculate = $property_data->{calculate}) { |
1794
|
|
|
|
|
|
|
$self->mk_calculation_accessor( |
1795
|
|
|
|
|
|
|
$class_name, |
1796
|
|
|
|
|
|
|
$accessor_name, |
1797
|
|
|
|
|
|
|
$property_data->{calculate}, |
1798
|
|
|
|
|
|
|
$property_data->{calculate_from}, |
1799
|
|
|
|
|
|
|
$property_data->{calculate_params}, |
1800
|
|
|
|
|
|
|
$property_data->{is_constant}, |
1801
|
|
|
|
|
|
|
$property_data->{column_name}, |
1802
|
1891
|
|
|
|
|
13797
|
); |
1803
|
|
|
|
|
|
|
} |
1804
|
|
|
|
|
|
|
elsif (my $calculate_sql = $property_data->{'calculate_sql'}) { |
1805
|
|
|
|
|
|
|
# The data gets filled in by the object loader behind the scenes. |
1806
|
|
|
|
|
|
|
# To the user, it's a read-only property |
1807
|
2
|
|
|
|
|
7
|
$self->mk_ro_accessor($class_name, $accessor_name, $calculate_sql); |
1808
|
|
|
|
|
|
|
|
1809
|
|
|
|
|
|
|
} |
1810
|
|
|
|
|
|
|
elsif ($property_data->{is_many} or $property_data->{reverse_as}){ |
1811
|
2736
|
|
|
|
|
4443
|
my $reverse_as = $property_data->{reverse_as}; |
1812
|
2736
|
|
|
|
|
4131
|
my $r_class_name = $property_data->{data_type}; |
1813
|
2736
|
|
|
|
|
3127
|
my $singular_name; |
1814
|
|
|
|
|
|
|
my $plural_name; |
1815
|
2736
|
100
|
|
|
|
5129
|
if ($property_data->{is_many}) { |
1816
|
2734
|
|
|
|
|
3304
|
$plural_name = $accessor_name; |
1817
|
2734
|
|
|
|
|
12317
|
$singular_name = $self->singular_accessor_name_for_is_many_accessor($accessor_name); |
1818
|
|
|
|
|
|
|
} |
1819
|
|
|
|
|
|
|
else { |
1820
|
2
|
|
|
|
|
3
|
$singular_name = $accessor_name; |
1821
|
|
|
|
|
|
|
} |
1822
|
2736
|
|
|
|
|
11467
|
$self->mk_object_set_accessors($class_name, $singular_name, $plural_name, $reverse_as, $r_class_name, $where); |
1823
|
|
|
|
|
|
|
} |
1824
|
|
|
|
|
|
|
elsif ($property_data->{'is_classwide'}) { |
1825
|
|
|
|
|
|
|
my($value, $column_name, $is_transient, $calc_default) |
1826
|
183
|
|
|
|
|
708
|
= @$property_data{'default_value','column_name','is_transient', 'calculated_default'}; |
1827
|
183
|
100
|
|
|
|
638
|
if ($property_data->{'is_constant'}) { |
1828
|
180
|
|
|
|
|
1488
|
$self->mk_ro_class_accessor($class_name,$accessor_name,$column_name,$value, $calc_default); |
1829
|
|
|
|
|
|
|
} else { |
1830
|
3
|
|
|
|
|
19
|
$self->mk_rw_class_accessor($class_name,$accessor_name,$column_name,$is_transient,$value, $calc_default); |
1831
|
|
|
|
|
|
|
} |
1832
|
|
|
|
|
|
|
} |
1833
|
|
|
|
|
|
|
else { |
1834
|
|
|
|
|
|
|
# Just use key/value pairs in the hash for normal |
1835
|
|
|
|
|
|
|
# table stuff, and also non-database stuff. |
1836
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
#if ($column_name) { |
1838
|
|
|
|
|
|
|
# push @$props, $property_name; |
1839
|
|
|
|
|
|
|
# push @$cols, $column_name; |
1840
|
|
|
|
|
|
|
#} |
1841
|
|
|
|
|
|
|
|
1842
|
67864
|
|
|
|
|
48624
|
my $maker; |
1843
|
67864
|
100
|
100
|
|
|
209230
|
if ($id_property_names{$property_name} or not $property_data->{is_mutable}) { |
1844
|
7904
|
|
|
|
|
9023
|
$maker = 'mk_ro_accessor'; |
1845
|
|
|
|
|
|
|
} |
1846
|
|
|
|
|
|
|
else { |
1847
|
59960
|
|
|
|
|
51190
|
$maker = 'mk_rw_accessor'; |
1848
|
|
|
|
|
|
|
} |
1849
|
67864
|
|
|
|
|
164051
|
$self->$maker($class_name, $accessor_name, $column_name, $property_name,$is_transient); |
1850
|
|
|
|
|
|
|
} |
1851
|
|
|
|
|
|
|
} |
1852
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
# right now we just stomp on the default accessors constructed above where they are: |
1854
|
|
|
|
|
|
|
# 1. the fk behind a dimensional relationships |
1855
|
|
|
|
|
|
|
# 2. the indirect properties created for the dimensional relationship |
1856
|
24690
|
|
|
|
|
267396
|
for my $dimension_id (keys %dimensions_by_fk) { |
1857
|
0
|
|
|
|
|
0
|
my $dimension_class_name = $dimensions_by_fk{$dimension_id}; |
1858
|
0
|
|
|
|
|
0
|
my $ref_class_meta = $dimension_class_name->__meta__; |
1859
|
0
|
|
|
|
|
0
|
my %remote_id_properties = map { $_ => 1 } $ref_class_meta->id_property_names; |
|
0
|
|
|
|
|
0
|
|
1860
|
0
|
|
|
|
|
0
|
my @non_id_properties = grep { not $remote_id_properties{$_} } $ref_class_meta->all_property_names; |
|
0
|
|
|
|
|
0
|
|
1861
|
0
|
|
|
|
|
0
|
for my $added_property_name (@non_id_properties) { |
1862
|
0
|
|
|
|
|
0
|
$self->mk_dimension_delegate_accessors($dimension_id,$dimension_class_name, \@non_id_properties, $added_property_name); |
1863
|
|
|
|
|
|
|
} |
1864
|
0
|
|
|
|
|
0
|
$self->mk_dimension_identifying_accessor($dimension_id,$dimension_class_name, \@non_id_properties); |
1865
|
|
|
|
|
|
|
} |
1866
|
|
|
|
|
|
|
|
1867
|
24690
|
|
|
|
|
49072
|
return 1; |
1868
|
|
|
|
|
|
|
} |
1869
|
|
|
|
|
|
|
|
1870
|
|
|
|
|
|
|
|
1871
|
|
|
|
|
|
|
1; |
1872
|
|
|
|
|
|
|
|
1873
|
|
|
|
|
|
|
=pod |
1874
|
|
|
|
|
|
|
|
1875
|
|
|
|
|
|
|
=head1 NAME |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
UR::Object::Type::AccessorWriter - Helper module for UR::Object::Type responsible for creating accessors for properties |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1880
|
|
|
|
|
|
|
|
1881
|
|
|
|
|
|
|
Subroutines within this module actually live in the UR::Object::Type |
1882
|
|
|
|
|
|
|
namespace; this module is just a convienent place to collect them. The |
1883
|
|
|
|
|
|
|
class initializer uses these subroutines when it's time to create accessor |
1884
|
|
|
|
|
|
|
methods for a newly defined class. Each accessor is implemented by a closure |
1885
|
|
|
|
|
|
|
that is then assigned a name by Sub::Name and inserted into the defined |
1886
|
|
|
|
|
|
|
class's namespace by Sub::Install. |
1887
|
|
|
|
|
|
|
|
1888
|
|
|
|
|
|
|
=head1 METHODS |
1889
|
|
|
|
|
|
|
|
1890
|
|
|
|
|
|
|
=over 4 |
1891
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
=item initialize_direct_accessors |
1893
|
|
|
|
|
|
|
|
1894
|
|
|
|
|
|
|
$classobj->initialize_direct_accessors(); |
1895
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
This is the entry point into the accessor writing system. It inspects each |
1897
|
|
|
|
|
|
|
item in the 'has' key of the class object's hashref, and creates methods for |
1898
|
|
|
|
|
|
|
each property. |
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
=item mk_rw_accessor |
1901
|
|
|
|
|
|
|
|
1902
|
|
|
|
|
|
|
$classobj->mk_rw_accessor($class_name, $accessor_name, $column_name, $property_name, $is_transient); |
1903
|
|
|
|
|
|
|
|
1904
|
|
|
|
|
|
|
Creates a mutable accessor named $accessor_name which stores its value in |
1905
|
|
|
|
|
|
|
the $property_name key of the object's hashref. |
1906
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
=item mk_ro_accessor |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
$classobj->mk_ro_accessor($class_name, $accessor_name, $column_name, $property_name); |
1910
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
Creates a read-only accessor named $accessor_name which retrieves its value |
1912
|
|
|
|
|
|
|
in the $property_name key of the object's hashref. If the method is used |
1913
|
|
|
|
|
|
|
as a mutator by passing in a value to the method, it will throw an exception |
1914
|
|
|
|
|
|
|
with Carp::croak. |
1915
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
=item mk_id_based_object_accessor |
1917
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
$classobj->mk_id_based_object_accessor($class_name, $accessor_name, $id_by, |
1919
|
|
|
|
|
|
|
$r_class_name, $where); |
1920
|
|
|
|
|
|
|
|
1921
|
|
|
|
|
|
|
Creates an object accessor named $accessor_name. It returns objects of type |
1922
|
|
|
|
|
|
|
$r_class_name, id-ed by the parameters named in the $id_by arrayref. $where |
1923
|
|
|
|
|
|
|
is an optional listref of additional filters to apply when retrieving |
1924
|
|
|
|
|
|
|
objects. |
1925
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
The behavior of the created accessor depends on the number of parameters |
1927
|
|
|
|
|
|
|
passed to it. For 0 params, it retrieves the object pointed to by |
1928
|
|
|
|
|
|
|
$r_class_name and $id_by. For 1 param, it looks up the ID param values |
1929
|
|
|
|
|
|
|
of the passed-in object-parameter, and reassigns value stored in the $id_by |
1930
|
|
|
|
|
|
|
properties of the acted-upon object, effectively acting as a mutator. |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
For more than 1 param, the additional parameters are taken as |
1933
|
|
|
|
|
|
|
properties/values to filter the returned objects on |
1934
|
|
|
|
|
|
|
|
1935
|
|
|
|
|
|
|
=item mk_indirect_ro_accessor |
1936
|
|
|
|
|
|
|
|
1937
|
|
|
|
|
|
|
$classobj->mk_indirect_ro_accessor($class_name, $accessor_name, $via, $to, $where); |
1938
|
|
|
|
|
|
|
|
1939
|
|
|
|
|
|
|
Creates a read-only via accessor named $accessor_name. Its value is |
1940
|
|
|
|
|
|
|
obtained by calling the object accessor named $via, and then calling |
1941
|
|
|
|
|
|
|
the method $to on that object. The optional $where listref is used |
1942
|
|
|
|
|
|
|
as additional filters when calling $via. |
1943
|
|
|
|
|
|
|
|
1944
|
|
|
|
|
|
|
=item mk_indirect_rw_accessor |
1945
|
|
|
|
|
|
|
|
1946
|
|
|
|
|
|
|
$classobj->mk_indirect_rw_accessor($class_name, $accessor_name, $via, $to, |
1947
|
|
|
|
|
|
|
$where, $singular_name); |
1948
|
|
|
|
|
|
|
|
1949
|
|
|
|
|
|
|
Creates a via accessor named $accessor_name that is able to change the |
1950
|
|
|
|
|
|
|
property it points to with $to when called as a mutator. If the $to property |
1951
|
|
|
|
|
|
|
on the remote object is an ID property of its class, it deletes the refered-to |
1952
|
|
|
|
|
|
|
object and creates a new one with the appropriate properties. Otherwise, it |
1953
|
|
|
|
|
|
|
updates the $to property on the refered-to object. |
1954
|
|
|
|
|
|
|
|
1955
|
|
|
|
|
|
|
=item mk_calculation_accessor |
1956
|
|
|
|
|
|
|
|
1957
|
|
|
|
|
|
|
$classobj->mk_calculation_accessor($class_name, $accessor_name, $calculation_src, |
1958
|
|
|
|
|
|
|
$calculate_from, $params, $is_constant, $column_name); |
1959
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
Creates a calculated accessor called $accessor_name. If the $is_constant |
1961
|
|
|
|
|
|
|
flag is true, then the accessor runs the calculation once, caches the result, |
1962
|
|
|
|
|
|
|
and returns that result for subsequent calls to the accessor. |
1963
|
|
|
|
|
|
|
|
1964
|
|
|
|
|
|
|
$calculation_src can be one of: coderef, string containing Perl code, or |
1965
|
|
|
|
|
|
|
the name of a module under UR::Object::Type::AccessorWriter which has a |
1966
|
|
|
|
|
|
|
method called C. If $calculation_src is empty, then $accessor_name |
1967
|
|
|
|
|
|
|
must be the name of an already-existing subroutine in the class's namespace. |
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
=item mk_dimension_delegate_accessors |
1970
|
|
|
|
|
|
|
|
1971
|
|
|
|
|
|
|
=item mk_dimension_identifying_accessor |
1972
|
|
|
|
|
|
|
|
1973
|
|
|
|
|
|
|
These create accessors for dealing with dimension tables in OLAP-type schemas. |
1974
|
|
|
|
|
|
|
They need more documentation. |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
=item mk_rw_class_accessor |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
$classobj->mk_rw_class_accessor($class_name, $accessor_name, $column_name, $is_transient, $variable_value); |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
Creates a read-write accessor called $accessor_name which stores its value |
1981
|
|
|
|
|
|
|
in a scalar captured by the accessor's closure. Since the closure is |
1982
|
|
|
|
|
|
|
inserted into the class's namespace, all instances of the class share the |
1983
|
|
|
|
|
|
|
same closure (and therefore the same scalar), and the property effectively |
1984
|
|
|
|
|
|
|
acts as a class-wide property. |
1985
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
=item mk_ro_class_accessor |
1987
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
$classobj->mk_ro_class_accessor($class_name, $accessor_name, $column_name, $variable_value); |
1989
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
Creates a read-only accessor called $accessor_name which retrieves its value |
1991
|
|
|
|
|
|
|
from a scalar captured by the accessor's closure. The value is initialized |
1992
|
|
|
|
|
|
|
to $variable_value. If called as a mutator, it throws an exception through |
1993
|
|
|
|
|
|
|
Carp::croak |
1994
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
=back |
1996
|
|
|
|
|
|
|
|
1997
|
|
|
|
|
|
|
=head1 SEE ALSO |
1998
|
|
|
|
|
|
|
|
1999
|
|
|
|
|
|
|
UR::Object::Type::AccessorWriter, UR::Object::Type |
2000
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
=cut |