line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DBIx::Class::Schema::PopulateMore::Visitor; |
2
|
|
|
|
|
|
|
|
3
|
3
|
|
|
3
|
|
11
|
use Moo; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
19
|
|
4
|
3
|
|
|
3
|
|
769
|
use Scalar::Util qw/refaddr/; |
|
3
|
|
|
|
|
3
|
|
|
3
|
|
|
|
|
287
|
|
5
|
3
|
|
|
3
|
|
1686
|
use Type::Library -base; |
|
3
|
|
|
|
|
55002
|
|
|
3
|
|
|
|
|
30
|
|
6
|
3
|
|
|
3
|
|
3111
|
use Types::Standard -types; |
|
3
|
|
|
|
|
112625
|
|
|
3
|
|
|
|
|
42
|
|
7
|
3
|
|
|
3
|
|
11802
|
use namespace::clean; |
|
3
|
|
|
|
|
9983
|
|
|
3
|
|
|
|
|
24
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
DBIx::Class::Schema::PopulateMore::Visitor - Visitor for the Populate Data |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSIS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
##Example Usage |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
See Tests for more example usage. |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 DESCRIPTION |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
When populating a table, sometimes we need to inflate values that we won't |
22
|
|
|
|
|
|
|
know of in advance. For example we might have a column that is FK to another |
23
|
|
|
|
|
|
|
column in another table. We want to make it easy to 'tag' a value as something |
24
|
|
|
|
|
|
|
other than a real value to be inserted into the table. |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
Right now we only have one substitution to do, which is the FK one mentioned |
27
|
|
|
|
|
|
|
above, but we might eventually create other substitution types so we've broken |
28
|
|
|
|
|
|
|
this out to make it neat and easy to do so. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
This class defines the following attributes. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head2 update_callback |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
The coderef to be execute should the match condition succeed |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=cut |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
has 'update_callback' => ( |
41
|
|
|
|
|
|
|
is=>'rw', |
42
|
|
|
|
|
|
|
required=>1, |
43
|
|
|
|
|
|
|
lazy=>1, |
44
|
|
|
|
|
|
|
isa=>CodeRef, |
45
|
|
|
|
|
|
|
default=> sub { |
46
|
|
|
|
|
|
|
return sub { |
47
|
|
|
|
|
|
|
return shift; |
48
|
|
|
|
|
|
|
}; |
49
|
|
|
|
|
|
|
}, |
50
|
|
|
|
|
|
|
); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head2 match_condition |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
How we know the value is really something to inflate or perform a substitution |
55
|
|
|
|
|
|
|
on. This get's the namespace of the substitution plugin and it's other data. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
The default behavior (where there is no substitution namespace, is to do the |
58
|
|
|
|
|
|
|
inflate to resultset. This is the most common usecase. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=cut |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
has 'match_condition' => ( |
63
|
|
|
|
|
|
|
is=>'ro', |
64
|
|
|
|
|
|
|
required=>1, |
65
|
|
|
|
|
|
|
isa=>RegexpRef, |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 seen |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
Used to collect up ref addresses of arrays/hashes we have already seen |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
has seen => ( |
75
|
|
|
|
|
|
|
is => 'rw', |
76
|
|
|
|
|
|
|
isa => HashRef, |
77
|
|
|
|
|
|
|
default => sub { {} }, |
78
|
|
|
|
|
|
|
); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head1 METHODS |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
This module defines the following methods. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=head2 callback |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
Given a coderef, sets the current callback and returns self so that we can chain |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=cut |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub callback |
91
|
|
|
|
|
|
|
{ |
92
|
16
|
|
|
16
|
1
|
756
|
my $self = shift @_; |
93
|
16
|
|
|
|
|
468
|
$self->update_callback(shift @_); |
94
|
16
|
|
|
|
|
2215
|
return $self; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=head2 visit |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
A simple visitor that only expects to perform replacements on values |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=cut |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub visit |
104
|
|
|
|
|
|
|
{ |
105
|
119
|
|
|
119
|
1
|
157
|
my ( $self, $target ) = @_; |
106
|
119
|
100
|
|
|
|
308
|
if ( ref $target eq 'ARRAY' ) { |
|
|
100
|
|
|
|
|
|
107
|
25
|
|
|
|
|
71
|
my $addr = refaddr $target; |
108
|
25
|
50
|
|
|
|
467
|
return $self->seen->{$addr} if defined $self->seen->{$addr}; |
109
|
25
|
|
|
|
|
513
|
my $new_array = $self->seen->{$addr} = []; |
110
|
25
|
|
|
|
|
173
|
@$new_array = map { $self->visit($_) } @$target; |
|
63
|
|
|
|
|
908
|
|
111
|
25
|
|
|
|
|
1751
|
return $new_array; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
elsif ( ref $target eq 'HASH' ) { |
114
|
30
|
|
|
|
|
79
|
my $addr = refaddr $target; |
115
|
30
|
50
|
|
|
|
560
|
return $self->seen->{$addr} if defined $self->seen->{$addr}; |
116
|
30
|
|
|
|
|
1728
|
my $new_hash = $self->seen->{$addr} = {}; |
117
|
30
|
|
|
|
|
216
|
%$new_hash = map { $_ => $self->visit( $target->{$_} ) } keys %$target; |
|
40
|
|
|
|
|
207
|
|
118
|
30
|
|
|
|
|
845
|
return $new_hash; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
else { |
121
|
64
|
|
|
|
|
116
|
$self->visit_value($target); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 visit_value |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Here is where we make the choice as to if this value needs to be inflated via a plugin |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=cut |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub visit_value |
132
|
|
|
|
|
|
|
{ |
133
|
64
|
|
|
64
|
1
|
74
|
my ($self, $data) = @_; |
134
|
|
|
|
|
|
|
|
135
|
64
|
100
|
|
|
|
116
|
if(my $item = $self->match_or_not($data)) |
136
|
|
|
|
|
|
|
{ |
137
|
33
|
|
|
|
|
589
|
return $self->update_callback->($item); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
31
|
|
|
|
|
69
|
return $data; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=head2 match_or_not |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
We break this out to handle the ugliness surrounding dealing with undef values |
147
|
|
|
|
|
|
|
and also to make it easier on subclassers. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=cut |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub match_or_not |
152
|
|
|
|
|
|
|
{ |
153
|
64
|
|
|
64
|
1
|
75
|
my ($self, $data) = @_; |
154
|
64
|
|
|
|
|
137
|
my $match_condition = $self->match_condition; |
155
|
|
|
|
|
|
|
|
156
|
64
|
50
|
|
|
|
445
|
if( !defined $data ) |
|
|
100
|
|
|
|
|
|
157
|
|
|
|
|
|
|
{ |
158
|
0
|
|
|
|
|
0
|
return; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
elsif(my ($item) = ($data=~m/$match_condition/)) |
161
|
|
|
|
|
|
|
{ |
162
|
33
|
|
|
|
|
94
|
return $item; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
31
|
|
|
|
|
77
|
return; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head1 AUTHOR |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Please see L<DBIx::Class::Schema::PopulateMore> For authorship information |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
visit method culled from code in L<Data::Visitor::Lite> which is copyright 2011 Daichi Hiroki <hirokidaichi {at} gmail.com> |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 LICENSE |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Please see L<DBIx::Class::Schema::PopulateMore> For licensing terms. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=cut |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
1; |