first commit
|
1 |
package DBI::Custom; |
2 |
use Object::Simple; |
|
add some method
|
3 |
use DBI; |
4 |
use SQL::Abstract; |
|
first commit
|
5 | |
cleanup
|
6 |
# Model |
7 |
sub model : ClassAttr { auto_build => \&_inherit_model } |
|
first commit
|
8 | |
cleanup
|
9 |
# Inherit super class model |
10 |
sub _inherit_model { |
|
11 |
$class = shict; |
|
12 |
my $super = do { |
|
13 |
no strict 'refs'; |
|
14 |
${"${class}::ISA"}[0]; |
|
15 |
}; |
|
16 |
my $model = eval{$super->can('model')} |
|
17 |
? $super->model->clone |
|
18 |
: $class->Object::Simple::new; |
|
cleanup
|
19 |
|
20 |
$class->model($model); |
|
first commit
|
21 |
} |
22 | ||
cleanup
|
23 |
# New |
24 |
sub new { |
|
25 |
my $self = shift->Object::Simple::new(@_); |
|
26 |
my $class = ref $self; |
|
27 |
return bless {%{$class->model->clone}, %{$self}}, $class; |
|
first commit
|
28 |
} |
29 | ||
cleanup
|
30 |
# Initialize modle |
31 |
sub initialize_model { |
|
32 |
my ($class, $callback) = @_; |
|
first commit
|
33 |
|
cleanup
|
34 |
# Callback to initialize model |
35 |
$callback->($class->model); |
|
first commit
|
36 |
} |
37 | ||
cleanup
|
38 |
# Clone |
39 |
sub clone { |
|
cleanup
|
40 |
my $self = shift; |
cleanup
|
41 |
my $new = $self->Object::Simple::new; |
42 |
$new->connect_infos(%{$self->connect_infos || {}}); |
|
43 |
$new->filters(%{$self->filters || {}}); |
|
cleanup
|
44 |
|
cleanup
|
45 |
$new->global_bind_rules(@{$self->global_bind_rules || []}); |
46 |
$new->global_fetch_rules(@{$self->global_fetch_rules || []}); |
|
cleanup
|
47 |
|
cleanup
|
48 |
foreach my $method (qw/bind_rules fetch_rules/) { |
49 |
my $new_rules = []; |
|
50 |
foreach my $rule (@{$self->method}) { |
|
51 |
my $new_rule = {}; |
|
52 |
foreach my $key ($rule) { |
|
53 |
if ($key eq 'filter') { |
|
54 |
my $new_filters = []; |
|
55 |
foreach my $filter (@{$rule->{$key} || []}) { |
|
56 |
push @$new_filters, $filter |
|
57 |
} |
|
58 |
$new_rule->{$key} = $new_filters; |
|
59 |
} |
|
60 |
else { |
|
61 |
$new_rule->{$key} = $rule->{$key}; |
|
62 |
} |
|
63 |
} |
|
64 |
push @$new_rules, $new_rule; |
|
65 |
} |
|
66 |
$self->$method($new_rules); |
|
cleanup
|
67 |
} |
68 |
} |
|
69 | ||
cleanup
|
70 |
# Attribute |
71 |
sub connect_info : Attr { type => 'hash', auto_build => sub { shift->connect_info({}) } } |
|
cleanup
|
72 | |
cleanup
|
73 |
sub global_bind_rules : Attr { type => 'array', auto_build => sub { shift->global_bind_rules([]) } } |
cleanup
|
74 |
sub add_global_bind_rule { shift->global_bind_rules(@_) } |
75 | ||
cleanup
|
76 |
sub global_fetch_rules : Attr { type => 'array', auto_build => sub { shift->global_fetch_rules([]) } } |
cleanup
|
77 |
sub add_global_fetch_rules { shift->global_fetch_rules(@_) } |
78 | ||
79 |
sub bind_rules : Attr { type => 'hash', auto_build => sub { shift->bind_rules({}) } |
|
80 |
sub add_bind_rule { shift->bind_rules(@_) } |
|
81 | ||
82 |
sub fetch_rules : Attr { type => 'hash', auto_build => sub { shift->fetch_rules({}) } |
|
83 |
sub add_fetch_rule { shift->fetch_rules(@_) } |
|
84 | ||
85 |
sub filters : Attr { type => 'hash', deref => 1, default => sub { {} } } |
|
86 |
sub add_filter { shift->filters(@_) } |
|
87 | ||
cleanup
|
88 | |
89 |
sub dbh : Attr { auto_build => sub { shift->connect } } |
|
90 |
sub sql_abstract : Attr { auto_build => sub { shift->sql_abstract(SQL::Abstract->new) }} |
|
cleanup
|
91 | |
add some method
|
92 |
sub connect { |
93 |
my $self = shift; |
|
94 |
my $connect_info = $self->connect_info; |
|
95 |
|
|
96 |
my $dbh = DBI->connect( |
|
97 |
$connect_info->{dsn}, |
|
98 |
$connect_info->{user}, |
|
99 |
$connect_info->{password}, |
|
100 |
{ |
|
101 |
RaiseError => 1, |
|
102 |
PrintError => 0, |
|
103 |
AutoCommit => 1, |
|
104 |
%{$connect_info->{options} || {} } |
|
105 |
} |
|
106 |
); |
|
107 |
|
|
108 |
$self->dbh($dbh); |
|
109 |
} |
|
first commit
|
110 | |
add some method
|
111 |
sub reconnect { |
112 |
my $self = shift; |
|
113 |
$self->dbh(undef); |
|
114 |
$self->connect; |
|
115 |
} |
|
first commit
|
116 | |
add some method
|
117 |
sub query { |
118 |
my ($self, $query, @binds) = @_; |
|
119 |
$self->{success} = 0; |
|
120 | ||
121 |
$self->_replace_omniholder(\$query, \@binds); |
|
122 | ||
123 |
my $st; |
|
124 |
my $sth; |
|
125 | ||
126 |
my $old = $old_statements{$self}; |
|
127 | ||
128 |
if (my $i = (grep $old->[$_][0] eq $query, 0..$#$old)[0]) { |
|
129 |
$st = splice(@$old, $i, 1)->[1]; |
|
130 |
$sth = $st->{sth}; |
|
131 |
} else { |
|
132 |
eval { $sth = $self->{dbh}->prepare($query) } or do { |
|
133 |
if ($@) { |
|
134 |
$@ =~ s/ at \S+ line \d+\.\n\z//; |
|
135 |
Carp::croak($@); |
|
136 |
} |
|
137 |
$self->{reason} = "Prepare failed ($DBI::errstr)"; |
|
138 |
return _dummy; |
|
139 |
}; |
|
140 | ||
141 |
# $self is quoted on purpose, to pass along the stringified version, |
|
142 |
# and avoid increasing reference count. |
|
143 |
$st = bless { |
|
144 |
db => "$self", |
|
145 |
sth => $sth, |
|
146 |
query => $query |
|
147 |
}, 'DBIx::Simple::Statement'; |
|
148 |
$statements{$self}{$st} = $st; |
|
149 |
} |
|
first commit
|
150 | |
add some method
|
151 |
eval { $sth->execute(@binds) } or do { |
152 |
if ($@) { |
|
153 |
$@ =~ s/ at \S+ line \d+\.\n\z//; |
|
154 |
Carp::croak($@); |
|
155 |
} |
|
first commit
|
156 | |
add some method
|
157 |
$self->{reason} = "Execute failed ($DBI::errstr)"; |
158 |
return _dummy; |
|
159 |
}; |
|
160 | ||
161 |
$self->{success} = 1; |
|
162 | ||
163 |
return bless { st => $st, lc_columns => $self->{lc_columns} }, $self->{result_class}; |
|
164 |
} |
|
165 | ||
166 |
sub query { |
|
167 |
my ($self, $sql) = @_; |
|
168 |
my $sth = $self->dbh->prepare($sql); |
|
169 |
$sth->execute(@bind); |
|
170 |
} |
|
171 | ||
172 |
sub select { |
|
173 |
my ($table, $column_names, $where, $order) = @_; |
|
first commit
|
174 |
|
add some method
|
175 |
my ($stmt, @bind) = $self->sql_abstract->select($table, $column_names, $where, $order); |
176 |
my $sth = $self->dbh->prepare($stmt); |
|
177 |
$sth->execute(@bind); |
|
178 |
} |
|
179 | ||
180 |
sub insert { |
|
181 |
my ($self, $table, $values) = @_; |
|
first commit
|
182 |
|
add some method
|
183 |
my ($stmt, @bind) = $self->sql_abstract->insert($table, $values); |
184 |
my $sth = $self->dbh->prepare($stmt); |
|
185 |
$sth->execute(@bind); |
|
186 |
} |
|
187 | ||
188 |
sub update { |
|
189 |
my ($self, $values, $where) = @_; |
|
190 |
my ($stmt, @bind) = $self->sql_abstract->update($table, $values, $where); |
|
191 |
my $sth = $self->dbh->prepare($stmt); |
|
192 |
$sth->execute(@bind); |
|
first commit
|
193 |
} |
194 | ||
add some method
|
195 |
sub delete { |
196 |
my ($self, $where) = @_; |
|
197 |
my ($stmt, @bind) = $self->sql_abstract->delete($table, $where); |
|
198 |
my $sth = $self->dbh->prepare($stmt); |
|
199 |
$sth->execute(@bind); |
|
200 |
} |
|
201 | ||
202 | ||
first commit
|
203 | |
204 |
Object::Simple->build_class; |
|
205 | ||
206 |
=head1 NAME |
|
207 | ||
208 |
DBI::Custom - The great new DBI::Custom! |
|
209 | ||
210 |
=head1 VERSION |
|
211 | ||
212 |
Version 0.01 |
|
213 | ||
214 |
=cut |
|
215 | ||
216 |
our $VERSION = '0.01'; |
|
217 | ||
218 | ||
219 |
=head1 SYNOPSIS |
|
220 | ||
221 |
Quick summary of what the module does. |
|
222 | ||
223 |
Perhaps a little code snippet. |
|
224 | ||
225 |
use DBI::Custom; |
|
226 | ||
227 |
my $foo = DBI::Custom->new(); |
|
228 |
... |
|
229 | ||
230 |
=head1 EXPORT |
|
231 | ||
232 |
A list of functions that can be exported. You can delete this section |
|
233 |
if you don't export anything, such as for a purely object-oriented module. |
|
234 | ||
235 |
=head1 FUNCTIONS |
|
236 | ||
237 |
=head2 function1 |
|
238 | ||
239 |
=cut |
|
240 | ||
241 |
sub function1 { |
|
242 |
} |
|
243 | ||
244 |
=head2 function2 |
|
245 | ||
246 |
=cut |
|
247 | ||
248 |
sub function2 { |
|
249 |
} |
|
250 | ||
251 |
=head1 AUTHOR |
|
252 | ||
253 |
Yuki Kimoto, C<< <kimoto.yuki at gmail.com> >> |
|
254 | ||
255 |
=head1 BUGS |
|
256 | ||
257 |
Please report any bugs or feature requests to C<bug-dbi-custom at rt.cpan.org>, or through |
|
258 |
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=DBI-Custom>. I will be notified, and then you'll |
|
259 |
automatically be notified of progress on your bug as I make changes. |
|
260 | ||
261 | ||
262 | ||
263 | ||
264 |
=head1 SUPPORT |
|
265 | ||
266 |
You can find documentation for this module with the perldoc command. |
|
267 | ||
268 |
perldoc DBI::Custom |
|
269 | ||
270 | ||
271 |
You can also look for information at: |
|
272 | ||
273 |
=over 4 |
|
274 | ||
275 |
=item * RT: CPAN's request tracker |
|
276 | ||
277 |
L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=DBI-Custom> |
|
278 | ||
279 |
=item * AnnoCPAN: Annotated CPAN documentation |
|
280 | ||
281 |
L<http://annocpan.org/dist/DBI-Custom> |
|
282 | ||
283 |
=item * CPAN Ratings |
|
284 | ||
285 |
L<http://cpanratings.perl.org/d/DBI-Custom> |
|
286 | ||
287 |
=item * Search CPAN |
|
288 | ||
289 |
L<http://search.cpan.org/dist/DBI-Custom/> |
|
290 | ||
291 |
=back |
|
292 | ||
293 | ||
294 |
=head1 ACKNOWLEDGEMENTS |
|
295 | ||
296 | ||
297 |
=head1 COPYRIGHT & LICENSE |
|
298 | ||
299 |
Copyright 2009 Yuki Kimoto, all rights reserved. |
|
300 | ||
301 |
This program is free software; you can redistribute it and/or modify it |
|
302 |
under the same terms as Perl itself. |
|
303 | ||
304 | ||
305 |
=cut |
|
306 | ||
307 |
1; # End of DBI::Custom |