line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package UR::DataSource::Default; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# NOTE: UR::DataSource::QueryPlan currently has conditional logic for this class |
4
|
|
|
|
|
|
|
|
5
|
210
|
|
|
210
|
|
7153
|
use strict; |
|
210
|
|
|
|
|
300
|
|
|
210
|
|
|
|
|
5702
|
|
6
|
210
|
|
|
210
|
|
744
|
use warnings; |
|
210
|
|
|
|
|
266
|
|
|
210
|
|
|
|
|
4950
|
|
7
|
210
|
|
|
210
|
|
698
|
use UR; |
|
210
|
|
|
|
|
268
|
|
|
210
|
|
|
|
|
1563
|
|
8
|
|
|
|
|
|
|
our $VERSION = "0.46"; # UR $VERSION; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
class UR::DataSource::Default { |
11
|
|
|
|
|
|
|
is => ['UR::DataSource','UR::Singleton'], |
12
|
|
|
|
|
|
|
doc => 'allows the class to describe its own loading strategy' |
13
|
|
|
|
|
|
|
}; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub create_iterator_closure_for_rule { |
17
|
131
|
|
|
131
|
1
|
168
|
my($self,$rule) = @_; |
18
|
|
|
|
|
|
|
|
19
|
131
|
|
|
|
|
311
|
my $subject_class_name = $rule->subject_class_name; |
20
|
131
|
50
|
|
|
|
552
|
unless ($subject_class_name->can('__load__')) { |
21
|
0
|
|
|
|
|
0
|
Carp::croak("Can't load from class $subject_class_name: UR::DataSource::Default requires the class to implement __load__"); |
22
|
|
|
|
|
|
|
} |
23
|
|
|
|
|
|
|
|
24
|
131
|
|
|
|
|
1263
|
my $template = $rule->template; |
25
|
131
|
|
|
|
|
592
|
my ($query_plan) = $self->_resolve_query_plan($template); |
26
|
|
|
|
|
|
|
|
27
|
131
|
|
|
|
|
323
|
my $expected_headers = $query_plan->{loading_templates}[0]{property_names}; |
28
|
131
|
|
|
|
|
537
|
my ($headers, $content) = $subject_class_name->__load__($rule,$expected_headers); |
29
|
|
|
|
|
|
|
|
30
|
128
|
|
|
|
|
3643
|
my $iterator; |
31
|
128
|
100
|
|
|
|
381
|
if (ref($content) eq 'ARRAY') { |
|
|
50
|
|
|
|
|
|
32
|
|
|
|
|
|
|
$iterator = sub { |
33
|
268
|
|
|
268
|
|
387
|
my $next_row = shift @$content; |
34
|
268
|
100
|
|
|
|
579
|
$content = undef if @$content == 0; |
35
|
268
|
|
|
|
|
497
|
return $next_row; |
36
|
124
|
|
|
|
|
544
|
}; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
elsif (ref($content) eq 'CODE') { |
39
|
4
|
|
|
|
|
15
|
$iterator = $content; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
else { |
42
|
0
|
|
|
|
|
0
|
Carp::confess("Expected an arrayref of properties, and then content in the form of an arrayref (rows,columns) or coderef/iterator returning rows from $subject_class_name __load__!\n"); |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
128
|
100
|
|
|
|
592
|
if ("@$headers" ne "@$expected_headers") { |
46
|
|
|
|
|
|
|
# translate the headers into the appropriate order |
47
|
9
|
|
|
|
|
19
|
my @mapping = eval { _map_fields($headers,$expected_headers);}; |
|
9
|
|
|
|
|
43
|
|
48
|
9
|
50
|
|
|
|
23
|
if ($@) { |
49
|
0
|
|
|
|
|
0
|
Carp::croak("Loading data for class $subject_class_name and boolexpr $rule failed: $@"); |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
# print Data::Dumper::Dumper($headers,$expected_headers,\@mapping); |
52
|
9
|
|
|
|
|
11
|
my $orig_iterator = $iterator; |
53
|
|
|
|
|
|
|
$iterator = sub { |
54
|
100026
|
|
|
100026
|
|
131612
|
my $result = $orig_iterator->(); |
55
|
100026
|
100
|
|
|
|
3808862
|
return unless $result; |
56
|
100018
|
|
|
|
|
205786
|
my @result2 = @$result[@mapping]; |
57
|
100018
|
|
|
|
|
192448
|
return \@result2; |
58
|
9
|
|
|
|
|
52
|
}; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
128
|
|
|
|
|
411
|
return $iterator; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
54
|
|
|
54
|
0
|
127
|
sub can_savepoint { 0 } |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub _map_fields { |
67
|
9
|
|
|
9
|
|
15
|
my ($from,$to) = @_; |
68
|
9
|
|
|
|
|
15
|
my $n = 0; |
69
|
9
|
|
|
|
|
26
|
my %from = map { $_ => $n++ } @$from; |
|
34
|
|
|
|
|
82
|
|
70
|
9
|
|
|
|
|
23
|
my @pos; |
71
|
9
|
|
|
|
|
24
|
for my $field (@$to) { |
72
|
35
|
|
|
|
|
37
|
my $pos = $from{$field}; |
73
|
35
|
50
|
|
|
|
56
|
unless (defined $pos) { |
74
|
|
|
|
|
|
|
#print "@$from\n@$to\n" . Carp::longmess() . "\n"; |
75
|
0
|
|
|
|
|
0
|
die("Can't resolve value for '$field' from the headers returned by its __load__: ". join(', ', @$from)); |
76
|
|
|
|
|
|
|
} |
77
|
35
|
|
|
|
|
41
|
push @pos, $pos; |
78
|
|
|
|
|
|
|
} |
79
|
9
|
|
|
|
|
37
|
return @pos; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# Nothing to be done for rollback |
83
|
12
|
|
|
12
|
1
|
42
|
sub rollback { 1;} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
my @saved_objects; |
86
|
|
|
|
|
|
|
sub _sync_database { |
87
|
4
|
|
|
4
|
|
7
|
my $self = shift; |
88
|
4
|
|
|
|
|
8
|
my %params = @_; |
89
|
4
|
|
|
|
|
6
|
my $changed_objects = $params{changed_objects}; |
90
|
|
|
|
|
|
|
|
91
|
4
|
|
|
|
|
8
|
my %class_can_save; |
92
|
4
|
|
|
|
|
6
|
my $err = do { |
93
|
4
|
|
|
|
|
6
|
local $@; |
94
|
4
|
|
|
|
|
6
|
eval { |
95
|
4
|
|
|
|
|
12
|
for my $obj (@$changed_objects) { |
96
|
8
|
|
|
|
|
29
|
my $obj_class = $obj->class; |
97
|
8
|
100
|
|
|
|
20
|
unless (exists $class_can_save{$obj_class}) { |
98
|
5
|
|
|
|
|
33
|
$class_can_save{$obj_class} = $obj->can('__save__'); |
99
|
|
|
|
|
|
|
} |
100
|
8
|
100
|
|
|
|
111
|
if ($class_can_save{$obj_class}) { |
101
|
7
|
|
|
|
|
9
|
push @saved_objects, $obj; |
102
|
7
|
|
|
|
|
16
|
$obj->__save__; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
}; |
106
|
4
|
|
|
|
|
9
|
$@; |
107
|
|
|
|
|
|
|
}; |
108
|
|
|
|
|
|
|
|
109
|
4
|
100
|
|
|
|
11
|
if ($err) { |
110
|
2
|
|
|
|
|
3
|
my @failed_rollback; |
111
|
2
|
|
|
|
|
4
|
do { |
112
|
2
|
|
|
|
|
2
|
my $rollback_error; |
113
|
2
|
|
|
|
|
6
|
while (my $obj = shift @saved_objects) { |
114
|
2
|
|
|
|
|
3
|
local $@; |
115
|
2
|
|
|
|
|
4
|
eval { |
116
|
2
|
|
|
|
|
7
|
$obj->__rollback__; |
117
|
|
|
|
|
|
|
}; |
118
|
2
|
100
|
|
|
|
9
|
if ($@) { |
119
|
1
|
|
|
|
|
3
|
$rollback_error = $@; |
120
|
1
|
|
|
|
|
4
|
push @failed_rollback, $obj; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} |
123
|
2
|
100
|
|
|
|
5
|
if (@failed_rollback) { |
124
|
1
|
|
|
|
|
8
|
$self->error_message('Rollback failed: ' . Data::Dumper::Dumper(\@failed_rollback)); |
125
|
1
|
|
|
|
|
23
|
Carp::croak "Failed to save, and ERRORS DURING ROLLBACK:\n$err\n $rollback_error\n"; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
}; |
128
|
1
|
|
|
|
|
5
|
die $err; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
2
|
|
|
|
|
5
|
return 1; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub commit { |
135
|
45
|
|
|
45
|
1
|
157
|
my @failed_commit; |
136
|
45
|
|
|
|
|
187
|
while (my $obj = shift @saved_objects) { |
137
|
5
|
|
|
|
|
5
|
local $@; |
138
|
5
|
|
|
|
|
4
|
eval { |
139
|
5
|
|
|
|
|
15
|
$obj->__commit__; |
140
|
|
|
|
|
|
|
}; |
141
|
5
|
50
|
|
|
|
16
|
if ($@) { |
142
|
0
|
|
|
|
|
0
|
push @failed_commit, $@ => $obj; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
45
|
50
|
|
|
|
146
|
if (@failed_commit) { |
147
|
0
|
|
|
|
|
0
|
my @failure_messages; |
148
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < @failed_commit; $i += 2) { |
149
|
0
|
|
|
|
|
0
|
my($exception, $obj) = @failed_commit[$i .. $i+1]; |
150
|
0
|
|
|
|
|
0
|
push @failure_messages, "$exception: ".Data::Dumper::Dumper($obj); |
151
|
|
|
|
|
|
|
} |
152
|
0
|
|
|
|
|
0
|
Carp::croak "Commit failed:\n" . join("\n", @failure_messages); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
45
|
|
|
|
|
124
|
return 1; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
1; |
159
|
|
|
|
|
|
|
|