| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package RapidApp::DBIC::Component::TableSpec; |
|
2
|
|
|
|
|
|
|
#use base 'DBIx::Class'; |
|
3
|
|
|
|
|
|
|
# this is for Attribute::Handlers: |
|
4
|
|
|
|
|
|
|
require base; base->import('DBIx::Class'); |
|
5
|
|
|
|
|
|
|
|
|
6
|
5
|
|
|
5
|
|
104205
|
use strict; |
|
|
5
|
|
|
|
|
14
|
|
|
|
5
|
|
|
|
|
138
|
|
|
7
|
5
|
|
|
5
|
|
24
|
use warnings; |
|
|
5
|
|
|
|
|
10
|
|
|
|
5
|
|
|
|
|
141
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
5
|
|
|
5
|
|
663
|
use Sub::Name qw/subname/; |
|
|
5
|
|
|
|
|
504
|
|
|
|
5
|
|
|
|
|
240
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# DBIx::Class Component: ties a RapidApp::TableSpec object to |
|
12
|
|
|
|
|
|
|
# a Result class for use in configuring various modules that |
|
13
|
|
|
|
|
|
|
# consume/use a DBIC Source |
|
14
|
|
|
|
|
|
|
|
|
15
|
5
|
|
|
5
|
|
570
|
use RapidApp::Util qw(:all); |
|
|
5
|
|
|
|
|
15
|
|
|
|
5
|
|
|
|
|
2348
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
5
|
|
|
5
|
|
1749
|
use RapidApp::TableSpec; |
|
|
5
|
|
|
|
|
44
|
|
|
|
5
|
|
|
|
|
207
|
|
|
18
|
5
|
|
|
5
|
|
2407
|
use RapidApp::Module::DbicCombo; |
|
|
5
|
|
|
|
|
20
|
|
|
|
5
|
|
|
|
|
295
|
|
|
19
|
5
|
|
|
5
|
|
34
|
use Module::Runtime; |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
45
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
#__PACKAGE__->load_components(qw/IntrospectableM2M/); |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
__PACKAGE__->load_components('+RapidApp::DBIC::Component::VirtualColumnsExt'); |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
__PACKAGE__->mk_classdata( 'TableSpec' ); |
|
26
|
|
|
|
|
|
|
__PACKAGE__->mk_classdata( 'TableSpec_rel_columns' ); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
__PACKAGE__->mk_classdata( 'TableSpec_cnf' ); |
|
29
|
|
|
|
|
|
|
__PACKAGE__->mk_classdata( 'TableSpec_built_cnf' ); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# See default profile definitions in RapidApp::TableSpec::Column |
|
32
|
|
|
|
|
|
|
my $default_data_type_profiles = { |
|
33
|
|
|
|
|
|
|
text => [ 'bigtext' ], |
|
34
|
|
|
|
|
|
|
mediumtext => [ 'bigtext' ], |
|
35
|
|
|
|
|
|
|
longtext => [ 'bigtext' ], |
|
36
|
|
|
|
|
|
|
tinytext => [ 'text' ], |
|
37
|
|
|
|
|
|
|
smalltext => [ 'text' ], |
|
38
|
|
|
|
|
|
|
varchar => [ 'text' ], |
|
39
|
|
|
|
|
|
|
char => [ 'text' ], |
|
40
|
|
|
|
|
|
|
nvarchar => [ 'text' ], |
|
41
|
|
|
|
|
|
|
nchar => [ 'text' ], |
|
42
|
|
|
|
|
|
|
float => [ 'number' ], |
|
43
|
|
|
|
|
|
|
integer => [ 'number', 'int' ], |
|
44
|
|
|
|
|
|
|
tinyint => [ 'number', 'int' ], |
|
45
|
|
|
|
|
|
|
smallint => [ 'number', 'int' ], |
|
46
|
|
|
|
|
|
|
mediumint => [ 'number', 'int' ], |
|
47
|
|
|
|
|
|
|
bigint => [ 'number', 'int' ], |
|
48
|
|
|
|
|
|
|
decimal => [ 'number' ], |
|
49
|
|
|
|
|
|
|
numeric => [ 'number' ], |
|
50
|
|
|
|
|
|
|
double => [ 'number' ], |
|
51
|
|
|
|
|
|
|
'double precision' => [ 'number' ], |
|
52
|
|
|
|
|
|
|
datetime => [ 'datetime' ], |
|
53
|
|
|
|
|
|
|
timestamp => [ 'datetime' ], |
|
54
|
|
|
|
|
|
|
date => [ 'date' ], |
|
55
|
|
|
|
|
|
|
blob => [ 'blob' ], |
|
56
|
|
|
|
|
|
|
longblob => [ 'blob' ], |
|
57
|
|
|
|
|
|
|
mediumblob => [ 'blob' ], |
|
58
|
|
|
|
|
|
|
tinyblob => [ 'blob' ], |
|
59
|
|
|
|
|
|
|
smallblob => [ 'blob' ], |
|
60
|
|
|
|
|
|
|
binary => [ 'blob' ], |
|
61
|
|
|
|
|
|
|
varbinary => [ 'blob' ], |
|
62
|
|
|
|
|
|
|
year => [ 'otherdate' ], |
|
63
|
|
|
|
|
|
|
tsvector => [ 'bigtext','unsearchable','virtual_source' ], #<-- postgres-specific |
|
64
|
|
|
|
|
|
|
boolean => ['bool'], |
|
65
|
|
|
|
|
|
|
ipaddr => ['unsearchable'] #<-- postgres-specific |
|
66
|
|
|
|
|
|
|
}; |
|
67
|
|
|
|
|
|
|
__PACKAGE__->mk_classdata( 'TableSpec_data_type_profiles' ); |
|
68
|
|
|
|
|
|
|
__PACKAGE__->TableSpec_data_type_profiles({ %$default_data_type_profiles }); |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
## Sets up many_to_many along with TableSpec m2m multi-relationship column |
|
72
|
|
|
|
|
|
|
sub TableSpec_m2m { |
|
73
|
2
|
|
|
2
|
0
|
6
|
my $self = shift; |
|
74
|
2
|
|
|
|
|
6
|
my ($m2m,$local_rel,$remote_rel) = @_; |
|
75
|
|
|
|
|
|
|
|
|
76
|
2
|
50
|
|
|
|
13
|
$self->is_TableSpec_applied and |
|
77
|
|
|
|
|
|
|
die "TableSpec_m2m must be called before apply_TableSpec!"; |
|
78
|
|
|
|
|
|
|
|
|
79
|
2
|
50
|
|
|
|
307
|
$self->has_column($m2m) and die "'$m2m' is already defined as a column."; |
|
80
|
2
|
50
|
|
|
|
214
|
$self->has_relationship($m2m) and die "'$m2m' is already defined as a relationship."; |
|
81
|
|
|
|
|
|
|
|
|
82
|
2
|
50
|
|
|
|
590
|
my $rinfo = $self->relationship_info($local_rel) or die "'$local_rel' relationship not found"; |
|
83
|
2
|
|
|
|
|
197
|
eval('require ' . $rinfo->{class}); |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
die "m2m bridge relationship '$local_rel' is not a multi relationship" |
|
86
|
2
|
50
|
|
|
|
15
|
unless ($rinfo->{attrs}->{accessor} eq 'multi'); |
|
87
|
|
|
|
|
|
|
|
|
88
|
2
|
|
|
|
|
51
|
my $rrinfo = $rinfo->{class}->relationship_info($remote_rel); |
|
89
|
2
|
50
|
|
|
|
97
|
unless($rrinfo) { |
|
90
|
|
|
|
|
|
|
# Note: we're not dying here because this is known to happen when called from Schema::Loader |
|
91
|
|
|
|
|
|
|
# and we don't want that to fail. It is not known to fail during normal operation. TODO/FIXME |
|
92
|
0
|
|
|
|
|
0
|
warn "TableSpec_m2m(): unable to resolve remote rel '$remote_rel' -- falling back to many_to_many\n"; |
|
93
|
0
|
|
|
|
|
0
|
return $self->many_to_many($m2m,$local_rel,$remote_rel); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
2
|
|
|
|
|
10
|
Module::Runtime::require_module($rrinfo->{class}); |
|
97
|
|
|
|
|
|
|
|
|
98
|
2
|
|
|
|
|
60
|
$rinfo->{table} = &_table_name_safe($rinfo->{class}->table); |
|
99
|
2
|
|
|
|
|
19
|
$rrinfo->{table} = &_table_name_safe($rrinfo->{class}->table); |
|
100
|
|
|
|
|
|
|
|
|
101
|
2
|
|
|
|
|
19
|
$rinfo->{cond_info} = $self->parse_relationship_cond($rinfo->{cond}); |
|
102
|
2
|
|
|
|
|
10
|
$rrinfo->{cond_info} = $self->parse_relationship_cond($rrinfo->{cond}); |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# |
|
105
|
|
|
|
|
|
|
#my $sql = '(' . |
|
106
|
|
|
|
|
|
|
# # SQLite Specific: |
|
107
|
|
|
|
|
|
|
# #'SELECT(GROUP_CONCAT(flags.flag,", "))' . |
|
108
|
|
|
|
|
|
|
# |
|
109
|
|
|
|
|
|
|
# # MySQL Sepcific: |
|
110
|
|
|
|
|
|
|
# #'SELECT(GROUP_CONCAT(flags.flag SEPARATOR ", "))' . |
|
111
|
|
|
|
|
|
|
# |
|
112
|
|
|
|
|
|
|
# # Generic (MySQL & SQLite): |
|
113
|
|
|
|
|
|
|
# 'SELECT(GROUP_CONCAT(`' . $rrinfo->{table} . '`.`' . $rrinfo->{cond_info}->{foreign} . '`))' . |
|
114
|
|
|
|
|
|
|
# |
|
115
|
|
|
|
|
|
|
# ' FROM `' . $rinfo->{table} . '`' . |
|
116
|
|
|
|
|
|
|
# ' JOIN `' . $rrinfo->{table} . '` `' . $rrinfo->{table} . '`' . |
|
117
|
|
|
|
|
|
|
# ' ON `' . $rinfo->{table} . '`.`' . $rrinfo->{cond_info}->{self} . '`' . |
|
118
|
|
|
|
|
|
|
# ' = `' . $rrinfo->{table} . '`.`' . $rrinfo->{cond_info}->{foreign} . '`' . |
|
119
|
|
|
|
|
|
|
# #' ON customers_to_flags.flag = flags.flag' . |
|
120
|
|
|
|
|
|
|
# ' WHERE `' . $rinfo->{cond_info}->{foreign} . '` = ' . $rel . '.' . $cond_data->{self} . |
|
121
|
|
|
|
|
|
|
#')'; |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Create a relationship exactly like the the local bridge relationship, adding |
|
124
|
|
|
|
|
|
|
# the 'm2m_attrs' attribute which will be used later on to setup the special, |
|
125
|
|
|
|
|
|
|
# m2m-specific multi-relationship column properties (renderer, editor, and to |
|
126
|
|
|
|
|
|
|
# trigger proxy m2m updates in DbicLink2): |
|
127
|
|
|
|
|
|
|
$self->add_relationship( |
|
128
|
|
|
|
|
|
|
$m2m, |
|
129
|
|
|
|
|
|
|
$rinfo->{class}, |
|
130
|
|
|
|
|
|
|
$rinfo->{cond}, |
|
131
|
2
|
|
|
|
|
7
|
{%{$rinfo->{attrs}}, m2m_attrs => { |
|
|
2
|
|
|
|
|
47
|
|
|
132
|
|
|
|
|
|
|
remote_rel => $remote_rel, |
|
133
|
|
|
|
|
|
|
rinfo => $rinfo, |
|
134
|
|
|
|
|
|
|
rrinfo => $rrinfo |
|
135
|
|
|
|
|
|
|
}} |
|
136
|
|
|
|
|
|
|
); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# -- Add a normal many_to_many bridge so we have the many_to_many sugar later on: |
|
139
|
|
|
|
|
|
|
# (we use 'set_$rel' in update_records in DbicLink2) |
|
140
|
|
|
|
|
|
|
local $ENV{DBIC_OVERWRITE_HELPER_METHODS_OK} = 1 |
|
141
|
2
|
50
|
|
|
|
935
|
unless (exists $ENV{DBIC_OVERWRITE_HELPER_METHODS_OK}); |
|
142
|
2
|
|
|
|
|
28
|
$self->many_to_many(@_); |
|
143
|
|
|
|
|
|
|
#$self->apply_m2m_sugar(@_); |
|
144
|
|
|
|
|
|
|
# -- |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
## sugar copied from many_to_many (DBIx::Class::Relationship::ManyToMany), |
|
148
|
|
|
|
|
|
|
## but only sets up add_$rel and set_$rel and won't overwrite existing subs (safer) |
|
149
|
|
|
|
|
|
|
#sub apply_m2m_sugar { |
|
150
|
|
|
|
|
|
|
# my ($class, $meth, $rel, $f_rel, $rel_attrs) = @_; |
|
151
|
|
|
|
|
|
|
# |
|
152
|
|
|
|
|
|
|
# my $set_meth = "set_${meth}"; |
|
153
|
|
|
|
|
|
|
# my $add_meth = "add_${meth}"; |
|
154
|
|
|
|
|
|
|
# |
|
155
|
|
|
|
|
|
|
# $class->can($set_meth) and |
|
156
|
|
|
|
|
|
|
# die "m2m: set method '$set_meth' is already defined in (" . ref($class) . ")"; |
|
157
|
|
|
|
|
|
|
# |
|
158
|
|
|
|
|
|
|
# $class->can($add_meth) and |
|
159
|
|
|
|
|
|
|
# die "m2m: add method '$add_meth' is already defined in (" . ref($class) . ")"; |
|
160
|
|
|
|
|
|
|
# |
|
161
|
|
|
|
|
|
|
# my $add_meth_name = join '::', $class, $add_meth; |
|
162
|
|
|
|
|
|
|
# *$add_meth_name = subname $add_meth_name, sub { |
|
163
|
|
|
|
|
|
|
# my $self = shift; |
|
164
|
|
|
|
|
|
|
# @_ > 0 or $self->throw_exception( |
|
165
|
|
|
|
|
|
|
# "${add_meth} needs an object or hashref" |
|
166
|
|
|
|
|
|
|
# ); |
|
167
|
|
|
|
|
|
|
# my $source = $self->result_source; |
|
168
|
|
|
|
|
|
|
# my $schema = $source->schema; |
|
169
|
|
|
|
|
|
|
# my $rel_source_name = $source->relationship_info($rel)->{source}; |
|
170
|
|
|
|
|
|
|
# my $rel_source = $schema->resultset($rel_source_name)->result_source; |
|
171
|
|
|
|
|
|
|
# my $f_rel_source_name = $rel_source->relationship_info($f_rel)->{source}; |
|
172
|
|
|
|
|
|
|
# my $f_rel_rs = $schema->resultset($f_rel_source_name)->search({}, $rel_attrs||{}); |
|
173
|
|
|
|
|
|
|
# |
|
174
|
|
|
|
|
|
|
# my $obj; |
|
175
|
|
|
|
|
|
|
# if (ref $_[0]) { |
|
176
|
|
|
|
|
|
|
# if (ref $_[0] eq 'HASH') { |
|
177
|
|
|
|
|
|
|
# $obj = $f_rel_rs->find_or_create($_[0]); |
|
178
|
|
|
|
|
|
|
# } else { |
|
179
|
|
|
|
|
|
|
# $obj = $_[0]; |
|
180
|
|
|
|
|
|
|
# } |
|
181
|
|
|
|
|
|
|
# } else { |
|
182
|
|
|
|
|
|
|
# $obj = $f_rel_rs->find_or_create({@_}); |
|
183
|
|
|
|
|
|
|
# } |
|
184
|
|
|
|
|
|
|
# |
|
185
|
|
|
|
|
|
|
# my $link_vals = @_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {}; |
|
186
|
|
|
|
|
|
|
# my $link = $self->search_related($rel)->new_result($link_vals); |
|
187
|
|
|
|
|
|
|
# $link->set_from_related($f_rel, $obj); |
|
188
|
|
|
|
|
|
|
# $link->insert(); |
|
189
|
|
|
|
|
|
|
# return $obj; |
|
190
|
|
|
|
|
|
|
# }; |
|
191
|
|
|
|
|
|
|
# |
|
192
|
|
|
|
|
|
|
# my $set_meth_name = join '::', $class, $set_meth; |
|
193
|
|
|
|
|
|
|
# *$set_meth_name = subname $set_meth_name, sub { |
|
194
|
|
|
|
|
|
|
# my $self = shift; |
|
195
|
|
|
|
|
|
|
# @_ > 0 or $self->throw_exception( |
|
196
|
|
|
|
|
|
|
# "{$set_meth} needs a list of objects or hashrefs" |
|
197
|
|
|
|
|
|
|
# ); |
|
198
|
|
|
|
|
|
|
# my @to_set = (ref($_[0]) eq 'ARRAY' ? @{ $_[0] } : @_); |
|
199
|
|
|
|
|
|
|
# # if there is a where clause in the attributes, ensure we only delete |
|
200
|
|
|
|
|
|
|
# # rows that are within the where restriction |
|
201
|
|
|
|
|
|
|
# if ($rel_attrs && $rel_attrs->{where}) { |
|
202
|
|
|
|
|
|
|
# $self->search_related( $rel, $rel_attrs->{where},{join => $f_rel})->delete; |
|
203
|
|
|
|
|
|
|
# } else { |
|
204
|
|
|
|
|
|
|
# $self->search_related( $rel, {} )->delete; |
|
205
|
|
|
|
|
|
|
# } |
|
206
|
|
|
|
|
|
|
# # add in the set rel objects |
|
207
|
|
|
|
|
|
|
# $self->$add_meth($_, ref($_[1]) ? $_[1] : {}) for (@to_set); |
|
208
|
|
|
|
|
|
|
# }; |
|
209
|
|
|
|
|
|
|
#} |
|
210
|
|
|
|
|
|
|
## -- |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub is_TableSpec_applied { |
|
213
|
56
|
|
|
56
|
0
|
108
|
my $self = shift; |
|
214
|
|
|
|
|
|
|
return ( |
|
215
|
|
|
|
|
|
|
defined $self->TableSpec_cnf and |
|
216
|
|
|
|
|
|
|
defined $self->TableSpec_cnf->{apply_TableSpec_timestamp} |
|
217
|
56
|
|
33
|
|
|
1300
|
); |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub apply_TableSpec { |
|
221
|
54
|
|
|
54
|
0
|
141
|
my $self = shift; |
|
222
|
54
|
50
|
|
|
|
201
|
my %opt = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
|
0
|
|
|
|
|
0
|
|
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# ignore/return if apply_TableSpec has already been called: |
|
225
|
54
|
50
|
|
|
|
286
|
return if $self->is_TableSpec_applied; |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# make sure _virtual_columns and _virtual_columns_order get initialized |
|
228
|
54
|
|
|
|
|
8548
|
$self->add_virtual_columns(); |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
$self->TableSpec_data_type_profiles( |
|
232
|
0
|
0
|
|
|
|
0
|
%{ $self->TableSpec_data_type_profiles || {} }, |
|
233
|
0
|
|
|
|
|
0
|
%{ delete $opt{TableSpec_data_type_profiles} } |
|
234
|
54
|
50
|
|
|
|
172
|
) if ($opt{TableSpec_data_type_profiles}); |
|
235
|
|
|
|
|
|
|
|
|
236
|
54
|
|
|
|
|
355
|
$self->TableSpec($self->create_result_TableSpec($self,%opt)); |
|
237
|
|
|
|
|
|
|
|
|
238
|
54
|
|
|
|
|
2251
|
$self->TableSpec_rel_columns({}); |
|
239
|
54
|
|
|
|
|
1531
|
$self->TableSpec_cnf({}); |
|
240
|
54
|
|
|
|
|
1568
|
$self->TableSpec_built_cnf(undef); |
|
241
|
|
|
|
|
|
|
|
|
242
|
54
|
|
|
|
|
920
|
$self->apply_row_methods(); |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# Just doing this to ensure we're initialized: |
|
245
|
54
|
|
|
|
|
374
|
$self->TableSpec_set_conf( apply_TableSpec_timestamp => time ); |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# --- Set some base defaults here: |
|
248
|
54
|
|
|
|
|
1068
|
my $table = &_table_name_safe($self->table); |
|
249
|
54
|
|
|
|
|
1609
|
my ($pri) = ($self->primary_columns,$self->columns); #<-- first primary col, or first col |
|
250
|
|
|
|
|
|
|
$self->TableSpec_set_conf( |
|
251
|
|
|
|
|
|
|
display_column => $pri, |
|
252
|
|
|
|
|
|
|
title => $table, |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# -- |
|
255
|
|
|
|
|
|
|
# New: initialize the columns cnf key early. It doesn't even need all |
|
256
|
|
|
|
|
|
|
# the columns (just at least one -- we're just doing the base columns |
|
257
|
|
|
|
|
|
|
# and not bothering with relationships + virtual columns). This is |
|
258
|
|
|
|
|
|
|
# just about getting the Hash defined so that later calls will update |
|
259
|
|
|
|
|
|
|
# this hash rather than create a new one, which can get lost in certain |
|
260
|
|
|
|
|
|
|
# situations (such as a Result Class that loads the TableSpec component |
|
261
|
|
|
|
|
|
|
# in-line but does not apply any column configs). |
|
262
|
|
|
|
|
|
|
# This was needed added after the recent prelim TableSpec_cnf refactor (in v0.99030) |
|
263
|
|
|
|
|
|
|
# which is a temp/in-between change that consolidates storage of column |
|
264
|
|
|
|
|
|
|
# configs internally while still preserving the original API for now. |
|
265
|
|
|
|
|
|
|
# Yes, this is ugly/hackish but will go away as soon as the full-blown, |
|
266
|
|
|
|
|
|
|
# long-planned TableSpec refactor is undertaken... |
|
267
|
54
|
|
|
|
|
840
|
columns => { map { $_ => {} } $self->columns } |
|
|
313
|
|
|
|
|
1346
|
|
|
268
|
|
|
|
|
|
|
# -- |
|
269
|
|
|
|
|
|
|
); |
|
270
|
|
|
|
|
|
|
# --- |
|
271
|
|
|
|
|
|
|
|
|
272
|
54
|
|
|
|
|
2368
|
return $self; |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub create_result_TableSpec { |
|
276
|
54
|
|
|
54
|
0
|
107
|
my $self = shift; |
|
277
|
54
|
|
|
|
|
99
|
my $ResultClass = shift; |
|
278
|
54
|
50
|
|
|
|
219
|
my %opt = (ref($_[0]) eq 'HASH') ? %{ $_[0] } : @_; # <-- arg as hash or hashref |
|
|
0
|
|
|
|
|
0
|
|
|
279
|
|
|
|
|
|
|
|
|
280
|
54
|
|
|
|
|
530
|
my $table = &_table_name_safe($ResultClass->table); |
|
281
|
|
|
|
|
|
|
|
|
282
|
54
|
|
|
|
|
1474
|
my $TableSpec = RapidApp::TableSpec->new( |
|
283
|
|
|
|
|
|
|
name => $table, |
|
284
|
|
|
|
|
|
|
%opt |
|
285
|
|
|
|
|
|
|
); |
|
286
|
|
|
|
|
|
|
|
|
287
|
54
|
|
|
|
|
1091
|
my $data_types = $self->TableSpec_data_type_profiles; |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
## WARNING! This logic overlaps with logic further down (in default_TableSpec_cnf_columns) |
|
290
|
54
|
|
|
|
|
2749
|
foreach my $col ($ResultClass->columns) { |
|
291
|
313
|
|
|
|
|
1827
|
my $info = $ResultClass->column_info($col); |
|
292
|
313
|
|
|
|
|
28930
|
my @profiles = (); |
|
293
|
|
|
|
|
|
|
|
|
294
|
313
|
100
|
|
|
|
883
|
push @profiles, $info->{is_nullable} ? 'nullable' : 'notnull'; |
|
295
|
313
|
100
|
|
|
|
717
|
push @profiles, 'autoinc' if ($info->{is_auto_increment}); |
|
296
|
|
|
|
|
|
|
|
|
297
|
313
|
|
50
|
|
|
797
|
my $type_profile = $data_types->{$info->{data_type}} || ['text']; |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# -- PostgreSQL override until array columns are supported (Github Issue #55): |
|
300
|
|
|
|
|
|
|
$type_profile = ['unsearchable','virtual_source'] if ( |
|
301
|
313
|
50
|
|
|
|
729
|
$info->{data_type} =~ /\[/ #<-- if the data_type contains a square backect, i.e. 'text[]' |
|
302
|
|
|
|
|
|
|
); |
|
303
|
|
|
|
|
|
|
# -- |
|
304
|
|
|
|
|
|
|
|
|
305
|
313
|
50
|
|
|
|
618
|
$type_profile = [ $type_profile ] unless (ref $type_profile); |
|
306
|
313
|
|
|
|
|
557
|
push @profiles, @$type_profile; |
|
307
|
|
|
|
|
|
|
|
|
308
|
313
|
|
|
|
|
1265
|
$TableSpec->add_columns( { name => $col, profiles => \@profiles } ); |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
54
|
|
|
|
|
1396
|
return $TableSpec; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub get_built_Cnf { |
|
316
|
1056
|
|
|
1056
|
0
|
1638
|
my $self = shift; |
|
317
|
|
|
|
|
|
|
|
|
318
|
1056
|
100
|
|
|
|
18723
|
$self->TableSpec_build_cnf unless ($self->TableSpec_built_cnf); |
|
319
|
1056
|
|
|
|
|
43855
|
return $self->TableSpec_built_cnf; |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub TableSpec_build_cnf { |
|
323
|
107
|
|
|
107
|
0
|
20601
|
my $self = shift; |
|
324
|
107
|
50
|
|
|
|
214
|
my %set_cnf = %{ $self->TableSpec_cnf || {} }; |
|
|
107
|
|
|
|
|
2333
|
|
|
325
|
107
|
|
|
|
|
5638
|
$self->TableSpec_built_cnf($self->default_TableSpec_cnf(\%set_cnf)); |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub default_TableSpec_cnf { |
|
329
|
107
|
|
|
107
|
0
|
258
|
my $self = shift; |
|
330
|
107
|
|
50
|
|
|
305
|
my $set = shift || {}; |
|
331
|
|
|
|
|
|
|
|
|
332
|
107
|
|
|
|
|
192
|
my $data = $set; |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
|
|
335
|
107
|
|
|
|
|
763
|
my $table = &_table_name_safe($self->table); |
|
336
|
|
|
|
|
|
|
|
|
337
|
107
|
|
|
|
|
591
|
my $is_virtual = $self->_is_virtual_source; |
|
338
|
107
|
50
|
|
|
|
2168
|
my $defs_i = $is_virtual ? 'ra-icon-pg-red' : 'ra-icon-pg'; |
|
339
|
107
|
50
|
|
|
|
278
|
my $defm_i = $is_virtual ? 'ra-icon-pg-multi-red' : 'ra-icon-pg-multi'; |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# FIXME: These defaults cannot be seen via call from related tablespec, because of |
|
342
|
|
|
|
|
|
|
# a circular logic situation. For base-defaults, see apply_TableSpec above |
|
343
|
|
|
|
|
|
|
# This is one of the reasons the whole TableSpec design needs to be refactored |
|
344
|
107
|
|
|
|
|
231
|
my %defaults = (); |
|
345
|
107
|
50
|
33
|
|
|
409
|
$defaults{iconCls} = $data->{singleIconCls} if ($data->{singleIconCls} and ! $data->{iconCls}); |
|
346
|
107
|
|
66
|
|
|
667
|
$defaults{iconCls} = $defaults{iconCls} || $data->{iconCls} || $defs_i; |
|
347
|
107
|
|
66
|
|
|
349
|
$defaults{multiIconCls} = $data->{multiIconCls} || $defm_i; |
|
348
|
107
|
|
33
|
|
|
533
|
$defaults{singleIconCls} = $data->{singleIconCls} || $defaults{iconCls}; |
|
349
|
107
|
|
33
|
|
|
371
|
$defaults{title} = $data->{title} || $table; |
|
350
|
107
|
|
33
|
|
|
467
|
$defaults{title_multi} = $data->{title_multi} || $defaults{title}; |
|
351
|
107
|
|
|
|
|
2720
|
($defaults{display_column}) = $self->primary_columns; |
|
352
|
|
|
|
|
|
|
|
|
353
|
107
|
50
|
|
|
|
4628
|
my @display_columns = $data->{display_column} ? ( $data->{display_column} ) : $self->primary_columns; |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# row_display coderef overrides display_column to provide finer grained display control |
|
356
|
|
|
|
|
|
|
my $orig_row_display = $data->{row_display} || sub { |
|
357
|
0
|
|
|
0
|
|
0
|
my $record = $_; |
|
358
|
0
|
|
|
|
|
0
|
my $title = join('/',map { $record->{$_} || '' } @display_columns); |
|
|
0
|
|
|
|
|
0
|
|
|
359
|
0
|
|
|
|
|
0
|
$title = sprintf('%.13s',$title) . '...' if (length $title > 13); |
|
360
|
0
|
|
|
|
|
0
|
return $title; |
|
361
|
107
|
|
50
|
|
|
866
|
}; |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
$defaults{row_display} = sub { |
|
364
|
0
|
|
|
0
|
|
0
|
my $display = $orig_row_display->(@_); |
|
365
|
0
|
0
|
|
|
|
0
|
return $display if (ref $display); |
|
366
|
|
|
|
|
|
|
return { |
|
367
|
|
|
|
|
|
|
title => $display, |
|
368
|
|
|
|
|
|
|
iconCls => $defaults{singleIconCls} |
|
369
|
0
|
|
|
|
|
0
|
}; |
|
370
|
107
|
|
|
|
|
563
|
}; |
|
371
|
|
|
|
|
|
|
|
|
372
|
107
|
|
|
|
|
278
|
my $rel_trans = {}; |
|
373
|
|
|
|
|
|
|
|
|
374
|
107
|
|
|
|
|
306
|
$defaults{related_column_property_transforms} = $rel_trans; |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
#my $defs = \%defaults; |
|
378
|
|
|
|
|
|
|
#my $col_cnf = $self->default_TableSpec_cnf_columns($set); |
|
379
|
|
|
|
|
|
|
#$defs = merge($defs,$col_cnf); |
|
380
|
|
|
|
|
|
|
#return merge($defs, $set); |
|
381
|
|
|
|
|
|
|
|
|
382
|
107
|
|
|
|
|
1588
|
%defaults = ( %defaults, %$set ); |
|
383
|
107
|
|
|
|
|
378
|
my $defs = \%defaults; |
|
384
|
107
|
|
|
|
|
666
|
my $col_cnf = $self->default_TableSpec_cnf_columns($defs); |
|
385
|
107
|
|
|
|
|
259
|
$defs->{columns} = $col_cnf->{columns}; |
|
386
|
|
|
|
|
|
|
|
|
387
|
107
|
|
|
|
|
2325
|
return $defs; |
|
388
|
|
|
|
|
|
|
} |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
sub _is_virtual_source { |
|
391
|
258
|
|
|
258
|
|
516
|
my $self = shift; |
|
392
|
|
|
|
|
|
|
return ( |
|
393
|
258
|
|
33
|
|
|
4591
|
$self->result_source_instance->can('is_virtual') && |
|
394
|
|
|
|
|
|
|
$self->result_source_instance->is_virtual |
|
395
|
|
|
|
|
|
|
); |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
sub default_TableSpec_cnf_columns { |
|
399
|
107
|
|
|
107
|
0
|
242
|
my $self = shift; |
|
400
|
107
|
|
50
|
|
|
329
|
my $set = shift || {}; |
|
401
|
|
|
|
|
|
|
|
|
402
|
107
|
|
|
|
|
171
|
my $data = $set; |
|
403
|
|
|
|
|
|
|
|
|
404
|
107
|
|
|
|
|
595
|
my @col_order = $self->default_TableSpec_cnf_column_order($set); |
|
405
|
|
|
|
|
|
|
|
|
406
|
107
|
|
|
|
|
258
|
my $cols = { map { $_ => {} } @col_order }; |
|
|
672
|
|
|
|
|
1241
|
|
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
# lowest precidence: |
|
409
|
|
|
|
|
|
|
#$cols = merge($cols,$set->{column_properties_defaults} || {}); |
|
410
|
107
|
50
|
|
|
|
430
|
%$cols = ( %$cols, %{ $set->{column_properties_defaults} || {}} ); |
|
|
107
|
|
|
|
|
9094
|
|
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
#$cols = merge($cols,$set->{column_properties_ordered} || {}); |
|
413
|
107
|
50
|
|
|
|
380
|
%$cols = ( %$cols, %{ $set->{column_properties_ordered} || {}} ); |
|
|
107
|
|
|
|
|
560
|
|
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# higher precidence: |
|
416
|
|
|
|
|
|
|
#$cols = merge($cols,$set->{column_properties} || {}); |
|
417
|
107
|
50
|
|
|
|
311
|
%$cols = ( %$cols, %{ $set->{column_properties} || {}} ); |
|
|
107
|
|
|
|
|
542
|
|
|
418
|
|
|
|
|
|
|
|
|
419
|
107
|
|
|
|
|
2614
|
my $data_types = $self->TableSpec_data_type_profiles; |
|
420
|
|
|
|
|
|
|
#scream(keys %$cols); |
|
421
|
|
|
|
|
|
|
|
|
422
|
107
|
|
|
|
|
4452
|
my $is_virtual = $self->_is_virtual_source; |
|
423
|
|
|
|
|
|
|
|
|
424
|
107
|
|
|
|
|
1996
|
foreach my $col (keys %$cols) { |
|
425
|
|
|
|
|
|
|
|
|
426
|
672
|
100
|
|
|
|
2380
|
my $is_phy = $self->has_column($col) ? 1 : 0; |
|
427
|
672
|
|
|
|
|
54870
|
$cols->{$col}{is_phy_colname} = $is_phy; #<-- track if this is also a physical column name |
|
428
|
|
|
|
|
|
|
|
|
429
|
672
|
|
|
|
|
958
|
my $is_local = $is_phy; |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# If this is both a local column and a relationship, allow the rel to take over |
|
432
|
|
|
|
|
|
|
# if 'priority_rel_columns' is true: |
|
433
|
|
|
|
|
|
|
$is_local = 0 if ( |
|
434
|
|
|
|
|
|
|
$is_local and |
|
435
|
|
|
|
|
|
|
$self->has_relationship($col) and |
|
436
|
672
|
50
|
100
|
|
|
9518
|
$set->{'priority_rel_columns'} |
|
|
|
|
66
|
|
|
|
|
|
437
|
|
|
|
|
|
|
); |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# -- If priority_rel_columns is on but we need to exclude a specific column: |
|
440
|
|
|
|
|
|
|
$is_local = 1 if ( |
|
441
|
|
|
|
|
|
|
! $is_local and |
|
442
|
|
|
|
|
|
|
$set->{no_priority_rel_column} and |
|
443
|
672
|
0
|
66
|
|
|
21563
|
$set->{no_priority_rel_column}->{$col} and |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
444
|
|
|
|
|
|
|
$is_phy |
|
445
|
|
|
|
|
|
|
); |
|
446
|
|
|
|
|
|
|
# -- |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# Never allow a rel col to take over a primary key: |
|
449
|
672
|
|
|
|
|
9879
|
my %pri_cols = map {$_=>1} $self->primary_columns; |
|
|
685
|
|
|
|
|
22872
|
|
|
450
|
672
|
100
|
|
|
|
1750
|
$is_local = 1 if ($pri_cols{$col}); |
|
451
|
|
|
|
|
|
|
|
|
452
|
672
|
100
|
|
|
|
1325
|
unless ($is_local) { |
|
453
|
|
|
|
|
|
|
# is it a rel col ? |
|
454
|
172
|
50
|
|
|
|
2781
|
if($self->has_relationship($col)) { |
|
455
|
172
|
|
|
|
|
8463
|
my $info = $self->relationship_info($col); |
|
456
|
|
|
|
|
|
|
|
|
457
|
172
|
|
|
|
|
5298
|
$cols->{$col}->{relationship_info} = $info; |
|
458
|
172
|
|
|
|
|
664
|
my $cond_data = $self->parse_relationship_cond($info->{cond}); |
|
459
|
172
|
|
|
|
|
1255
|
$cols->{$col}->{relationship_cond_data} = { %$cond_data, %$info }; |
|
460
|
|
|
|
|
|
|
|
|
461
|
172
|
100
|
100
|
|
|
1266
|
if ($info->{attrs}->{accessor} eq 'single' || $info->{attrs}->{accessor} eq 'filter') { |
|
|
|
50
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
# -- NEW: Virtual Single Relationship - will be read-only |
|
464
|
67
|
50
|
33
|
|
|
351
|
unless($cond_data->{foreign} && $cond_data->{self}) { |
|
465
|
0
|
|
|
|
|
0
|
$cols->{$col}{virtualized_single_rel} = 1; |
|
466
|
0
|
|
|
|
|
0
|
$cols->{$col}{allow_add} = 0; |
|
467
|
0
|
|
|
|
|
0
|
$cols->{$col}{allow_edit} = 0; |
|
468
|
0
|
|
|
|
|
0
|
next; |
|
469
|
|
|
|
|
|
|
} |
|
470
|
|
|
|
|
|
|
# -- |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
# New: pass the is_nullable flag in from the local FK column: |
|
473
|
67
|
50
|
|
|
|
253
|
if($self->has_column($cond_data->{self})) { |
|
474
|
|
|
|
|
|
|
$cols->{$col}{is_nullable} = $self->column_info($cond_data->{self}) |
|
475
|
67
|
100
|
|
|
|
5624
|
->{is_nullable} ? 1 : 0; |
|
476
|
|
|
|
|
|
|
} |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# Use TableSpec_related_get_set_conf instead of TableSpec_related_get_conf |
|
479
|
|
|
|
|
|
|
# to prevent possible deep recursion: |
|
480
|
|
|
|
|
|
|
|
|
481
|
67
|
|
|
|
|
5867
|
my $display_column = $self->TableSpec_related_get_set_conf($col,'display_column'); |
|
482
|
67
|
|
|
|
|
201
|
my $display_columns = $self->TableSpec_related_get_set_conf($col,'display_columns'); |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# -- auto_editor_params/auto_editor_type can be defined in either the local column |
|
485
|
|
|
|
|
|
|
# properties, or the remote TableSpec conf |
|
486
|
67
|
|
100
|
|
|
193
|
my $auto_editor_type = $self->TableSpec_related_get_set_conf($col,'auto_editor_type') || 'combo'; |
|
487
|
67
|
|
100
|
|
|
207
|
my $auto_editor_params = $self->TableSpec_related_get_set_conf($col,'auto_editor_params') || {}; |
|
488
|
67
|
|
50
|
|
|
215
|
my $auto_editor_win_params = $self->TableSpec_related_get_set_conf($col,'auto_editor_win_params') || {}; |
|
489
|
67
|
|
66
|
|
|
297
|
$cols->{$col}->{auto_editor_type} = $cols->{$col}->{auto_editor_type} || $auto_editor_type; |
|
490
|
67
|
|
100
|
|
|
305
|
$cols->{$col}->{auto_editor_params} = $cols->{$col}->{auto_editor_params} || {}; |
|
491
|
|
|
|
|
|
|
$cols->{$col}->{auto_editor_params} = { |
|
492
|
|
|
|
|
|
|
%$auto_editor_params, |
|
493
|
67
|
|
|
|
|
292
|
%{$cols->{$col}->{auto_editor_params}} |
|
|
67
|
|
|
|
|
315
|
|
|
494
|
|
|
|
|
|
|
}; |
|
495
|
|
|
|
|
|
|
# -- |
|
496
|
|
|
|
|
|
|
|
|
497
|
67
|
0
|
33
|
|
|
319
|
$display_column = $display_columns->[0] if ( |
|
|
|
|
33
|
|
|
|
|
|
498
|
|
|
|
|
|
|
! defined $display_column and |
|
499
|
|
|
|
|
|
|
ref($display_columns) eq 'ARRAY' and |
|
500
|
|
|
|
|
|
|
@$display_columns > 0 |
|
501
|
|
|
|
|
|
|
); |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
## fall-back set the display_column to the first key |
|
504
|
67
|
50
|
|
|
|
166
|
($display_column) = $self->primary_columns unless ($display_column); |
|
505
|
|
|
|
|
|
|
|
|
506
|
67
|
50
|
33
|
|
|
323
|
$display_columns = [ $display_column ] if ( |
|
507
|
|
|
|
|
|
|
! defined $display_columns and |
|
508
|
|
|
|
|
|
|
defined $display_column |
|
509
|
|
|
|
|
|
|
); |
|
510
|
|
|
|
|
|
|
|
|
511
|
67
|
50
|
|
|
|
177
|
die "$col doesn't have display_column or display_columns set!" unless ($display_column); |
|
512
|
|
|
|
|
|
|
|
|
513
|
67
|
|
|
|
|
174
|
$cols->{$col}->{displayField} = $display_column; |
|
514
|
67
|
|
|
|
|
174
|
$cols->{$col}->{display_columns} = $display_columns; #<-- in progress - used for grid instead of combo |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
#TODO: needs to be more generalized/abstracted |
|
517
|
|
|
|
|
|
|
#open_url, if defined, will add an autoLoad link to the renderer to |
|
518
|
|
|
|
|
|
|
#open/navigate to the related item |
|
519
|
67
|
|
|
|
|
190
|
$cols->{$col}->{open_url} = $self->TableSpec_related_get_set_conf($col,'open_url'); |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
$cols->{$col}->{valueField} = $cond_data->{foreign} |
|
522
|
67
|
50
|
|
|
|
231
|
or die "couldn't get foreign col condition data for $col relationship!"; |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
$cols->{$col}->{keyField} = $cond_data->{self} |
|
525
|
67
|
50
|
|
|
|
236
|
or die "couldn't get self col condition data for $col relationship!"; |
|
526
|
|
|
|
|
|
|
|
|
527
|
67
|
|
|
|
|
291
|
next; |
|
528
|
|
|
|
|
|
|
} |
|
529
|
|
|
|
|
|
|
elsif($info->{attrs}->{accessor} eq 'multi') { |
|
530
|
105
|
|
|
|
|
510
|
$cols->{$col}->{title_multi} = $self->TableSpec_related_get_set_conf($col,'title_multi'); |
|
531
|
105
|
|
|
|
|
336
|
$cols->{$col}->{multiIconCls} = $self->TableSpec_related_get_set_conf($col,'multiIconCls'); |
|
532
|
105
|
|
|
|
|
337
|
$cols->{$col}->{open_url_multi} = $self->TableSpec_related_get_set_conf($col,'open_url_multi'); |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
$cols->{$col}->{open_url_multi_rs_join_name} = |
|
535
|
105
|
|
50
|
|
|
331
|
$self->TableSpec_related_get_set_conf($col,'open_url_multi_rs_join_name') || 'me'; |
|
536
|
|
|
|
|
|
|
} |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# New: add the 'relcol' profile to relationship columns: |
|
539
|
105
|
|
100
|
|
|
498
|
$cols->{$col}->{profiles} ||= []; |
|
540
|
105
|
|
|
|
|
218
|
push @{$cols->{$col}->{profiles}}, 'relcol'; |
|
|
105
|
|
|
|
|
402
|
|
|
541
|
105
|
50
|
|
|
|
281
|
push @{$cols->{$col}->{profiles}}, 'virtual_source' if ($is_virtual); |
|
|
0
|
|
|
|
|
0
|
|
|
542
|
105
|
50
|
|
|
|
420
|
push @{$cols->{$col}->{profiles}}, 'multirel' if ($info->{attrs}->{accessor} eq 'multi'); |
|
|
105
|
|
|
|
|
415
|
|
|
543
|
|
|
|
|
|
|
} |
|
544
|
105
|
|
|
|
|
316
|
next; |
|
545
|
|
|
|
|
|
|
} |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
## WARNING! This logic overlaps with logic further up (in create_result_TableSpec) FIXME! |
|
548
|
500
|
|
|
|
|
1772
|
my $info = $self->column_info($col); |
|
549
|
500
|
|
|
|
|
41912
|
my @profiles = (); |
|
550
|
|
|
|
|
|
|
|
|
551
|
500
|
100
|
|
|
|
1543
|
push @profiles, $info->{is_nullable} ? 'nullable' : 'notnull'; |
|
552
|
500
|
100
|
|
|
|
1222
|
push @profiles, 'autoinc' if ($info->{is_auto_increment}); |
|
553
|
|
|
|
|
|
|
|
|
554
|
500
|
|
50
|
|
|
1384
|
my $type_profile = $data_types->{$info->{data_type}} || ['text']; |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# -- PostgreSQL override until array columns are supported (Github Issue #55): |
|
557
|
|
|
|
|
|
|
$type_profile = ['unsearchable','virtual_source'] if ( |
|
558
|
500
|
50
|
|
|
|
1366
|
$info->{data_type} =~ /\[/ #<-- if the data_type contains a square backect, i.e. 'text[]' |
|
559
|
|
|
|
|
|
|
); |
|
560
|
|
|
|
|
|
|
# -- |
|
561
|
|
|
|
|
|
|
|
|
562
|
500
|
50
|
|
|
|
1102
|
$type_profile = [ $type_profile ] unless (ref $type_profile); |
|
563
|
500
|
|
|
|
|
983
|
push @profiles, @$type_profile; |
|
564
|
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
$cols->{$col}->{profiles} = [ $cols->{$col}->{profiles} ] if ( |
|
566
|
|
|
|
|
|
|
defined $cols->{$col}->{profiles} and |
|
567
|
|
|
|
|
|
|
not ref $cols->{$col}->{profiles} |
|
568
|
500
|
50
|
66
|
|
|
1991
|
); |
|
569
|
500
|
100
|
|
|
|
1089
|
push @profiles, @{$cols->{$col}->{profiles}} if ($cols->{$col}->{profiles}); |
|
|
250
|
|
|
|
|
842
|
|
|
570
|
|
|
|
|
|
|
|
|
571
|
500
|
50
|
|
|
|
962
|
push @profiles, 'virtual_source' if ($is_virtual); |
|
572
|
|
|
|
|
|
|
|
|
573
|
500
|
|
|
|
|
997
|
$cols->{$col}->{profiles} = \@profiles; |
|
574
|
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
## -- |
|
576
|
500
|
|
|
|
|
750
|
my $editor = {}; |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
## Set the 'default' field value to match the default from the db (if exists) for this column: |
|
579
|
500
|
100
|
|
|
|
1040
|
$editor->{value} = $info->{default_value} if (exists $info->{default_value}); |
|
580
|
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
# -- NEW: |
|
582
|
|
|
|
|
|
|
# ScalarRef values mean literal SQL which should be evaluated at the time. New feature in |
|
583
|
|
|
|
|
|
|
# RapidApp::JSON::MixedEncoder supports CodeRef values, which call them at encode time. This |
|
584
|
|
|
|
|
|
|
# lets us set the default editor value to what it should be at the time the form is loaded. |
|
585
|
500
|
50
|
50
|
|
|
1769
|
if((ref($info->{default_value})||'') eq 'SCALAR') { |
|
586
|
|
|
|
|
|
|
$editor->{value} = sub { |
|
587
|
0
|
|
|
0
|
|
0
|
my $value = $info->{default_value}; |
|
588
|
|
|
|
|
|
|
try { |
|
589
|
|
|
|
|
|
|
# Actually ask the database via calling a select on the literal SQL. We're in a try |
|
590
|
|
|
|
|
|
|
# block so if any of this fails, we fall back to the original ScalarRef which will |
|
591
|
|
|
|
|
|
|
# probably end up being undef |
|
592
|
|
|
|
|
|
|
$value = RapidApp->active_request_context |
|
593
|
0
|
|
|
|
|
0
|
->stash->{'RAPIDAPP_DISPATCH_MODULE'} # only way to get Module by the time we're called in the view |
|
594
|
|
|
|
|
|
|
->ResultSource->schema->storage->dbh |
|
595
|
|
|
|
|
|
|
->selectrow_arrayref( "SELECT $$value" )->[0]; |
|
596
|
0
|
|
|
|
|
0
|
}; |
|
597
|
0
|
|
|
|
|
0
|
return $value; |
|
598
|
|
|
|
|
|
|
} unless ( |
|
599
|
|
|
|
|
|
|
# just because this one is so common, don't waste resources asking the database |
|
600
|
0
|
0
|
|
|
|
0
|
${$info->{default_value}} eq 'null' |
|
|
0
|
|
|
|
|
0
|
|
|
601
|
|
|
|
|
|
|
); |
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
# -- |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
## This sets additional properties of the editor for numeric type columns according |
|
607
|
|
|
|
|
|
|
## to the DBIC schema (max-length, signed/unsigned, float vs int). The API with "profiles" |
|
608
|
|
|
|
|
|
|
## didn't anticipate this fine-grained need, so 'extra_properties' was added specifically |
|
609
|
|
|
|
|
|
|
## to accomidate this (see special logic in TableSpec::Column): |
|
610
|
|
|
|
|
|
|
## note: these properties only apply if the editor xtype is 'numberfield' which we assume, |
|
611
|
|
|
|
|
|
|
## and is already set from the profiles of 'decimal', 'float', etc |
|
612
|
500
|
100
|
66
|
|
|
1387
|
my $unsigned = ($info->{extra} && $info->{extra}->{unsigned}) ? 1 : 0; |
|
613
|
500
|
100
|
|
|
|
832
|
$editor->{allowNegative} = \0 if ($unsigned); |
|
614
|
|
|
|
|
|
|
|
|
615
|
500
|
100
|
|
|
|
1044
|
if($info->{size}) { |
|
616
|
336
|
|
|
|
|
530
|
my $size = $info->{size}; |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
# Special case for 'float'/'decimal' with a specified precision (where 0 is the same as int): |
|
619
|
336
|
100
|
|
|
|
685
|
if(ref $size eq 'ARRAY' ) { |
|
620
|
12
|
|
|
|
|
50
|
my ($s,$p) = @$size; |
|
621
|
12
|
|
|
|
|
33
|
$size = $s; |
|
622
|
12
|
|
|
|
|
48
|
$editor->{maxValue} = ('9' x $s); |
|
623
|
12
|
50
|
|
|
|
39
|
$size += 1 unless ($unsigned); #<-- room for a '-' |
|
624
|
12
|
50
|
33
|
|
|
68
|
if ($p && $p > 0) { |
|
625
|
12
|
|
|
|
|
49
|
$editor->{maxValue} .= '.' . ('9' x $p); |
|
626
|
12
|
|
|
|
|
27
|
$size += $p + 1 ; #<-- precision plus a spot for '.' in the max field length |
|
627
|
12
|
|
|
|
|
31
|
$editor->{decimalPrecision} = $p; |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
else { |
|
630
|
0
|
|
|
|
|
0
|
$editor->{allowDecimals} = \0; |
|
631
|
|
|
|
|
|
|
} |
|
632
|
|
|
|
|
|
|
} |
|
633
|
336
|
|
|
|
|
677
|
$editor->{maxLength} = $size; |
|
634
|
|
|
|
|
|
|
} |
|
635
|
|
|
|
|
|
|
|
|
636
|
500
|
100
|
|
|
|
1287
|
if(keys %$editor > 0) { |
|
637
|
353
|
|
100
|
|
|
1096
|
$cols->{$col}->{extra_properties} = $cols->{$col}->{extra_properties} || {}; |
|
638
|
|
|
|
|
|
|
$cols->{$col}->{extra_properties} = merge($cols->{$col}->{extra_properties},{ |
|
639
|
353
|
|
|
|
|
1483
|
editor => $editor |
|
640
|
|
|
|
|
|
|
}); |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
## -- |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
# --vv-- NEW: handling for 'enum' columns (Github Issue #30): |
|
645
|
500
|
0
|
33
|
|
|
1859
|
if($info->{data_type} eq 'enum' && $info->{extra} && $info->{extra}{list}) { |
|
|
|
|
0
|
|
|
|
|
|
646
|
0
|
|
|
|
|
0
|
my $list = $info->{extra}{list}; |
|
647
|
|
|
|
|
|
|
|
|
648
|
0
|
|
|
|
|
0
|
my $selections = []; |
|
649
|
|
|
|
|
|
|
# Null choice: |
|
650
|
|
|
|
|
|
|
push @$selections, { |
|
651
|
|
|
|
|
|
|
# #A9A9A9 = light grey |
|
652
|
|
|
|
|
|
|
text => '<span style="color:#A9A9A9;">(None)</span>', value => undef |
|
653
|
0
|
0
|
|
|
|
0
|
} if ($info->{is_nullable}); |
|
654
|
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
push @$selections, map { |
|
656
|
0
|
|
|
|
|
0
|
{ text => $_, value => $_ } |
|
|
0
|
|
|
|
|
0
|
|
|
657
|
|
|
|
|
|
|
} @$list; |
|
658
|
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
$cols->{$col}{menu_select_editor} = { |
|
660
|
|
|
|
|
|
|
#mode: 'combo', 'menu' or 'cycle': |
|
661
|
0
|
|
|
|
|
0
|
mode => 'menu', |
|
662
|
|
|
|
|
|
|
selections => $selections |
|
663
|
|
|
|
|
|
|
}; |
|
664
|
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
# New: also save the list of possible values in a hashref... |
|
666
|
|
|
|
|
|
|
# This is being done so that they can be pre-validated in |
|
667
|
|
|
|
|
|
|
# quick search, needed for Postfix (Github Issue #56) |
|
668
|
|
|
|
|
|
|
# TODO: not happy about having to do this - revisit later |
|
669
|
0
|
|
|
|
|
0
|
$cols->{$col}{enum_value_hash} = { map {$_=>1} @$list } |
|
|
0
|
|
|
|
|
0
|
|
|
670
|
|
|
|
|
|
|
} |
|
671
|
|
|
|
|
|
|
# --^^-- |
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
} |
|
674
|
|
|
|
|
|
|
|
|
675
|
107
|
|
|
|
|
507
|
return { columns => $cols }; |
|
676
|
|
|
|
|
|
|
} |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
sub TableSpec_valid_db_columns { |
|
679
|
306
|
|
|
306
|
0
|
593
|
my $self = shift; |
|
680
|
|
|
|
|
|
|
|
|
681
|
306
|
|
|
|
|
604
|
my @single_rels = (); |
|
682
|
306
|
|
|
|
|
524
|
my @multi_rels = (); |
|
683
|
306
|
|
|
|
|
550
|
my @virtual_single_rels = (); |
|
684
|
|
|
|
|
|
|
|
|
685
|
306
|
|
|
|
|
571
|
my %fk_cols = (); |
|
686
|
306
|
|
|
|
|
5354
|
my %pri_cols = map {$_=>1} $self->primary_columns; |
|
|
331
|
|
|
|
|
12210
|
|
|
687
|
|
|
|
|
|
|
|
|
688
|
306
|
|
|
|
|
7398
|
foreach my $rel ($self->relationships) { |
|
689
|
585
|
|
|
|
|
22553
|
my $info = $self->relationship_info($rel); |
|
690
|
|
|
|
|
|
|
|
|
691
|
585
|
|
|
|
|
19663
|
my $accessor = $info->{attrs}->{accessor}; |
|
692
|
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
# 'filter' means single, but the name is also a local column |
|
694
|
|
|
|
|
|
|
$accessor = 'single' if ( |
|
695
|
|
|
|
|
|
|
$accessor eq 'filter' and |
|
696
|
|
|
|
|
|
|
$self->TableSpec_cnf->{'priority_rel_columns'} and |
|
697
|
|
|
|
|
|
|
!( |
|
698
|
|
|
|
|
|
|
$self->TableSpec_cnf->{'no_priority_rel_column'} and |
|
699
|
|
|
|
|
|
|
$self->TableSpec_cnf->{'no_priority_rel_column'}->{$rel} |
|
700
|
|
|
|
|
|
|
) and |
|
701
|
585
|
100
|
100
|
|
|
5532
|
! $pri_cols{$rel} #<-- exclude primary column names. TODO: this check is performed later, fix |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
702
|
|
|
|
|
|
|
); |
|
703
|
|
|
|
|
|
|
|
|
704
|
585
|
100
|
|
|
|
16223
|
if($accessor eq 'single') { |
|
|
|
100
|
|
|
|
|
|
|
705
|
191
|
|
|
|
|
836
|
my $cond_info = $self->parse_relationship_cond($info->{cond}); |
|
706
|
191
|
50
|
33
|
|
|
820
|
if($cond_info->{self} && $cond_info->{foreign}) { |
|
707
|
191
|
|
|
|
|
441
|
push @single_rels, $rel; |
|
708
|
191
|
|
|
|
|
356
|
my ($fk) = keys %{$info->{attrs}->{fk_columns}}; |
|
|
191
|
|
|
|
|
614
|
|
|
709
|
191
|
100
|
|
|
|
690
|
$fk_cols{$fk} = $rel if($fk); |
|
710
|
|
|
|
|
|
|
} |
|
711
|
|
|
|
|
|
|
else { |
|
712
|
|
|
|
|
|
|
# (Github Issue #40) |
|
713
|
|
|
|
|
|
|
# New: "virtual" single rels are relationships for which we |
|
714
|
|
|
|
|
|
|
# cannot introspect in both directions (i.e. not physical |
|
715
|
|
|
|
|
|
|
# foreign keys). These are still "single" in that they map to |
|
716
|
|
|
|
|
|
|
# one related row, but will not be editable and not have a |
|
717
|
|
|
|
|
|
|
# open link (yet) |
|
718
|
0
|
|
|
|
|
0
|
push @virtual_single_rels, $rel; |
|
719
|
|
|
|
|
|
|
} |
|
720
|
|
|
|
|
|
|
} |
|
721
|
|
|
|
|
|
|
elsif($accessor eq 'multi') { |
|
722
|
309
|
|
|
|
|
855
|
push @multi_rels, $rel; |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
} |
|
725
|
|
|
|
|
|
|
|
|
726
|
306
|
|
|
|
|
2434
|
$self->TableSpec_set_conf('relationship_column_names',\@single_rels); |
|
727
|
306
|
|
|
|
|
8474
|
$self->TableSpec_set_conf('multi_relationship_column_names',\@multi_rels); |
|
728
|
306
|
|
|
|
|
7291
|
$self->TableSpec_set_conf('relationship_column_fks_map',\%fk_cols); |
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
# New: move single rels up to immediately follow their FK column: |
|
731
|
306
|
100
|
|
|
|
8404
|
my @cols = map { $_, ( $fk_cols{$_} ? $fk_cols{$_} : () ) } $self->columns; |
|
|
1722
|
|
|
|
|
9318
|
|
|
732
|
|
|
|
|
|
|
|
|
733
|
306
|
|
|
|
|
1243
|
return uniq(@cols,@single_rels,@multi_rels,@virtual_single_rels); |
|
734
|
|
|
|
|
|
|
} |
|
735
|
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
# There is no longer extra logic at this stage because we're |
|
737
|
|
|
|
|
|
|
# backing off of the entire original "ordering" design: |
|
738
|
199
|
|
|
199
|
0
|
976
|
sub default_TableSpec_cnf_column_order { (shift)->TableSpec_valid_db_columns } |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
# Tmp code: these are all key names that may be used to set column |
|
741
|
|
|
|
|
|
|
# properties (column TableSpecs). We are keeping track of them to |
|
742
|
|
|
|
|
|
|
# use to for remapping while the TableSpec_cnf refactor/consolidation |
|
743
|
|
|
|
|
|
|
# is underway... |
|
744
|
|
|
|
|
|
|
my @col_prop_names = qw( |
|
745
|
|
|
|
|
|
|
columns |
|
746
|
|
|
|
|
|
|
column_properties |
|
747
|
|
|
|
|
|
|
column_properties_ordered |
|
748
|
|
|
|
|
|
|
column_properties_defaults |
|
749
|
|
|
|
|
|
|
); |
|
750
|
|
|
|
|
|
|
my %col_prop_names = map {$_=>1} @col_prop_names; |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
# The TableSpec_set_conf method is overly complex to allow |
|
753
|
|
|
|
|
|
|
# flexible arguments as either hash or hashref, and because of |
|
754
|
|
|
|
|
|
|
# the special case of setting the nested 'column_properties' |
|
755
|
|
|
|
|
|
|
# param, if specified as the first argument, and then be able to |
|
756
|
|
|
|
|
|
|
# accept its sub params as either a hash or a hashref. In hindsight, |
|
757
|
|
|
|
|
|
|
# allowing this was probably not worth the extra maintenace/code and |
|
758
|
|
|
|
|
|
|
# was too fancy for its own good (since this case may or may not |
|
759
|
|
|
|
|
|
|
# shift the key/value positions in the arg list) but it is a part |
|
760
|
|
|
|
|
|
|
# of the API for now... |
|
761
|
|
|
|
|
|
|
sub TableSpec_set_conf { |
|
762
|
1223
|
|
|
1223
|
0
|
1857
|
my $self = shift; |
|
763
|
1223
|
50
|
|
|
|
2565
|
die "TableSpec_set_conf(): bad arguments" unless (scalar(@_) > 0); |
|
764
|
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
# First arg can be a hashref - deref and call again: |
|
766
|
1223
|
50
|
|
|
|
2333
|
if(ref($_[0])) { |
|
767
|
0
|
0
|
0
|
|
|
0
|
die "TableSpec_set_conf(): bad arguments" unless ( |
|
768
|
|
|
|
|
|
|
ref($_[0]) eq 'HASH' and |
|
769
|
|
|
|
|
|
|
scalar(@_) == 1 |
|
770
|
|
|
|
|
|
|
); |
|
771
|
0
|
|
|
|
|
0
|
return $self->TableSpec_set_conf(%{$_[0]}) |
|
|
0
|
|
|
|
|
0
|
|
|
772
|
|
|
|
|
|
|
} |
|
773
|
|
|
|
|
|
|
|
|
774
|
1223
|
|
|
|
|
20838
|
$self->TableSpec_built_cnf(undef); #<-- FIXME!! |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
# Special handling for setting 'column_properties': |
|
777
|
1223
|
100
|
|
|
|
16015
|
if ($col_prop_names{$_[0]}) { |
|
778
|
50
|
|
|
|
|
87
|
shift @_; #<-- pull out the 'column_properties' first arg |
|
779
|
50
|
|
|
|
|
152
|
return $self->_TableSpec_set_column_properties(@_); |
|
780
|
|
|
|
|
|
|
}; |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
# Enforce even number of args for good measure: |
|
783
|
1173
|
50
|
|
|
|
2535
|
die join(' ', |
|
784
|
|
|
|
|
|
|
'TableSpec_set_conf( %cnf ):', |
|
785
|
|
|
|
|
|
|
"odd number of args in key/value list:", Dumper(\@_) |
|
786
|
|
|
|
|
|
|
) if (scalar(@_) & 1); |
|
787
|
|
|
|
|
|
|
|
|
788
|
1173
|
|
|
|
|
2791
|
my %cnf = @_; |
|
789
|
|
|
|
|
|
|
|
|
790
|
1173
|
|
|
|
|
2697
|
for my $param (keys %cnf) { |
|
791
|
|
|
|
|
|
|
# Also make sure all the keys (even positions) are simple scalars: |
|
792
|
1585
|
50
|
|
|
|
10227
|
die join(' ', |
|
793
|
|
|
|
|
|
|
'TableSpec_set_conf( %cnf ):', |
|
794
|
|
|
|
|
|
|
'found ref in key position:', Dumper($_) |
|
795
|
|
|
|
|
|
|
) if (ref($param)); |
|
796
|
|
|
|
|
|
|
|
|
797
|
1585
|
100
|
|
|
|
2775
|
if($col_prop_names{$param}) { |
|
798
|
|
|
|
|
|
|
# Also handle column_properties specified with other params: |
|
799
|
|
|
|
|
|
|
die join(' ', |
|
800
|
|
|
|
|
|
|
'TableSpec_set_conf( %cnf ): Expected', |
|
801
|
|
|
|
|
|
|
"HashRef value for config key '$param':", Dumper($cnf{$param}) |
|
802
|
57
|
50
|
|
|
|
167
|
) unless (ref($cnf{$param}) eq 'HASH'); |
|
803
|
57
|
|
|
|
|
322
|
$self->_TableSpec_set_column_properties($cnf{$param}); |
|
804
|
|
|
|
|
|
|
} |
|
805
|
|
|
|
|
|
|
else { |
|
806
|
1528
|
|
|
|
|
23442
|
$self->TableSpec_cnf->{$param} = $cnf{$param} |
|
807
|
|
|
|
|
|
|
} |
|
808
|
|
|
|
|
|
|
} |
|
809
|
|
|
|
|
|
|
} |
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
# Special new internal method for setting column properties and |
|
812
|
|
|
|
|
|
|
# properly handle backward compatability. Simultaneously sets/updates |
|
813
|
|
|
|
|
|
|
# the cnf key names for all the 'column_properties' names that are |
|
814
|
|
|
|
|
|
|
# currently supported by the API (as references pointing to the same |
|
815
|
|
|
|
|
|
|
# single config HashRef). This is only temporary and is a throwback |
|
816
|
|
|
|
|
|
|
# caused by the older/original API design for the TableSpec_cnf and |
|
817
|
|
|
|
|
|
|
# will be removed later on once the other config names can be depricated |
|
818
|
|
|
|
|
|
|
# along with other planned refactored. This is just a stop-gap to |
|
819
|
|
|
|
|
|
|
# allow this refactor to be done in stages... |
|
820
|
|
|
|
|
|
|
sub _TableSpec_set_column_properties { |
|
821
|
165
|
|
|
165
|
|
243
|
my $self = shift; |
|
822
|
165
|
50
|
|
|
|
341
|
die "TableSpec_set_conf( column_properties => %cnf ): bad args" |
|
823
|
|
|
|
|
|
|
unless (scalar(@_) > 0); |
|
824
|
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
# First arg can be a hashref - deref and call again: |
|
826
|
165
|
100
|
|
|
|
299
|
if(ref($_[0])) { |
|
827
|
58
|
50
|
33
|
|
|
267
|
die "TableSpec_set_conf( column_properties => %cnf ): bad args" unless ( |
|
828
|
|
|
|
|
|
|
ref($_[0]) eq 'HASH' and |
|
829
|
|
|
|
|
|
|
scalar(@_) == 1 |
|
830
|
|
|
|
|
|
|
); |
|
831
|
58
|
|
|
|
|
100
|
return $self->_TableSpec_set_column_properties(%{$_[0]}) |
|
|
58
|
|
|
|
|
261
|
|
|
832
|
|
|
|
|
|
|
} |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
# Enforce even number of args for good measure: |
|
835
|
107
|
50
|
|
|
|
225
|
die join(' ', |
|
836
|
|
|
|
|
|
|
'TableSpec_set_conf( column_properties => %cnf ):', |
|
837
|
|
|
|
|
|
|
"odd number of args in key/value list:", Dumper(\@_) |
|
838
|
|
|
|
|
|
|
) if (scalar(@_) & 1); |
|
839
|
|
|
|
|
|
|
|
|
840
|
107
|
|
|
|
|
370
|
my %cnf = @_; |
|
841
|
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
# Also make sure all the keys (even positions) are simple scalars: |
|
843
|
|
|
|
|
|
|
ref($_) and die join(' ', |
|
844
|
|
|
|
|
|
|
'TableSpec_set_conf( column_properties => %cnf ):', |
|
845
|
|
|
|
|
|
|
'found ref in key position:', Dumper($_) |
|
846
|
107
|
|
50
|
|
|
641
|
) for (keys %cnf); |
|
847
|
|
|
|
|
|
|
|
|
848
|
107
|
|
|
|
|
520
|
my %valid_colnames = map {$_=>1} ($self->TableSpec_valid_db_columns); |
|
|
744
|
|
|
|
|
1225
|
|
|
849
|
|
|
|
|
|
|
|
|
850
|
107
|
|
|
|
|
223
|
my $col_props; |
|
851
|
107
|
|
100
|
|
|
2034
|
$col_props ||= $self->TableSpec_cnf->{$_} for (@col_prop_names); |
|
852
|
107
|
|
100
|
|
|
5873
|
$col_props ||= {}; |
|
853
|
|
|
|
|
|
|
|
|
854
|
107
|
|
|
|
|
269
|
for my $col (keys %cnf) { |
|
855
|
|
|
|
|
|
|
warn join(' ', |
|
856
|
|
|
|
|
|
|
"Ignoring config for unknown column name '$col'", |
|
857
|
|
|
|
|
|
|
"in $self TableSpec config\n" |
|
858
|
681
|
50
|
0
|
|
|
994
|
) and next unless ($valid_colnames{$col}); |
|
859
|
681
|
|
|
|
|
1054
|
$col_props->{$col} = $cnf{$col}; |
|
860
|
|
|
|
|
|
|
} |
|
861
|
|
|
|
|
|
|
|
|
862
|
107
|
|
|
|
|
1766
|
$self->TableSpec_cnf->{$_} = $col_props for (@col_prop_names); |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
# New function for updating/merging in column configs. This allows |
|
867
|
|
|
|
|
|
|
# setting certain column configs without overwriting existing config |
|
868
|
|
|
|
|
|
|
# keys that are not being specified: |
|
869
|
|
|
|
|
|
|
sub TableSpec_merge_columns_conf { |
|
870
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
871
|
0
|
|
|
|
|
0
|
my $conf = shift; |
|
872
|
|
|
|
|
|
|
|
|
873
|
0
|
0
|
|
|
|
0
|
die "TableSpec_merge_columns_conf( \%columns ): bad args" |
|
874
|
|
|
|
|
|
|
unless (ref($conf) eq 'HASH'); |
|
875
|
|
|
|
|
|
|
|
|
876
|
0
|
|
0
|
|
|
0
|
my $existing = $self->TableSpec_get_conf('columns') || {}; |
|
877
|
|
|
|
|
|
|
|
|
878
|
0
|
|
|
|
|
0
|
my @cols = uniq( keys %$conf, keys %$existing ); |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
my %new = ( map { |
|
881
|
0
|
|
|
|
|
0
|
$_ => { |
|
882
|
0
|
0
|
|
|
|
0
|
%{ $existing->{$_} || {} }, |
|
883
|
0
|
0
|
|
|
|
0
|
%{ $conf->{$_} || {} }, |
|
|
0
|
|
|
|
|
0
|
|
|
884
|
|
|
|
|
|
|
} |
|
885
|
|
|
|
|
|
|
} @cols ); |
|
886
|
|
|
|
|
|
|
|
|
887
|
0
|
|
|
|
|
0
|
return $self->TableSpec_set_conf( columns => \%new ); |
|
888
|
|
|
|
|
|
|
} |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
sub TableSpec_get_conf { |
|
893
|
1922
|
|
|
1922
|
0
|
18323
|
my $self = shift; |
|
894
|
1922
|
|
50
|
|
|
4083
|
my $param = shift || return undef; |
|
895
|
1922
|
|
66
|
|
|
5194
|
my $storage = shift || $self->get_built_Cnf; |
|
896
|
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
# Special: map all column prop names into 'column_properties' |
|
898
|
1922
|
100
|
|
|
|
19901
|
$param = 'column_properties' if ($col_prop_names{$param}); |
|
899
|
|
|
|
|
|
|
|
|
900
|
1922
|
|
|
|
|
3663
|
my $value = $storage->{$param}; |
|
901
|
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
# --- FIXME FIXME FIXME |
|
903
|
|
|
|
|
|
|
# In the original design of the TableSpec_cnf internals, which |
|
904
|
|
|
|
|
|
|
# was too fancy for its own good, meta/type information was |
|
905
|
|
|
|
|
|
|
# transparently stored to be able to do things like remember |
|
906
|
|
|
|
|
|
|
# the order of keys in hashes, auto dereference, etc. This has |
|
907
|
|
|
|
|
|
|
# been unfactored and converted to simple key/values since, however, |
|
908
|
|
|
|
|
|
|
# places that might still call TableSpec_get_conf still expect |
|
909
|
|
|
|
|
|
|
# to get back lists instead of ArrayRefs/HashRefs in certain |
|
910
|
|
|
|
|
|
|
# places. These places should be very limited (part of the reason |
|
911
|
|
|
|
|
|
|
# it was decided this whole thing wasn't worth it, because it just |
|
912
|
|
|
|
|
|
|
# wasn't used enough), but for now, to honor the original API (mostly) |
|
913
|
|
|
|
|
|
|
# we're dereferencing according to wantarray, since all the places |
|
914
|
|
|
|
|
|
|
# that expect to get lists back obviously call TableSpec_get_conf |
|
915
|
|
|
|
|
|
|
# in LIST context. This should not be kept this way for too long, |
|
916
|
|
|
|
|
|
|
# however! It is just temporary until those outside places |
|
917
|
|
|
|
|
|
|
# can be confirmed and eliminated, or a proper deprecation plan |
|
918
|
|
|
|
|
|
|
# can be made, should that even be needed... |
|
919
|
|
|
|
|
|
|
|
|
920
|
1922
|
50
|
66
|
|
|
4100
|
if(wantarray && ref($value)) { |
|
921
|
0
|
0
|
0
|
|
|
0
|
cluck join("\n",'', |
|
922
|
|
|
|
|
|
|
" WARNING: calling TableSpec_get_conf() in LIST context", |
|
923
|
|
|
|
|
|
|
" is deprecated, please update your code.", |
|
924
|
|
|
|
|
|
|
" --> Auto-dereferencing param '$param' $value",'', |
|
925
|
|
|
|
|
|
|
'') if (ref($value) eq 'ARRAY' || ref($value) eq 'HASH'); |
|
926
|
0
|
0
|
|
|
|
0
|
return @$value if (ref($value) eq 'ARRAY'); |
|
927
|
0
|
0
|
|
|
|
0
|
return %$value if (ref($value) eq 'HASH'); |
|
928
|
|
|
|
|
|
|
} |
|
929
|
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
# When trying to get a param that does not exist, return an |
|
931
|
|
|
|
|
|
|
# empty list if called in LIST context, otherwise undef |
|
932
|
1922
|
50
|
|
|
|
6089
|
return wantarray ? () : undef unless (exists $storage->{$param}); |
|
|
|
100
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
# --- |
|
934
|
|
|
|
|
|
|
|
|
935
|
1178
|
|
|
|
|
5774
|
return $value; |
|
936
|
|
|
|
|
|
|
} |
|
937
|
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
sub TableSpec_has_conf { |
|
940
|
84
|
|
|
84
|
0
|
175
|
my $self = shift; |
|
941
|
84
|
|
|
|
|
143
|
my $param = shift; |
|
942
|
84
|
|
33
|
|
|
438
|
my $storage = shift || $self->get_built_Cnf; |
|
943
|
84
|
50
|
|
|
|
2318
|
return 1 if (exists $storage->{$param}); |
|
944
|
0
|
|
|
|
|
0
|
return 0; |
|
945
|
|
|
|
|
|
|
} |
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
sub TableSpec_related_class { |
|
949
|
822
|
|
|
822
|
0
|
1082
|
my $self = shift; |
|
950
|
822
|
|
50
|
|
|
1472
|
my $rel = shift || return undef; |
|
951
|
822
|
|
50
|
|
|
12786
|
my $info = $self->relationship_info($rel) || return undef; |
|
952
|
822
|
|
|
|
|
28089
|
my $relclass = $info->{class}; |
|
953
|
|
|
|
|
|
|
|
|
954
|
822
|
|
|
|
|
35028
|
eval "require $relclass;"; |
|
955
|
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
#my $relclass = $self->related_class($rel) || return undef; |
|
957
|
822
|
50
|
|
|
|
36088
|
$relclass->can('TableSpec_get_conf') || return undef; |
|
958
|
822
|
|
|
|
|
2347
|
return $relclass; |
|
959
|
|
|
|
|
|
|
} |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
# Gets a TableSpec conf param, if exists, from a related Result Class |
|
962
|
|
|
|
|
|
|
sub TableSpec_related_get_conf { |
|
963
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
964
|
0
|
|
0
|
|
|
0
|
my $rel = shift || return undef; |
|
965
|
0
|
|
0
|
|
|
0
|
my $param = shift || return undef; |
|
966
|
|
|
|
|
|
|
|
|
967
|
0
|
|
0
|
|
|
0
|
my $relclass = $self->TableSpec_related_class($rel) || return undef; |
|
968
|
|
|
|
|
|
|
|
|
969
|
0
|
|
|
|
|
0
|
return $relclass->TableSpec_get_conf($param); |
|
970
|
|
|
|
|
|
|
} |
|
971
|
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
# Gets a TableSpec conf param, if exists, from a related Result Class, |
|
973
|
|
|
|
|
|
|
# but uses the already 'set' params in TableSpec_cnf as storage, so that |
|
974
|
|
|
|
|
|
|
# get_built_cnf doesn't get called. |
|
975
|
|
|
|
|
|
|
sub TableSpec_related_get_set_conf { |
|
976
|
822
|
|
|
822
|
0
|
1194
|
my $self = shift; |
|
977
|
822
|
|
50
|
|
|
1490
|
my $rel = shift || return undef; |
|
978
|
822
|
|
50
|
|
|
1462
|
my $param = shift || return undef; |
|
979
|
|
|
|
|
|
|
|
|
980
|
822
|
|
50
|
|
|
1758
|
my $relclass = $self->TableSpec_related_class($rel) || return undef; |
|
981
|
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
#return $relclass->TableSpec_get_conf($param,$relclass->TableSpec_cnf); |
|
983
|
822
|
|
|
|
|
1933
|
return $relclass->TableSpec_get_set_conf($param); |
|
984
|
|
|
|
|
|
|
} |
|
985
|
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
# The "set conf" is different from the "built conf" in that it is passive, and only |
|
987
|
|
|
|
|
|
|
# returns the values which have been expressly "set" on the Result class with a |
|
988
|
|
|
|
|
|
|
# "TableSpec_set_conf" call. The built conf reaches out to code to build a configuration, |
|
989
|
|
|
|
|
|
|
# which causes recursive limitations in that code that reaches out to other TableSpec |
|
990
|
|
|
|
|
|
|
# classes. |
|
991
|
|
|
|
|
|
|
sub TableSpec_get_set_conf { |
|
992
|
1126
|
|
|
1126
|
0
|
1696
|
my $self = shift; |
|
993
|
1126
|
|
50
|
|
|
1949
|
my $param = shift || return undef; |
|
994
|
1126
|
|
|
|
|
18944
|
return $self->TableSpec_get_conf($param,$self->TableSpec_cnf); |
|
995
|
|
|
|
|
|
|
} |
|
996
|
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
# TODO: Find a better way to handle this. Is there a real API |
|
999
|
|
|
|
|
|
|
# in DBIC to find this information? |
|
1000
|
|
|
|
|
|
|
sub get_foreign_column_from_cond { |
|
1001
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
1002
|
0
|
|
|
|
|
0
|
my $cond = shift; |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
0
|
0
|
0
|
|
|
0
|
die "currently only single-key hashref conditions are supported" unless ( |
|
1005
|
|
|
|
|
|
|
ref($cond) eq 'HASH' and |
|
1006
|
|
|
|
|
|
|
scalar keys %$cond == 1 |
|
1007
|
|
|
|
|
|
|
); |
|
1008
|
|
|
|
|
|
|
|
|
1009
|
0
|
|
|
|
|
0
|
foreach my $i (%$cond) { |
|
1010
|
0
|
|
|
|
|
0
|
my ($side,$col) = split(/\./,$i); |
|
1011
|
0
|
0
|
0
|
|
|
0
|
return $col if (defined $col and $side eq 'foreign'); |
|
1012
|
|
|
|
|
|
|
} |
|
1013
|
|
|
|
|
|
|
|
|
1014
|
0
|
|
|
|
|
0
|
die "Failed to find forein column from condition: " . Dumper($cond); |
|
1015
|
|
|
|
|
|
|
} |
|
1016
|
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
# This function parses 'foreign' and 'self' column names from the |
|
1018
|
|
|
|
|
|
|
# 'cond' of a defined in a DBIC relationship into a hashref. It is |
|
1019
|
|
|
|
|
|
|
# only able to do this for simple, single-key foreign key rels |
|
1020
|
|
|
|
|
|
|
# of the form: { "foreign.id_col" => "self.fk_col" } |
|
1021
|
|
|
|
|
|
|
# All other forms, such as multi-keys and CodeRefs, will return |
|
1022
|
|
|
|
|
|
|
# and empty HashRef. The only reason we really need this information |
|
1023
|
|
|
|
|
|
|
# outside of DBIC is for editable single rels (FKs) to be able |
|
1024
|
|
|
|
|
|
|
# to present selection dialogs (i.e. dropdowns) and currently |
|
1025
|
|
|
|
|
|
|
# the "open" magnify links, but the open links are planned to be |
|
1026
|
|
|
|
|
|
|
# changed to reference URLs based on the relationship name, which |
|
1027
|
|
|
|
|
|
|
# will remove this dependency and allow open links for any relationship |
|
1028
|
|
|
|
|
|
|
# column, including even those with CodeRef conditions... |
|
1029
|
|
|
|
|
|
|
sub parse_relationship_cond { |
|
1030
|
657
|
|
|
657
|
0
|
1671
|
my ($self,$cond,$info) = @_; |
|
1031
|
|
|
|
|
|
|
|
|
1032
|
|
|
|
|
|
|
return {} unless ( |
|
1033
|
657
|
50
|
33
|
|
|
3738
|
ref($cond) eq 'HASH' and |
|
1034
|
|
|
|
|
|
|
scalar keys %$cond == 1 |
|
1035
|
|
|
|
|
|
|
); |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
657
|
|
|
|
|
1447
|
my $data = {}; |
|
1038
|
657
|
|
|
|
|
1877
|
foreach my $i (%$cond) { |
|
1039
|
1314
|
|
|
|
|
3750
|
my ($side,$col) = split(/\./,$i); |
|
1040
|
1314
|
|
|
|
|
3199
|
$data->{$side} = $col; |
|
1041
|
|
|
|
|
|
|
} |
|
1042
|
657
|
|
|
|
|
1624
|
return $data; |
|
1043
|
|
|
|
|
|
|
} |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
# Works like an around method modifier, but $self is expected as first arg and |
|
1046
|
|
|
|
|
|
|
# $orig (method) is expected as second arg (reversed from a normal around modifier). |
|
1047
|
|
|
|
|
|
|
# Calls the supplied method and returns what changed in the record from before to |
|
1048
|
|
|
|
|
|
|
# after the call. e.g.: |
|
1049
|
|
|
|
|
|
|
# |
|
1050
|
|
|
|
|
|
|
# my ($changes) = $self->proxy_method_get_changed('update',{ foo => 'sdfds'}); |
|
1051
|
|
|
|
|
|
|
# |
|
1052
|
|
|
|
|
|
|
# This is typically used for update, but could be any other method, too. |
|
1053
|
|
|
|
|
|
|
# |
|
1054
|
|
|
|
|
|
|
# Detects/propogates wantarray context. Call like this to chain from another modifier: |
|
1055
|
|
|
|
|
|
|
#my ($changes,@ret) = wantarray ? |
|
1056
|
|
|
|
|
|
|
# $self->proxy_method_get_changed($orig,@_) : |
|
1057
|
|
|
|
|
|
|
# @{$self->proxy_method_get_changed($orig,@_)}; |
|
1058
|
|
|
|
|
|
|
# |
|
1059
|
|
|
|
|
|
|
sub proxy_method_get_changed { |
|
1060
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
1061
|
0
|
|
|
|
|
0
|
my $method = shift; |
|
1062
|
|
|
|
|
|
|
|
|
1063
|
5
|
|
|
5
|
|
19222
|
no warnings 'uninitialized'; # because we might compare undef values |
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
3917
|
|
|
1064
|
|
|
|
|
|
|
|
|
1065
|
0
|
|
|
|
|
0
|
my $origRow = $self; |
|
1066
|
0
|
|
|
|
|
0
|
my %old = (); |
|
1067
|
0
|
0
|
|
|
|
0
|
if($self->in_storage) { |
|
1068
|
0
|
|
0
|
|
|
0
|
$origRow = $self->get_from_storage || $self; |
|
1069
|
0
|
|
|
|
|
0
|
%old = $origRow->get_columns; |
|
1070
|
|
|
|
|
|
|
} |
|
1071
|
|
|
|
|
|
|
|
|
1072
|
0
|
|
|
|
|
0
|
my @ret = (); |
|
1073
|
|
|
|
|
|
|
wantarray ? |
|
1074
|
0
|
0
|
|
|
|
0
|
@ret = $self->$method(@_) : |
|
1075
|
|
|
|
|
|
|
$ret[0] = $self->$method(@_); |
|
1076
|
|
|
|
|
|
|
|
|
1077
|
0
|
|
|
|
|
0
|
my %new = (); |
|
1078
|
0
|
0
|
|
|
|
0
|
if($self->in_storage) { |
|
1079
|
0
|
|
|
|
|
0
|
%new = $self->get_columns; |
|
1080
|
|
|
|
|
|
|
} |
|
1081
|
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
# This logic is duplicated in DbicLink2. Not sure how to avoid it, though, |
|
1083
|
|
|
|
|
|
|
# and keep a clean API |
|
1084
|
0
|
|
|
|
|
0
|
my @changed = (); |
|
1085
|
0
|
|
|
|
|
0
|
foreach my $col (uniq(keys %new,keys %old)) { |
|
1086
|
0
|
0
|
0
|
|
|
0
|
next if (! defined $new{$col} and ! defined $old{$col}); |
|
1087
|
0
|
0
|
|
|
|
0
|
next if ($new{$col} eq $old{$col}); |
|
1088
|
0
|
|
|
|
|
0
|
push @changed, $col; |
|
1089
|
|
|
|
|
|
|
} |
|
1090
|
|
|
|
|
|
|
|
|
1091
|
0
|
|
|
|
|
0
|
my @new_changed = (); |
|
1092
|
0
|
|
|
|
|
0
|
my $fk_map = $self->TableSpec_get_conf('relationship_column_fks_map'); |
|
1093
|
0
|
|
|
|
|
0
|
foreach my $col (@changed) { |
|
1094
|
0
|
0
|
|
|
|
0
|
unless($fk_map->{$col}) { |
|
1095
|
0
|
|
|
|
|
0
|
push @new_changed, $col; |
|
1096
|
0
|
|
|
|
|
0
|
next; |
|
1097
|
|
|
|
|
|
|
} |
|
1098
|
|
|
|
|
|
|
|
|
1099
|
0
|
|
|
|
|
0
|
my $rel = $fk_map->{$col}; |
|
1100
|
0
|
|
|
|
|
0
|
my $display_col = $self->TableSpec_related_get_set_conf($rel,'display_column'); |
|
1101
|
|
|
|
|
|
|
|
|
1102
|
0
|
|
|
|
|
0
|
my $relOld = $origRow->$rel; |
|
1103
|
0
|
|
|
|
|
0
|
my $relNew = $self->$rel; |
|
1104
|
|
|
|
|
|
|
|
|
1105
|
0
|
0
|
0
|
|
|
0
|
unless($display_col and ($relOld or $relNew)) { |
|
|
|
|
0
|
|
|
|
|
|
1106
|
0
|
|
|
|
|
0
|
push @new_changed, $col; |
|
1107
|
0
|
|
|
|
|
0
|
next; |
|
1108
|
|
|
|
|
|
|
} |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
0
|
|
|
|
|
0
|
push @new_changed, $rel; |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
0
|
0
|
0
|
|
|
0
|
$old{$rel} = $relOld->get_column($display_col) if (exists $old{$col} and $relOld); |
|
1113
|
0
|
0
|
0
|
|
|
0
|
$new{$rel} = $relNew->get_column($display_col) if (exists $new{$col} and $relNew); |
|
1114
|
|
|
|
|
|
|
} |
|
1115
|
|
|
|
|
|
|
|
|
1116
|
0
|
|
|
|
|
0
|
@changed = @new_changed; |
|
1117
|
|
|
|
|
|
|
|
|
1118
|
0
|
|
|
|
|
0
|
my $col_props = $self->TableSpec_get_conf('columns'); |
|
1119
|
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
my %diff = map { |
|
1121
|
0
|
|
|
|
|
0
|
$_ => { |
|
1122
|
|
|
|
|
|
|
old => $old{$_}, |
|
1123
|
|
|
|
|
|
|
new => $new{$_}, |
|
1124
|
|
|
|
|
|
|
header => ($col_props->{$_} && $col_props->{$_}->{header}) ? |
|
1125
|
0
|
0
|
0
|
|
|
0
|
$col_props->{$_}->{header} : $_ |
|
1126
|
|
|
|
|
|
|
} |
|
1127
|
|
|
|
|
|
|
} @changed; |
|
1128
|
|
|
|
|
|
|
|
|
1129
|
0
|
0
|
|
|
|
0
|
return wantarray ? (\%diff,@ret) : [\%diff,@ret]; |
|
1130
|
|
|
|
|
|
|
} |
|
1131
|
|
|
|
|
|
|
|
|
1132
|
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
sub getOpenUrl { |
|
1134
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
1135
|
0
|
|
|
|
|
0
|
return $self->TableSpec_get_conf('open_url'); |
|
1136
|
|
|
|
|
|
|
} |
|
1137
|
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
sub getRestKey { |
|
1139
|
183
|
|
|
183
|
0
|
9105
|
my $self = shift; |
|
1140
|
183
|
|
|
|
|
653
|
my $rest_key_col = $self->TableSpec_get_conf('rest_key_column'); |
|
1141
|
183
|
50
|
33
|
|
|
680
|
return $rest_key_col if ($rest_key_col && $rest_key_col ne ''); |
|
1142
|
183
|
|
|
|
|
3325
|
my @pri = $self->primary_columns; |
|
1143
|
183
|
50
|
33
|
|
|
8389
|
return $pri[0] if ($pri[0] && scalar @pri == 1); |
|
1144
|
0
|
|
|
|
|
0
|
return undef; |
|
1145
|
|
|
|
|
|
|
} |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
### Util functions: to be called in Row-object context |
|
1148
|
|
|
|
|
|
|
sub apply_row_methods { |
|
1149
|
54
|
|
|
54
|
0
|
114
|
my $class = shift; |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
my %RowMethods = ( |
|
1152
|
|
|
|
|
|
|
|
|
1153
|
0
|
|
|
0
|
|
0
|
getOpenUrl => sub { $class->TableSpec_get_conf('open_url') }, |
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
getRecordPkValue => sub { |
|
1156
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1157
|
0
|
|
|
|
|
0
|
my @pk_vals = map { $self->get_column($_) } $self->primary_columns; |
|
|
0
|
|
|
|
|
0
|
|
|
1158
|
0
|
|
|
|
|
0
|
return join('~$~',@pk_vals); |
|
1159
|
|
|
|
|
|
|
}, |
|
1160
|
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
getRestKeyVal => sub { |
|
1162
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1163
|
0
|
0
|
|
|
|
0
|
my $col = $class->getRestKey or return $self->getRecordPkValue; |
|
1164
|
0
|
|
|
0
|
|
0
|
return try{$self->get_column($col)}; |
|
|
0
|
|
|
|
|
0
|
|
|
1165
|
|
|
|
|
|
|
}, |
|
1166
|
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
getRestPath => sub { |
|
1168
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1169
|
0
|
0
|
|
|
|
0
|
my $url = $class->getOpenUrl or return undef; |
|
1170
|
0
|
0
|
|
|
|
0
|
my $val = $self->getRestKeyVal or return undef; |
|
1171
|
0
|
|
|
|
|
0
|
return "$url/$val"; |
|
1172
|
|
|
|
|
|
|
}, |
|
1173
|
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
getDisplayValue => sub { |
|
1175
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1176
|
0
|
|
|
|
|
0
|
my $display_column = $class->TableSpec_get_conf('display_column'); |
|
1177
|
0
|
0
|
|
|
|
0
|
return $self->get_column($display_column) if ($self->has_column($display_column)); |
|
1178
|
0
|
|
|
|
|
0
|
return $self->getRecordPkValue; |
|
1179
|
|
|
|
|
|
|
}, |
|
1180
|
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
inlineNavLink => sub { |
|
1182
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1183
|
0
|
|
0
|
|
|
0
|
my $text = shift || '<span>open</span>'; |
|
1184
|
0
|
|
|
|
|
0
|
my %attrs = ( class => "ra-nav-link ra-icon-magnify-tiny", @_ ); |
|
1185
|
|
|
|
|
|
|
|
|
1186
|
0
|
0
|
|
|
|
0
|
my $title = $self->getDisplayValue or return undef; |
|
1187
|
0
|
0
|
|
|
|
0
|
my $url = $self->getRestPath or return undef; |
|
1188
|
|
|
|
|
|
|
|
|
1189
|
0
|
|
|
|
|
0
|
%attrs = ( |
|
1190
|
|
|
|
|
|
|
href => '#!' . $url, |
|
1191
|
|
|
|
|
|
|
title => $title, |
|
1192
|
|
|
|
|
|
|
%attrs |
|
1193
|
|
|
|
|
|
|
); |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
0
|
|
|
|
|
0
|
my $attr_str = join(' ',map { $_ . '="' . $attrs{$_} . '"' } keys %attrs); |
|
|
0
|
|
|
|
|
0
|
|
|
1196
|
0
|
|
|
|
|
0
|
return '<a ' . $attr_str . '>' . $text . '</a>'; |
|
1197
|
|
|
|
|
|
|
}, |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
displayWithLink => sub { |
|
1200
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1201
|
0
|
|
|
|
|
0
|
return $self->getDisplayValue . ' ' . $self->inlineNavLink; |
|
1202
|
|
|
|
|
|
|
} |
|
1203
|
54
|
|
|
|
|
1294
|
); |
|
1204
|
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
# --- Actualize/load methods into the Row object namespace: |
|
1206
|
54
|
|
|
|
|
232
|
foreach my $meth (keys %RowMethods) { |
|
1207
|
5
|
|
|
5
|
|
37
|
no strict 'refs'; |
|
|
5
|
|
|
|
|
17
|
|
|
|
5
|
|
|
|
|
1046
|
|
|
1208
|
378
|
|
|
|
|
738
|
my $meth_name = join '::', $class, $meth; |
|
1209
|
378
|
|
|
|
|
2384
|
*$meth_name = subname $meth_name => $RowMethods{$meth}; |
|
1210
|
|
|
|
|
|
|
} |
|
1211
|
|
|
|
|
|
|
# --- |
|
1212
|
|
|
|
|
|
|
} |
|
1213
|
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
|
|
1215
|
|
|
|
|
|
|
sub _table_name_safe { |
|
1216
|
488
|
|
|
488
|
|
22053
|
my $arg = shift; |
|
1217
|
|
|
|
|
|
|
|
|
1218
|
488
|
50
|
33
|
|
|
4840
|
my $table = !(ref $arg) && $arg->can('table') ? $arg->table : $arg; # class method or straight function |
|
1219
|
|
|
|
|
|
|
|
|
1220
|
488
|
50
|
50
|
|
|
2369
|
$table = $$table if ((ref($table)||'') eq 'SCALAR'); # Handle ScalarRef values |
|
1221
|
488
|
|
|
|
|
1828
|
$table = (reverse split(/\./,$table))[0]; # Handle 'db.table' and 'schema.db.table' formats |
|
1222
|
|
|
|
|
|
|
|
|
1223
|
488
|
|
|
|
|
1439
|
$table =~ s/[\'\"]//g; # Strip quotes |
|
1224
|
488
|
|
|
|
|
947
|
$table =~ s/\W/_/g; # Convert any non-word characters to underscore |
|
1225
|
|
|
|
|
|
|
|
|
1226
|
488
|
|
|
|
|
1310
|
$table |
|
1227
|
|
|
|
|
|
|
} |
|
1228
|
|
|
|
|
|
|
|
|
1229
|
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
### -- old, pre-rest inlineNavLink: |
|
1232
|
|
|
|
|
|
|
## This function creates links just like the JavaScript function Ext.ux.RapidApp.inlineLink |
|
1233
|
|
|
|
|
|
|
#use URI::Escape; |
|
1234
|
|
|
|
|
|
|
#sub inlineNavLink { |
|
1235
|
|
|
|
|
|
|
# my $self = shift; |
|
1236
|
|
|
|
|
|
|
# my $text = shift || '<span>open</span>'; |
|
1237
|
|
|
|
|
|
|
# my %attrs = ( class => "magnify-link-tiny", @_ ); |
|
1238
|
|
|
|
|
|
|
# my $loadCfg = delete $attrs{loadCfg} || {}; |
|
1239
|
|
|
|
|
|
|
# |
|
1240
|
|
|
|
|
|
|
# my $title = $self->getDisplayValue || return undef; |
|
1241
|
|
|
|
|
|
|
# my $url = $self->getOpenUrl || return undef; |
|
1242
|
|
|
|
|
|
|
# my $pk_val = $self->getRecordPkValue || return undef; |
|
1243
|
|
|
|
|
|
|
# |
|
1244
|
|
|
|
|
|
|
# $loadCfg = merge({ |
|
1245
|
|
|
|
|
|
|
# title => $title, |
|
1246
|
|
|
|
|
|
|
# autoLoad => { |
|
1247
|
|
|
|
|
|
|
# url => $url, |
|
1248
|
|
|
|
|
|
|
# params => { '___record_pk' => $pk_val } |
|
1249
|
|
|
|
|
|
|
# } |
|
1250
|
|
|
|
|
|
|
# },$loadCfg); |
|
1251
|
|
|
|
|
|
|
# |
|
1252
|
|
|
|
|
|
|
# my $href = '#loadcfg:data=' . uri_escape(encode_json($loadCfg)); |
|
1253
|
|
|
|
|
|
|
# my $onclick = 'return Ext.ux.RapidApp.InlineLinkHandler.apply(this,arguments);'; |
|
1254
|
|
|
|
|
|
|
# |
|
1255
|
|
|
|
|
|
|
# %attrs = ( |
|
1256
|
|
|
|
|
|
|
# href => $href, |
|
1257
|
|
|
|
|
|
|
# onclick => $onclick, |
|
1258
|
|
|
|
|
|
|
# ondblclick => $onclick, |
|
1259
|
|
|
|
|
|
|
# title => $title, |
|
1260
|
|
|
|
|
|
|
# %attrs |
|
1261
|
|
|
|
|
|
|
# ); |
|
1262
|
|
|
|
|
|
|
# |
|
1263
|
|
|
|
|
|
|
# my $attr_str = join(' ',map { $_ . '="' . $attrs{$_} . '"' } keys %attrs); |
|
1264
|
|
|
|
|
|
|
# |
|
1265
|
|
|
|
|
|
|
# return '<a ' . $attr_str . '>' . $text . '</a>'; |
|
1266
|
|
|
|
|
|
|
# |
|
1267
|
|
|
|
|
|
|
#} |
|
1268
|
|
|
|
|
|
|
# |
|
1269
|
|
|
|
|
|
|
|
|
1270
|
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
1; |