| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Web::App::Lib::EntityCollection; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
1503
|
use Class::Easy; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
sub entity_collection_from_params { |
|
6
|
0
|
|
|
0
|
0
|
0
|
my $class = shift; |
|
7
|
0
|
|
|
|
|
0
|
my $app = shift; |
|
8
|
0
|
|
|
|
|
0
|
my $params = shift; |
|
9
|
|
|
|
|
|
|
|
|
10
|
0
|
|
|
|
|
0
|
my $entity_type = delete $params->{entity}; |
|
11
|
|
|
|
|
|
|
# deprecated |
|
12
|
0
|
0
|
|
|
|
0
|
$entity_type = delete $params->{entity_type} |
|
13
|
|
|
|
|
|
|
unless defined $entity_type; |
|
14
|
|
|
|
|
|
|
|
|
15
|
0
|
0
|
|
|
|
0
|
critical "no entity type defined by controller param entity(_type)?" |
|
16
|
|
|
|
|
|
|
unless defined $entity_type; |
|
17
|
|
|
|
|
|
|
|
|
18
|
0
|
|
|
|
|
0
|
my $collection_pack = $app->project->collection ($entity_type); |
|
19
|
0
|
|
|
|
|
0
|
my $collection = $collection_pack->new; |
|
20
|
|
|
|
|
|
|
|
|
21
|
0
|
0
|
|
|
|
0
|
if ($params->{fieldset}) { |
|
22
|
0
|
|
|
|
|
0
|
my $method = "fieldset_$params->{fieldset}"; |
|
23
|
0
|
|
|
|
|
0
|
my $record = $collection_pack->record_package; |
|
24
|
0
|
0
|
|
|
|
0
|
critical "can't use fieldset $params->{fieldset} because no ${record}->$method method available" |
|
25
|
|
|
|
|
|
|
unless $record->can ($method); |
|
26
|
0
|
|
|
|
|
0
|
$collection->fieldset ($record->$method); |
|
27
|
|
|
|
|
|
|
} else { |
|
28
|
0
|
|
|
|
|
0
|
my $method = "fieldset_default"; |
|
29
|
0
|
|
|
|
|
0
|
my $record = $collection_pack->record_package; |
|
30
|
0
|
0
|
|
|
|
0
|
$collection->fieldset ($record->$method) |
|
31
|
|
|
|
|
|
|
if $record->can ($method); |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
|
|
34
|
0
|
|
|
|
|
0
|
return $collection; |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub statement_from_params { |
|
38
|
1
|
|
|
1
|
0
|
476
|
my $class = shift; |
|
39
|
1
|
|
|
|
|
2
|
my $app = shift; |
|
40
|
1
|
|
|
|
|
3
|
my $params = shift; |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# allowed: filter.* => where, group_by, sort.(field|order) => sort_(field|order) |
|
43
|
|
|
|
|
|
|
# limit, offset |
|
44
|
|
|
|
|
|
|
|
|
45
|
1
|
|
|
|
|
3
|
my $result = {where => {}}; |
|
46
|
|
|
|
|
|
|
|
|
47
|
1
|
|
|
|
|
5
|
foreach my $k (%$params) { |
|
48
|
8
|
50
|
|
|
|
37
|
if ($k =~ /^group_by$/) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
49
|
0
|
|
|
|
|
0
|
$result->{$k} = $params->{$k} |
|
50
|
|
|
|
|
|
|
} elsif ($k =~ /^sort\.(field|order)$/) { |
|
51
|
2
|
|
|
|
|
7
|
$result->{"sort_$1"} = $params->{$k} |
|
52
|
|
|
|
|
|
|
} elsif ($k =~ /^filter\.(.*)$/) { |
|
53
|
2
|
|
|
|
|
12
|
$result->{where}->{$1} = $params->{$k}; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
1
|
|
|
|
|
3
|
return $result; |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub records { |
|
61
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
|
62
|
|
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
|
my $collection = $class->entity_collection_from_params (@_); |
|
64
|
0
|
|
|
|
|
|
my $statement = $class->statement_from_params (@_); |
|
65
|
|
|
|
|
|
|
|
|
66
|
0
|
|
|
|
|
|
my $list = $collection->records (%$statement); |
|
67
|
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
return $list; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub embed_record { |
|
72
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
|
73
|
|
|
|
|
|
|
|
|
74
|
0
|
|
|
|
|
|
my $collection = $class->entity_collection_from_params (@_); |
|
75
|
0
|
|
|
|
|
|
my $statement = $class->statement_from_params (@_); |
|
76
|
|
|
|
|
|
|
|
|
77
|
0
|
|
|
|
|
|
my $to = $_[1]->{to}; |
|
78
|
0
|
|
|
|
|
|
my $by = $_[1]->{by}; |
|
79
|
0
|
|
|
|
|
|
my $key = $_[1]->{key}; |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# TODO: check for to and by emptiness |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
my $to_ids = {}; |
|
84
|
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
foreach my $rec_to (@$to) { |
|
86
|
|
|
|
|
|
|
# TODO: also check availability of $by in $rec_to |
|
87
|
0
|
|
|
|
|
|
push @{$to_ids->{$rec_to->$by}}, $rec_to; |
|
|
0
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
0
|
0
|
|
|
|
|
return unless scalar keys %$to_ids; |
|
91
|
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
$statement->{where}->{$collection->_pk_} = [keys %$to_ids]; |
|
93
|
|
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
my $list = $collection->records (%$statement); |
|
95
|
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
|
foreach my $rec (@$list) { |
|
97
|
0
|
|
|
|
|
|
my $pk = $rec->_pk_; |
|
98
|
0
|
0
|
|
|
|
|
next unless exists $to_ids->{$rec->$pk}; |
|
99
|
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
|
foreach my $rec_to (@{$to_ids->{$rec->$pk}}) { |
|
|
0
|
|
|
|
|
|
|
|
101
|
0
|
|
|
|
|
|
$rec_to->{$key} = {%$rec}; |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
return; |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub page { |
|
111
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
|
112
|
|
|
|
|
|
|
|
|
113
|
0
|
|
|
|
|
|
my $collection = $class->entity_collection_from_params (@_); |
|
114
|
0
|
|
|
|
|
|
my $statement = $class->statement_from_params (@_); |
|
115
|
|
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
my $app = shift; |
|
117
|
0
|
|
|
|
|
|
my $params = shift; |
|
118
|
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
|
my $count = $collection->count ($statement->{where}); |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# by default i want 20 last records ordered by primary key |
|
122
|
|
|
|
|
|
|
|
|
123
|
0
|
|
0
|
|
|
|
my $page_num = $params->{num} || 1; |
|
124
|
|
|
|
|
|
|
|
|
125
|
0
|
|
0
|
|
|
|
$statement->{limit} = $params->{length} || 20; |
|
126
|
0
|
|
|
|
|
|
$statement->{offset} = ($page_num - 1) * $statement->{limit}; |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Sort field |
|
129
|
0
|
|
0
|
|
|
|
$statement->{sort_field} = $params->{sort_field} || ''; |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# When using LIMIT, it is important to use an ORDER BY clause that |
|
132
|
|
|
|
|
|
|
# constrains the result rows into a unique order. Otherwise you will |
|
133
|
|
|
|
|
|
|
# get an unpredictable subset of the query's rows. You might be asking |
|
134
|
|
|
|
|
|
|
# for the tenth through twentieth rows, but tenth through twentieth |
|
135
|
|
|
|
|
|
|
# in what ordering? The ordering is unknown, unless you specified ORDER BY. |
|
136
|
0
|
0
|
|
|
|
|
$statement->{sort_field} = $collection->_pk_ |
|
137
|
|
|
|
|
|
|
unless $statement->{sort_field}; |
|
138
|
|
|
|
|
|
|
|
|
139
|
0
|
0
|
|
|
|
|
$statement->{sort_order} = 'desc' |
|
140
|
|
|
|
|
|
|
unless $statement->{sort_order}; |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# check for overflow |
|
143
|
0
|
0
|
|
|
|
|
if ($count < $statement->{offset}) { |
|
144
|
|
|
|
|
|
|
# TODO: return 404 |
|
145
|
0
|
|
|
|
|
|
$statement->{offset} = 0; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
0
|
0
|
|
|
|
|
if (300 < $statement->{limit}) { |
|
149
|
|
|
|
|
|
|
# TODO: return 404 |
|
150
|
0
|
|
|
|
|
|
$statement->{limit} = 20; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
|
my $list = $collection->records (%$statement); |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
|
0
|
|
|
|
my $paging = { |
|
156
|
|
|
|
|
|
|
page_size => $statement->{limit}, |
|
157
|
|
|
|
|
|
|
count => $count, |
|
158
|
|
|
|
|
|
|
page_num => $page_num, |
|
159
|
|
|
|
|
|
|
pages_to_show => $params->{pager_size} || 8 |
|
160
|
|
|
|
|
|
|
}; |
|
161
|
|
|
|
|
|
|
|
|
162
|
0
|
|
|
|
|
|
my $pager = $collection->pager ($paging); |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
return { |
|
165
|
0
|
|
|
|
|
|
items => $list, |
|
166
|
|
|
|
|
|
|
total_count => $count, |
|
167
|
|
|
|
|
|
|
version => 1, |
|
168
|
|
|
|
|
|
|
pager => $pager, |
|
169
|
|
|
|
|
|
|
page_size => $statement->{limit}, |
|
170
|
|
|
|
|
|
|
page_num => $page_num, |
|
171
|
|
|
|
|
|
|
}; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
1; |