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