line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DBI::Easy; |
2
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
848346
|
use Class::Easy::Base; |
|
6
|
|
|
|
|
28128
|
|
|
6
|
|
|
|
|
42
|
|
4
|
|
|
|
|
|
|
|
5
|
6
|
|
|
6
|
|
16623
|
use DBI 1.611; |
|
6
|
|
|
|
|
64147
|
|
|
6
|
|
|
|
|
401
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#use Hash::Util; |
8
|
|
|
|
|
|
|
|
9
|
6
|
|
|
6
|
|
52
|
use vars qw($VERSION); |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
490
|
|
10
|
|
|
|
|
|
|
$VERSION = '0.24'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
13
|
|
|
|
|
|
|
# interface splitted to various sections: |
14
|
|
|
|
|
|
|
# sql generation stuff prefixed with sql and located |
15
|
|
|
|
|
|
|
# at DBI::Class::SQL |
16
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
17
|
|
|
|
|
|
|
|
18
|
6
|
|
|
6
|
|
5734
|
use DBI::Easy::SQL; |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
216
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
21
|
|
|
|
|
|
|
# real dbh operations contains methods fetch_* and no_fetch |
22
|
|
|
|
|
|
|
# and placed in DBI::Class::DBH |
23
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
24
|
|
|
|
|
|
|
|
25
|
6
|
|
|
6
|
|
4425
|
use DBI::Easy::DBH; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
187
|
|
26
|
|
|
|
|
|
|
|
27
|
6
|
|
|
6
|
|
3632
|
use DBI::Easy::DriverPatcher; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
150
|
|
28
|
|
|
|
|
|
|
|
29
|
6
|
|
|
6
|
|
3276
|
use DBI::Easy::Helper; |
|
6
|
|
|
|
|
22
|
|
|
6
|
|
|
|
|
7961
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# bwahahahaha |
32
|
|
|
|
|
|
|
our %GREP_COLUMN_INFO = qw(TYPE_NAME 1 mysql_values 1); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
our $wrapper = 1; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
our $H = 'DBI::Easy::Helper'; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub new { |
39
|
77
|
|
|
77
|
1
|
7143
|
my $class = shift; |
40
|
|
|
|
|
|
|
|
41
|
77
|
|
|
|
|
125
|
my $params; |
42
|
|
|
|
|
|
|
my $init_params; |
43
|
|
|
|
|
|
|
|
44
|
77
|
100
|
|
|
|
1238
|
$init_params = $class->_init (@_) |
45
|
|
|
|
|
|
|
if $class->can ('_init'); |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
$params = $init_params || {(@_ == 1 && ref $_[0] && ref $_[0] eq 'HASH') |
48
|
77
|
|
100
|
|
|
576
|
? %{$_[0]} |
49
|
|
|
|
|
|
|
: @_ |
50
|
|
|
|
|
|
|
}; |
51
|
|
|
|
|
|
|
|
52
|
77
|
|
|
|
|
783
|
bless $params, $class; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub import { |
56
|
33
|
|
|
33
|
|
161
|
my $class = shift; |
57
|
|
|
|
|
|
|
|
58
|
33
|
100
|
|
|
|
61
|
unless (${"${class}::imported"}) { |
|
33
|
|
|
|
|
414
|
|
59
|
23
|
|
|
|
|
261
|
make_accessor ($class, 'dbh', is => 'rw', global => 1); |
60
|
|
|
|
|
|
|
make_accessor ($class, 'dbh_modify', is => 'rw', global => 1, default => sub { |
61
|
42
|
|
|
42
|
|
137
|
return shift->dbh; |
62
|
23
|
|
|
|
|
1212
|
}); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
33
|
100
|
66
|
|
|
998
|
if (! ${"${class}::wrapper"} and $class ne __PACKAGE__ and ! ${"${class}::imported"} ) { |
|
33
|
|
100
|
|
|
688
|
|
|
21
|
|
|
|
|
147
|
|
66
|
|
|
|
|
|
|
|
67
|
17
|
|
|
|
|
104
|
debug "importing $class"; |
68
|
|
|
|
|
|
|
|
69
|
17
|
|
|
|
|
1375
|
my $t = timer ('init_class'); |
70
|
17
|
|
|
|
|
1040
|
$class->_init_class; |
71
|
|
|
|
|
|
|
|
72
|
17
|
|
|
|
|
824
|
$t->lap ('init_db'); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# we call _init_db from package before real db |
75
|
17
|
|
|
|
|
289
|
$class->_init_db; |
76
|
|
|
|
|
|
|
|
77
|
17
|
|
|
|
|
1075
|
$t->lap ("init_collection $class"); |
78
|
|
|
|
|
|
|
|
79
|
17
|
100
|
|
|
|
246
|
$class->_init_collection |
80
|
|
|
|
|
|
|
if $class->is_collection; |
81
|
|
|
|
|
|
|
|
82
|
17
|
|
|
|
|
421
|
$t->lap ("dbh check and accessors $class"); |
83
|
|
|
|
|
|
|
|
84
|
17
|
50
|
33
|
|
|
145
|
die "can't use database class '$class' without db connection: $DBI::errstr" |
85
|
|
|
|
|
|
|
if ! $class->dbh or $class->dbh eq '0E0'; |
86
|
|
|
|
|
|
|
|
87
|
17
|
50
|
|
|
|
722
|
die "can't retrieve table '".$class->table_name."' columns for '$class'" |
88
|
|
|
|
|
|
|
unless $class->_init_make_accessors; |
89
|
|
|
|
|
|
|
|
90
|
17
|
|
|
|
|
118
|
$t->lap ("init_last $class"); |
91
|
|
|
|
|
|
|
|
92
|
17
|
|
|
|
|
299
|
$class->_init_last; |
93
|
|
|
|
|
|
|
|
94
|
17
|
|
|
|
|
69
|
$t->end; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# my $driver = $class->dbh->get_info (17); |
97
|
|
|
|
|
|
|
# warn "driver name from |
98
|
|
|
|
|
|
|
# get_info ($DBI::Const::GetInfoType{SQL_DBMS_NAME}): $driver"; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
33
|
|
|
|
|
133
|
${"${class}::imported"} = 1; |
|
33
|
|
|
|
|
138
|
|
102
|
|
|
|
|
|
|
|
103
|
33
|
50
|
|
|
|
506
|
$class::SUPER->import (@_) |
104
|
|
|
|
|
|
|
if (defined $class::SUPER); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub _init_db { |
109
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
110
|
0
|
|
|
|
|
0
|
$self->dbh (DBI->connect); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub _init_class { |
114
|
17
|
|
|
17
|
|
44
|
my $self = shift; |
115
|
|
|
|
|
|
|
|
116
|
17
|
|
33
|
|
|
667
|
my $ref = ref $self || $self; |
117
|
|
|
|
|
|
|
|
118
|
17
|
|
|
|
|
111
|
my @pack_chunks = split /\:\:/, $ref; |
119
|
|
|
|
|
|
|
|
120
|
17
|
|
|
|
|
40
|
my $is_collection = 0; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# fix for collections |
123
|
17
|
100
|
|
|
|
82
|
if ($pack_chunks[-1] eq 'Collection') { |
|
|
50
|
|
|
|
|
|
124
|
6
|
|
|
|
|
12
|
pop @pack_chunks; |
125
|
|
|
|
|
|
|
|
126
|
6
|
|
|
|
|
30
|
make_accessor ($ref, 'record_package', is => 'rw', global => 1); |
127
|
|
|
|
|
|
|
|
128
|
6
|
|
|
|
|
215
|
$is_collection = 1; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
} elsif ($pack_chunks[-1] eq 'Record') { |
131
|
0
|
|
|
|
|
0
|
pop @pack_chunks; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
17
|
|
|
|
|
71
|
make_accessor ($ref, 'is_collection', default => $is_collection); |
135
|
|
|
|
|
|
|
|
136
|
17
|
|
|
|
|
992
|
my $table_name = DBI::Easy::Helper::table_from_package ($pack_chunks[-1]); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# dies when this method called without object reference; |
139
|
|
|
|
|
|
|
# expected behaviour |
140
|
|
|
|
|
|
|
|
141
|
17
|
|
|
|
|
43
|
my $common_table_prefix = ''; |
142
|
|
|
|
|
|
|
|
143
|
17
|
100
|
|
|
|
570
|
$common_table_prefix = $ref->common_table_prefix |
144
|
|
|
|
|
|
|
if $ref->can ('common_table_prefix'); |
145
|
|
|
|
|
|
|
|
146
|
17
|
50
|
|
|
|
647
|
make_accessor ( |
147
|
|
|
|
|
|
|
$ref, 'table_name', is => 'rw', global => 1, |
148
|
|
|
|
|
|
|
default => $common_table_prefix . $table_name |
149
|
|
|
|
|
|
|
) unless $ref->can ('table_name'); |
150
|
|
|
|
|
|
|
|
151
|
17
|
|
|
|
|
723
|
make_accessor ($ref, '_date_format', is => 'rw', global => 1); |
152
|
|
|
|
|
|
|
|
153
|
17
|
50
|
|
|
|
786
|
make_accessor ( |
154
|
|
|
|
|
|
|
$ref, 'column_prefix', is => 'rw', global => 1, |
155
|
|
|
|
|
|
|
default => $ref->table_name . "_" |
156
|
|
|
|
|
|
|
) unless $ref->can ('column_prefix'); |
157
|
|
|
|
|
|
|
|
158
|
17
|
|
|
|
|
773
|
make_accessor ($ref, 'fieldset', is => 'rw', default => '*'); |
159
|
|
|
|
|
|
|
|
160
|
17
|
|
|
|
|
749
|
make_accessor ($ref, 'prepare_method', is => 'rw', global => 1, |
161
|
|
|
|
|
|
|
default => 'prepare_cached'); |
162
|
17
|
|
|
|
|
598
|
make_accessor ($ref, 'prepare_param', is => 'rw', global => 1, |
163
|
|
|
|
|
|
|
default => 3); |
164
|
17
|
|
|
|
|
613
|
make_accessor ($ref, 'undef_as_null', is => 'rw', global => 1, |
165
|
|
|
|
|
|
|
default => 0); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
sub _init_collection { |
170
|
6
|
|
|
6
|
|
132
|
my $self = shift; |
171
|
|
|
|
|
|
|
|
172
|
6
|
|
|
|
|
27
|
my $rec_pkg = $self->record_package; |
173
|
|
|
|
|
|
|
|
174
|
6
|
50
|
|
|
|
135
|
unless ($rec_pkg) { |
175
|
6
|
|
33
|
|
|
39
|
my $ref = ref $self || $self; |
176
|
|
|
|
|
|
|
|
177
|
6
|
|
|
|
|
35
|
my @pack_chunks = split /\:\:/, $ref; |
178
|
|
|
|
|
|
|
|
179
|
6
|
|
|
|
|
13
|
pop @pack_chunks; |
180
|
|
|
|
|
|
|
|
181
|
6
|
|
|
|
|
22
|
$rec_pkg = join '::', @pack_chunks; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# TODO: move to Class::Easy |
184
|
6
|
50
|
|
|
|
26
|
unless (try_to_use ($rec_pkg)) { |
185
|
0
|
0
|
|
|
|
0
|
die unless try_to_use ($rec_pkg . '::Record'); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
6
|
|
|
|
|
5727
|
$self->record_package ($rec_pkg); |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub _detect_vendor { |
194
|
17
|
|
|
17
|
|
35
|
my $class = shift; |
195
|
|
|
|
|
|
|
|
196
|
17
|
|
|
|
|
60
|
my $dbh = $class->dbh; |
197
|
|
|
|
|
|
|
|
198
|
17
|
|
|
|
|
390
|
my $vendor = lc ($dbh->get_info(17)); |
199
|
|
|
|
|
|
|
|
200
|
17
|
|
|
|
|
243
|
make_accessor ($class, 'dbh_vendor', default => $vendor); |
201
|
|
|
|
|
|
|
|
202
|
17
|
|
|
|
|
869
|
my $vendor_pack = "DBI::Easy::Vendor::$vendor"; |
203
|
17
|
|
|
|
|
76
|
my $have_vendor_pack = try_to_use_quiet ($vendor_pack); |
204
|
|
|
|
|
|
|
|
205
|
17
|
50
|
|
|
|
15926
|
unless ($have_vendor_pack) { |
206
|
17
|
|
|
|
|
41
|
$vendor_pack = "DBI::Easy::Vendor::Base"; |
207
|
17
|
50
|
|
|
|
60
|
die unless try_to_use_quiet ($vendor_pack); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
6
|
|
|
6
|
|
65
|
no strict 'refs'; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
390
|
|
211
|
|
|
|
|
|
|
|
212
|
17
|
|
|
|
|
2348
|
push @{"$class\::ISA"}, $vendor_pack; |
|
17
|
|
|
|
|
754
|
|
213
|
|
|
|
|
|
|
|
214
|
6
|
|
|
6
|
|
36
|
use strict 'refs'; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
16417
|
|
215
|
|
|
|
|
|
|
|
216
|
17
|
|
|
|
|
256
|
$class->_init_vendor; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# here we retrieve fields and create make_accessors |
221
|
|
|
|
|
|
|
sub _init_make_accessors { |
222
|
17
|
|
|
17
|
|
38
|
my $class = shift; |
223
|
|
|
|
|
|
|
|
224
|
17
|
|
|
|
|
86
|
my $table_name = $class->table_name; |
225
|
17
|
|
|
|
|
125
|
my $column_prefix = $class->column_prefix; |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# detecting vendor |
228
|
17
|
|
|
|
|
220
|
$class->_detect_vendor; |
229
|
|
|
|
|
|
|
|
230
|
17
|
|
|
|
|
150
|
my $t = timer ('columns info wrapper'); |
231
|
|
|
|
|
|
|
|
232
|
17
|
|
|
|
|
1106
|
my $columns = $class->_dbh_columns_info; |
233
|
|
|
|
|
|
|
|
234
|
17
|
|
|
|
|
65
|
$t->end; |
235
|
|
|
|
|
|
|
|
236
|
17
|
|
|
|
|
153
|
make_accessor ($class, 'columns', default => $columns); |
237
|
17
|
|
|
|
|
962
|
make_accessor ($class, 'column_values', is => 'rw'); |
238
|
|
|
|
|
|
|
|
239
|
17
|
|
|
|
|
584
|
my $fields = {}; |
240
|
|
|
|
|
|
|
|
241
|
17
|
|
|
|
|
65
|
make_accessor ($class, 'fields', default => $fields); |
242
|
17
|
|
|
|
|
633
|
make_accessor ($class, 'field_values', is => 'rw'); |
243
|
|
|
|
|
|
|
|
244
|
17
|
|
|
|
|
786
|
my $pri_key; |
245
|
|
|
|
|
|
|
my $pri_key_column; |
246
|
|
|
|
|
|
|
|
247
|
17
|
|
|
|
|
76
|
foreach my $col_name (keys %$columns) { |
248
|
81
|
|
|
|
|
1892
|
my $col_meta = $columns->{$col_name}; |
249
|
|
|
|
|
|
|
# here we translate rows |
250
|
81
|
|
|
|
|
315
|
my $field_name = lc ($col_name); # oracle fix |
251
|
|
|
|
|
|
|
|
252
|
81
|
100
|
33
|
|
|
1304
|
if ( |
|
|
|
66
|
|
|
|
|
253
|
|
|
|
|
|
|
defined $column_prefix |
254
|
|
|
|
|
|
|
and $column_prefix ne '' |
255
|
|
|
|
|
|
|
and $col_name =~ /^$column_prefix(.*)/i |
256
|
|
|
|
|
|
|
) { |
257
|
32
|
|
|
|
|
166
|
$field_name = lc($1); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# field meta referenced to column meta |
261
|
|
|
|
|
|
|
# no we can use $field_meta->{col_name} and $col_meta->{field_name} |
262
|
81
|
|
|
|
|
182
|
$fields->{$field_name} = $col_meta; |
263
|
|
|
|
|
|
|
|
264
|
81
|
|
|
|
|
175
|
$col_meta->{field_name} = $field_name; |
265
|
|
|
|
|
|
|
|
266
|
81
|
50
|
33
|
|
|
251
|
if ($col_meta->{type_name} eq 'ENUM' and $#{$col_meta->{mysql_values}} >= 0) { |
|
0
|
|
|
|
|
0
|
|
267
|
0
|
|
|
|
|
0
|
make_accessor ($class, "${field_name}_variants", |
268
|
|
|
|
|
|
|
default => $col_meta->{mysql_values}); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# attach decoder for complex datatypes, as example date, datetime, timestamp |
272
|
81
|
|
|
|
|
387
|
$class->attach_decoder ($col_meta); |
273
|
|
|
|
|
|
|
|
274
|
81
|
100
|
66
|
|
|
383
|
if (exists $col_meta->{X_IS_PK} and $col_meta->{X_IS_PK} == 1) { |
275
|
|
|
|
|
|
|
|
276
|
17
|
50
|
|
|
|
64
|
if ($pri_key) { |
277
|
0
|
|
|
|
|
0
|
warn "multiple pri keys: $fields->{$pri_key}->{column_name} and $field_name"; |
278
|
|
|
|
|
|
|
} else { |
279
|
17
|
|
|
|
|
35
|
$pri_key = $field_name; |
280
|
17
|
|
|
|
|
48
|
$pri_key_column = $col_name; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
my $fetch_by_pk_sub = sub { |
284
|
5
|
|
|
5
|
|
97
|
my $package = shift; |
285
|
5
|
|
|
|
|
9
|
my $value = shift; |
286
|
|
|
|
|
|
|
|
287
|
5
|
|
|
|
|
74
|
return $package->fetch ({$field_name => $value}, @_); |
288
|
17
|
|
|
|
|
99
|
}; |
289
|
|
|
|
|
|
|
|
290
|
17
|
|
|
|
|
83
|
make_accessor ($class, "fetch_by_$field_name", default => $fetch_by_pk_sub); |
291
|
17
|
|
|
|
|
608
|
make_accessor ($class, "fetch_by_pk", default => $fetch_by_pk_sub); |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# access to the precise field value or column value without cool accessors |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
make_accessor ($class, $field_name, default => sub { |
297
|
47
|
|
|
47
|
|
6823
|
my $self = shift; |
298
|
|
|
|
|
|
|
|
299
|
47
|
100
|
|
|
|
163
|
unless (@_) { |
300
|
|
|
|
|
|
|
# bad style? |
301
|
|
|
|
|
|
|
return |
302
|
44
|
|
66
|
|
|
436
|
$self->{field_values}->{$field_name} || ( |
303
|
|
|
|
|
|
|
exists $self->columns->{$col_name}->{decoder} |
304
|
|
|
|
|
|
|
? $self->columns->{$col_name}->{decoder}->($self) # ($self->{column_values}->{$col_name}); |
305
|
|
|
|
|
|
|
: $self->{column_values}->{$col_name}); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
3
|
50
|
|
|
|
18
|
die "too many parameters" if @_ > 1; |
309
|
|
|
|
|
|
|
|
310
|
3
|
|
|
|
|
49
|
$self->assign_values ($field_name => $_[0]); |
311
|
|
|
|
|
|
|
|
312
|
81
|
|
|
|
|
920
|
}); |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
make_accessor ($class, "_fetched_${field_name}", default => sub { |
315
|
1
|
|
|
1
|
|
564
|
my $self = shift; |
316
|
|
|
|
|
|
|
|
317
|
1
|
50
|
|
|
|
5
|
unless (@_) { |
318
|
1
|
|
|
|
|
7
|
return $self->{column_values}->{$col_name}; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
0
|
die "too many parameters"; |
322
|
81
|
|
|
|
|
3123
|
}); |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
make_accessor ($class, "_raw_${field_name}", default => sub { |
325
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
326
|
|
|
|
|
|
|
|
327
|
1
|
50
|
|
|
|
6
|
die "you must supply one parameter" unless @_ == 1; |
328
|
|
|
|
|
|
|
|
329
|
1
|
|
|
|
|
5
|
$self->{field_values}->{$field_name} = $_[0]; |
330
|
81
|
|
|
|
|
3476
|
}); |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
17
|
|
|
|
|
1238
|
make_accessor ($class, '_pk_', default => $pri_key); |
335
|
17
|
|
|
|
|
559
|
make_accessor ($class, '_pk_column_', default => $pri_key_column); |
336
|
|
|
|
|
|
|
|
337
|
17
|
|
|
|
|
950
|
return $class; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub assign_values { |
341
|
3
|
|
|
3
|
0
|
6
|
my $self = shift; |
342
|
3
|
|
|
|
|
12
|
my $to_assign = {@_}; |
343
|
|
|
|
|
|
|
|
344
|
3
|
|
|
|
|
15
|
foreach my $k (keys %$to_assign) { |
345
|
3
|
|
|
|
|
26
|
$self->{field_values}->{$k} = $to_assign->{$k}; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub attach_decoder { |
350
|
81
|
|
|
81
|
0
|
113
|
my $class = shift; |
351
|
81
|
|
|
|
|
98
|
my $col_meta = shift; |
352
|
|
|
|
|
|
|
|
353
|
81
|
|
|
|
|
132
|
my $type = $col_meta->{type_name}; |
354
|
|
|
|
|
|
|
|
355
|
81
|
50
|
33
|
|
|
452
|
if (defined $type and $H->is_rich_type ($type)) { |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
$col_meta->{decoder} = sub { |
358
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
359
|
0
|
|
|
|
|
0
|
my $value = $self->column_values->{$col_meta->{column_name}}; |
360
|
0
|
|
|
|
|
0
|
return $H->value_from_type ($type, $value, $self); |
361
|
|
|
|
|
|
|
} |
362
|
0
|
|
|
|
|
0
|
} |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
|
366
|
17
|
|
|
17
|
|
29
|
sub _init_last { |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub _dbh_columns_info { |
371
|
17
|
|
|
17
|
|
41
|
my $class = shift; |
372
|
|
|
|
|
|
|
|
373
|
17
|
|
|
|
|
58
|
my $ts = timer ('inside columns info'); |
374
|
|
|
|
|
|
|
|
375
|
17
|
|
|
|
|
853
|
my $dbh = $class->dbh; |
376
|
|
|
|
|
|
|
|
377
|
17
|
|
|
|
|
128
|
my $table_name = $class->table_name; |
378
|
|
|
|
|
|
|
|
379
|
17
|
|
|
|
|
115
|
$ts->lap ('make accessor'); |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# preparations |
382
|
17
|
|
|
|
|
300
|
make_accessor ( |
383
|
|
|
|
|
|
|
$class, 'table_quoted', |
384
|
|
|
|
|
|
|
default => $class->quote_identifier ($table_name) |
385
|
|
|
|
|
|
|
); |
386
|
|
|
|
|
|
|
|
387
|
17
|
|
|
|
|
1536
|
my $real_row_count = 0; |
388
|
|
|
|
|
|
|
|
389
|
17
|
|
|
|
|
39
|
my $column_info = {}; |
390
|
|
|
|
|
|
|
|
391
|
17
|
|
|
|
|
68
|
$ts->lap ('eval column info'); |
392
|
|
|
|
|
|
|
|
393
|
17
|
|
|
|
|
106
|
eval { |
394
|
|
|
|
|
|
|
|
395
|
17
|
|
|
|
|
56
|
my $t = timer ('column info call'); |
396
|
|
|
|
|
|
|
|
397
|
17
|
|
|
|
|
795
|
my $sth = $dbh->column_info( |
398
|
|
|
|
|
|
|
undef, undef, $table_name, '%' |
399
|
|
|
|
|
|
|
); |
400
|
|
|
|
|
|
|
|
401
|
17
|
|
|
|
|
53856
|
$t->lap ('execute'); |
402
|
|
|
|
|
|
|
|
403
|
17
|
50
|
|
|
|
243
|
$sth->execute |
404
|
|
|
|
|
|
|
unless $sth->{Executed}; |
405
|
|
|
|
|
|
|
|
406
|
17
|
|
|
|
|
1347
|
$t->lap ('fetchrow hashref'); |
407
|
|
|
|
|
|
|
|
408
|
17
|
|
|
|
|
275
|
while (my $row = $sth->fetchrow_hashref) { |
409
|
81
|
|
|
|
|
2361
|
$real_row_count ++; |
410
|
|
|
|
|
|
|
|
411
|
81
|
|
|
|
|
150
|
my $column_name = $row->{COLUMN_NAME}; |
412
|
|
|
|
|
|
|
|
413
|
81
|
|
|
|
|
907
|
$column_info->{$column_name} = { |
414
|
|
|
|
|
|
|
(map { |
415
|
1458
|
|
|
|
|
2710
|
lc($_) => $row->{$_} |
416
|
|
|
|
|
|
|
} grep { |
417
|
81
|
|
|
|
|
354
|
exists $GREP_COLUMN_INFO{$_} |
418
|
|
|
|
|
|
|
} keys %$row), |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
column_name => $column_name, |
421
|
|
|
|
|
|
|
quoted_column_name => $dbh->quote_identifier ($column_name), |
422
|
|
|
|
|
|
|
nullable => $row->{NULLABLE}, |
423
|
|
|
|
|
|
|
}; |
424
|
|
|
|
|
|
|
|
425
|
81
|
|
|
|
|
2414
|
my $default_val = $row->{COLUMN_DEF}; |
426
|
81
|
100
|
|
|
|
1084
|
if (defined $default_val) { |
427
|
5
|
|
|
|
|
89
|
$default_val =~ s/^"(.*)"$/$1/; |
428
|
5
|
|
|
|
|
84
|
$column_info->{$column_name}->{default} = $default_val; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
17
|
|
|
|
|
630
|
$t->end; |
434
|
|
|
|
|
|
|
|
435
|
17
|
|
|
|
|
674
|
$t->total; |
436
|
|
|
|
|
|
|
|
437
|
17
|
50
|
|
|
|
967
|
if ($real_row_count == 0) { |
438
|
0
|
|
|
|
|
0
|
die "no rows for table '$table_name' fetched"; |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
}; |
441
|
|
|
|
|
|
|
|
442
|
17
|
|
|
|
|
79
|
$ts->lap ('_dbh_error'); |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
return |
445
|
17
|
50
|
|
|
|
753
|
if $class->_dbh_error ($@); |
446
|
|
|
|
|
|
|
|
447
|
17
|
|
|
|
|
31
|
$real_row_count = 0; |
448
|
|
|
|
|
|
|
|
449
|
17
|
|
|
|
|
66
|
$ts->lap ('primary_key_info'); |
450
|
|
|
|
|
|
|
|
451
|
17
|
|
|
|
|
109
|
eval { |
452
|
|
|
|
|
|
|
|
453
|
17
|
|
|
|
|
76
|
my $t = timer ('primary key'); |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# fuckin oracle |
456
|
17
|
|
|
|
|
1105
|
my $schema = $class->vendor_schema; |
457
|
|
|
|
|
|
|
|
458
|
17
|
|
|
|
|
152
|
my $sth = $dbh->primary_key_info( |
459
|
|
|
|
|
|
|
undef, $schema, $table_name |
460
|
|
|
|
|
|
|
); |
461
|
|
|
|
|
|
|
|
462
|
17
|
|
|
|
|
25351
|
$t->lap ('execute'); |
463
|
|
|
|
|
|
|
|
464
|
17
|
50
|
|
|
|
168
|
if ($sth) { |
465
|
17
|
50
|
|
|
|
116
|
$sth->execute |
466
|
|
|
|
|
|
|
unless $sth->{Executed}; |
467
|
|
|
|
|
|
|
|
468
|
17
|
|
|
|
|
512
|
$t->lap ('fetchrow'); |
469
|
|
|
|
|
|
|
|
470
|
17
|
|
|
|
|
466
|
while (my $row = $sth->fetchrow_hashref) { |
471
|
17
|
|
|
|
|
330
|
$real_row_count ++; |
472
|
|
|
|
|
|
|
# here we translate rows |
473
|
17
|
|
|
|
|
45
|
my $pri_key_name = $row->{COLUMN_NAME}; |
474
|
|
|
|
|
|
|
|
475
|
17
|
|
|
|
|
64
|
$column_info->{$row->{COLUMN_NAME}}->{X_IS_PK} = 1; |
476
|
17
|
|
|
|
|
212
|
$column_info->{$row->{COLUMN_NAME}}->{nullable} = 0; |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
17
|
|
|
|
|
303
|
$t->end; |
482
|
|
|
|
|
|
|
|
483
|
17
|
|
|
|
|
109
|
$t->total; |
484
|
|
|
|
|
|
|
|
485
|
17
|
50
|
|
|
|
796
|
if ($real_row_count == 0) { |
486
|
0
|
|
|
|
|
0
|
warn "no primary keys for table '$table_name'"; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
}; |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
return |
491
|
17
|
50
|
|
|
|
75
|
if $class->_dbh_error ($@); |
492
|
|
|
|
|
|
|
|
493
|
17
|
|
|
|
|
62
|
$ts->end; |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
#Hash::Util::lock_hash_recurse (%$column_info); |
496
|
|
|
|
|
|
|
|
497
|
17
|
|
|
|
|
127
|
return $column_info; |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
sub _dbh_error { |
501
|
102
|
|
|
102
|
|
251
|
my $self = shift; |
502
|
102
|
|
|
|
|
219
|
my $error = shift; |
503
|
102
|
|
|
|
|
193
|
my $statement = shift; |
504
|
|
|
|
|
|
|
|
505
|
102
|
50
|
|
|
|
584
|
return unless $error; |
506
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
0
|
my @caller = caller (1); |
508
|
0
|
|
|
|
|
0
|
my @caller2 = caller (2); |
509
|
|
|
|
|
|
|
|
510
|
0
|
0
|
0
|
|
|
0
|
if ($DBI::Easy::ERRHANDLER and ref $DBI::Easy::ERRHANDLER eq 'CODE') { |
511
|
0
|
|
|
|
|
0
|
&$DBI::Easy::ERRHANDLER ($self, $error, $statement); |
512
|
|
|
|
|
|
|
} else { |
513
|
0
|
|
|
|
|
0
|
warn ("[db error at $caller[3] ($caller[2]) called at $caller2[3] ($caller2[2])] ", |
514
|
|
|
|
|
|
|
$error |
515
|
|
|
|
|
|
|
); |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
0
|
0
|
|
|
|
0
|
if ($self->{in_transaction}) { |
519
|
0
|
|
|
|
|
0
|
eval {$self->rollback}; |
|
0
|
|
|
|
|
0
|
|
520
|
0
|
|
|
|
|
0
|
die $error; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
0
|
|
|
|
|
0
|
return 1; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
528
|
|
|
|
|
|
|
# we always work with one table or view. |
529
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
sub _prefix_manipulations { |
532
|
107
|
|
|
107
|
|
160
|
my $self = shift; |
533
|
107
|
|
|
|
|
149
|
my $dir = shift; |
534
|
107
|
|
|
|
|
246
|
my $values = shift; |
535
|
107
|
|
50
|
|
|
474
|
my $in_place = shift || 0; |
536
|
|
|
|
|
|
|
|
537
|
107
|
|
|
|
|
445
|
my $entities; |
538
|
|
|
|
|
|
|
my $ent_key; |
539
|
0
|
|
|
|
|
0
|
my $convert; |
540
|
107
|
50
|
|
|
|
309
|
if ($dir eq 'fields2cols') { |
|
|
0
|
|
|
|
|
|
541
|
107
|
|
|
|
|
633
|
$entities = $self->fields; |
542
|
107
|
|
|
|
|
554
|
$ent_key = 'column_name'; |
543
|
107
|
|
|
|
|
291
|
$convert = 'value_to_type'; |
544
|
107
|
100
|
|
|
|
508
|
$values = $self->field_values |
545
|
|
|
|
|
|
|
unless $values; |
546
|
|
|
|
|
|
|
} elsif ($dir eq 'cols2fields') { |
547
|
0
|
|
|
|
|
0
|
$entities = $self->cols; |
548
|
0
|
|
|
|
|
0
|
$ent_key = 'field_name'; |
549
|
0
|
|
|
|
|
0
|
$convert = 'value_from_type'; |
550
|
0
|
0
|
|
|
|
0
|
$values = $self->column_values |
551
|
|
|
|
|
|
|
unless $values; |
552
|
|
|
|
|
|
|
} else { |
553
|
0
|
|
|
|
|
0
|
die "you can't call _prefix_manipulations without direction"; |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
|
556
|
107
|
100
|
|
|
|
575
|
return $values if ! ref $values; |
557
|
|
|
|
|
|
|
|
558
|
79
|
|
|
|
|
110
|
my $place = $values; |
559
|
79
|
50
|
|
|
|
362
|
unless ($in_place) { |
560
|
79
|
|
|
|
|
257
|
$place = {}; |
561
|
|
|
|
|
|
|
} |
562
|
|
|
|
|
|
|
|
563
|
79
|
|
|
|
|
289
|
foreach (keys %$values) { |
564
|
|
|
|
|
|
|
|
565
|
84
|
50
|
66
|
|
|
467
|
next unless exists $entities->{$_} or /^[_:-]\w+$/; |
566
|
|
|
|
|
|
|
#&& ($self->undef_as_null || defined $entities->{$_}) |
567
|
|
|
|
|
|
|
|
568
|
84
|
100
|
|
|
|
302
|
if (/^:\w+$/) { # copy placeholders |
569
|
1
|
50
|
|
|
|
4
|
unless ($in_place) { |
570
|
1
|
|
|
|
|
3
|
$place->{$_} = $values->{$_}; |
571
|
|
|
|
|
|
|
} |
572
|
1
|
|
|
|
|
4
|
next; |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
# next if $ent->{$ent_key} eq $_ and $in_place; # |
575
|
83
|
|
|
|
|
498
|
my ($column_prefix, $k) = (/^(_?)(\w+)$/); |
576
|
83
|
50
|
|
|
|
228
|
$column_prefix = '' |
577
|
|
|
|
|
|
|
unless defined $column_prefix; |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# debug $k, $_; |
580
|
|
|
|
|
|
|
|
581
|
83
|
|
|
|
|
171
|
my $ent = $entities->{$k}; |
582
|
83
|
|
|
|
|
174
|
my $value = $values->{$_}; |
583
|
|
|
|
|
|
|
|
584
|
83
|
50
|
|
|
|
193
|
if ($in_place) { |
585
|
0
|
|
|
|
|
0
|
delete $values->{$_}; |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
|
588
|
83
|
|
|
|
|
351
|
my $v = $value; |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# we must convert only convertible values |
591
|
|
|
|
|
|
|
# field => 'value' |
592
|
|
|
|
|
|
|
# _field => {'>', 'value'} |
593
|
83
|
100
|
66
|
|
|
364
|
if ($column_prefix eq '') { |
|
|
100
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
594
|
73
|
|
|
|
|
1151
|
$v = $H->$convert ( |
595
|
|
|
|
|
|
|
$ent->{type_name}, $value, $self |
596
|
|
|
|
|
|
|
); |
597
|
|
|
|
|
|
|
} elsif ( |
598
|
|
|
|
|
|
|
$column_prefix eq '_' and ref $value and ref $value eq 'HASH' |
599
|
|
|
|
|
|
|
and keys %$value == 1 |
600
|
|
|
|
|
|
|
) { |
601
|
3
|
|
|
|
|
8
|
my $condition = (keys %$value)[0]; |
602
|
3
|
|
|
|
|
23
|
$v = $condition . $self->quote ($H->$convert ( |
603
|
|
|
|
|
|
|
$ent->{type_name}, $value->{$condition}, $self |
604
|
|
|
|
|
|
|
)); |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
83
|
50
|
|
|
|
317
|
next unless exists $ent->{$ent_key}; |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
# warn "$prefix/$ent_key => $ent->{$ent_key}"; |
610
|
83
|
|
|
|
|
382
|
$place->{$column_prefix . $ent->{$ent_key}} = $v; |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
79
|
50
|
|
|
|
662
|
return $place |
614
|
|
|
|
|
|
|
unless $in_place; |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
sub fields_to_columns { |
619
|
107
|
|
|
107
|
0
|
191
|
my $self = shift; |
620
|
|
|
|
|
|
|
|
621
|
107
|
|
|
|
|
541
|
$self->_prefix_manipulations ('fields2cols', shift, 0); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
sub columns_to_fields { |
625
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
626
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
$self->_prefix_manipulations ('cols2fields', shift, 0); |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
631
|
|
|
|
|
|
|
# we always work with one table or view. |
632
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
636
|
|
|
|
|
|
|
# simplified sql execute |
637
|
|
|
|
|
|
|
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
1; |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=head1 NAME |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
DBI::Easy - yet another perl ORM for SQL databases |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=head1 DESCRIPTION |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
DBI::Easy is another ORM, aimed at making the life of the developer |
650
|
|
|
|
|
|
|
using it a lot easier. |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=head1 INTRODUCTION |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
The key notions of DBI::Easy are data records, collection of data records |
655
|
|
|
|
|
|
|
and relations between them. A data record is a presentation of SQL result: |
656
|
|
|
|
|
|
|
row or blessed hash, depending on how you look at it. Data records collection |
657
|
|
|
|
|
|
|
is a set of records limited by certain criteria or without any limitations. |
658
|
|
|
|
|
|
|
the differentiation between collections and records has to do with |
659
|
|
|
|
|
|
|
different relations between them: one-to-one, one-to-many, many-to-many. |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
For Example: Within a domain auction based on DBI::Easy, every user may |
662
|
|
|
|
|
|
|
have a few bids, but each bid belongs to just one concrete user. |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
It's also worth mentioning the relations between DBI::Easy and SQL. DBI::Easy |
665
|
|
|
|
|
|
|
is currently using a small set of sql, limited to tables and views, |
666
|
|
|
|
|
|
|
including four operations to work with data: insert, update, select, delete. |
667
|
|
|
|
|
|
|
The relations between SQL objects are not formed automatically with the help |
668
|
|
|
|
|
|
|
of constraints. |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
Also it's important that DBI::Easy is not trying to hide SQL from you. |
671
|
|
|
|
|
|
|
If you need it you can use it fully. However, it allows carrying out the vast |
672
|
|
|
|
|
|
|
majority of simple operations with data without the participation of SQL. |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=head1 SYNOPSIS |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
Let's start from the most simple things. To start the work you will need two |
677
|
|
|
|
|
|
|
modules that will return database handler ($dbh) upon request. |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
To avoid unpleasant consequences it's recommended to cache the returned |
680
|
|
|
|
|
|
|
connection only after the fork, if there is a fork in your code. |
681
|
|
|
|
|
|
|
for the case when CL environment variables for DBI_DSN and DBI_* are defined, |
682
|
|
|
|
|
|
|
and they can be used to establish a connection that doesn't need to be cached, |
683
|
|
|
|
|
|
|
you can do without these modules at all. The main task for 'Entity' is to |
684
|
|
|
|
|
|
|
acquire DBI::Easy::Record[::Collection] or one of the child classes. |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
package DBEntity; |
687
|
|
|
|
|
|
|
use strict; |
688
|
|
|
|
|
|
|
use DBI; |
689
|
|
|
|
|
|
|
use DBI::Easy::Record; |
690
|
|
|
|
|
|
|
use base qw(DBI::Easy::Record); |
691
|
|
|
|
|
|
|
sub dbh { # optional. You don't have to write a procedure similar |
692
|
|
|
|
|
|
|
# to this one since DBI->connect is requested |
693
|
|
|
|
|
|
|
# when a ready $dbh hasn't been provided |
694
|
|
|
|
|
|
|
return DBI->connect; |
695
|
|
|
|
|
|
|
}; |
696
|
|
|
|
|
|
|
1; |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
#----------------------------------------- |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
package DBEntity::Collection; |
701
|
|
|
|
|
|
|
use strict; |
702
|
|
|
|
|
|
|
use DBI::Easy::Record::Collection; |
703
|
|
|
|
|
|
|
use base qw(DBI::Easy::Record::Collection); |
704
|
|
|
|
|
|
|
1; |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
Now let's get down to something concrete. Let's assume we have a user and his |
707
|
|
|
|
|
|
|
passport data (one-to-one relation) and some contact data (one-to-many) |
708
|
|
|
|
|
|
|
NOTE: the many-to-many relations hasn't been realized yet. |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
package Entity::Passport; |
712
|
|
|
|
|
|
|
use strict; |
713
|
|
|
|
|
|
|
use DBEntity; |
714
|
|
|
|
|
|
|
use base qw(DBEntity); |
715
|
|
|
|
|
|
|
1; |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
#----------------------------------------- |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
package Entity::Contact; |
720
|
|
|
|
|
|
|
use strict; |
721
|
|
|
|
|
|
|
use DBEntity; |
722
|
|
|
|
|
|
|
use base qw(DBEntity); |
723
|
|
|
|
|
|
|
1; |
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
#----------------------------------------- |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
package Entity::Contact::Collection; |
728
|
|
|
|
|
|
|
use strict; |
729
|
|
|
|
|
|
|
use DBEntity::Collection; |
730
|
|
|
|
|
|
|
use base qw(DBEntity::Collection); |
731
|
|
|
|
|
|
|
1; |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
#----------------------------------------- |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
package Entity::Account; |
736
|
|
|
|
|
|
|
use strict; |
737
|
|
|
|
|
|
|
use DBEntity; |
738
|
|
|
|
|
|
|
use base qw(DBEntity); |
739
|
|
|
|
|
|
|
use Entity::Passport; |
740
|
|
|
|
|
|
|
use Entity::Contact::Collection; |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
sub _init_last { |
743
|
|
|
|
|
|
|
my $self = shift; |
744
|
|
|
|
|
|
|
$self->is_related_to ( |
745
|
|
|
|
|
|
|
passport => 'Entity::Passport' |
746
|
|
|
|
|
|
|
); |
747
|
|
|
|
|
|
|
$self->is_related_to ( |
748
|
|
|
|
|
|
|
contacts => 'Entity::Contact::Collection' |
749
|
|
|
|
|
|
|
); |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
1; |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
#----------------------------------------- |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
package Entity::Account::Collection; |
756
|
|
|
|
|
|
|
use strict; |
757
|
|
|
|
|
|
|
use DBEntity::Collection; |
758
|
|
|
|
|
|
|
use base qw(DBEntity::Collection); |
759
|
|
|
|
|
|
|
1; |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
#----------------------------------------- |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
Now let's create some SQL tables for our test application (using SQLite): |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
create table account ( |
766
|
|
|
|
|
|
|
account_id serial not null primary key, |
767
|
|
|
|
|
|
|
account_login varchar (50) not null |
768
|
|
|
|
|
|
|
); |
769
|
|
|
|
|
|
|
create table pasport ( |
770
|
|
|
|
|
|
|
passport_id serial not null primary key, |
771
|
|
|
|
|
|
|
passport_serial varchar (50) not null, |
772
|
|
|
|
|
|
|
account_id integer |
773
|
|
|
|
|
|
|
); |
774
|
|
|
|
|
|
|
create table contact ( |
775
|
|
|
|
|
|
|
contact_id serial not null primary key, |
776
|
|
|
|
|
|
|
contact_proto varchar (10) not null, |
777
|
|
|
|
|
|
|
contact_address varchar (200) not null, |
778
|
|
|
|
|
|
|
account_id integer |
779
|
|
|
|
|
|
|
); |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
And now the funniest part: the script itself: |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
#----------------------------------------- |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
#!/usr/bin/perl |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
use strict; |
788
|
|
|
|
|
|
|
use Entity::Account; |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
# here it doesn`t matter whether there is a user with such a login in |
791
|
|
|
|
|
|
|
# the database, if needed we can create it. |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
my $account = Entity::Account->fetch_or_create ({login => 'apla'}); |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
# here fetch_or_create is implicitly activated with the parameters |
796
|
|
|
|
|
|
|
# {id => $account->id, serial => 'aabbcc'} |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
$account->passport ({serial => 'aabbcc'}); |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
my $acc_contacts = $account->contacts; |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
my $contact = $acc_contacts->new_record ({ |
803
|
|
|
|
|
|
|
proto => 'email', address => 'apla@localhost' |
804
|
|
|
|
|
|
|
}); |
805
|
|
|
|
|
|
|
$contact->save; |
806
|
|
|
|
|
|
|
$acc_contacts->count; |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
1; |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=head1 AUTHOR |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
Ivan Baktsheev, C<< >> |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=head1 BUGS |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
Please report any bugs or feature requests to my email address, |
819
|
|
|
|
|
|
|
or through the web interface at L. |
820
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified |
821
|
|
|
|
|
|
|
of progress on your bug as I make changes. |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
=head1 SUPPORT |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Copyright 2008-2009 Ivan Baktsheev |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
836
|
|
|
|
|
|
|
under the same terms as Perl itself. |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
=cut |
839
|
|
|
|
|
|
|
|