Added DBIC dep on Module::Find (for Schema)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI.pm
CommitLineData
8b445e33 1package DBIx::Class::Storage::DBI;
2
20a2c954 3use strict;
4use warnings;
8b445e33 5use DBI;
aeaf3ce2 6use SQL::Abstract::Limit;
28927b50 7use DBIx::Class::Storage::DBI::Cursor;
8b445e33 8
bd7efd39 9BEGIN {
10
11package DBIC::SQL::Abstract; # Temporary. Merge upstream.
12
13use base qw/SQL::Abstract::Limit/;
14
15sub select {
16 my ($self, $ident, @rest) = @_;
17 return $self->SUPER::select($self->from($ident), @rest);
18}
19
20sub from {
21 my ($self, $from) = @_;
22 if (ref $from eq 'ARRAY') {
23 return $self->_recurse_from(@$from);
24 } elsif (ref $from eq 'HASH') {
25 return $self->_make_as($from);
26 } else {
27 return $from;
28 }
29}
30
31sub _recurse_from {
32 my ($self, $from, @join) = @_;
33 my @sqlf;
34 push(@sqlf, $self->_make_as($from));
35 foreach my $j (@join) {
36 my ($to, $on) = @$j;
73856587 37
38 # check whether a join type exists
39 my $join_clause = '';
40 if (ref($to) eq 'HASH' and exists($to->{-join_type})) {
41 $join_clause = ' '.uc($to->{-join_type}).' JOIN ';
42 } else {
43 $join_clause = ' JOIN ';
44 }
45 push(@sqlf, $join_clause);
46
bd7efd39 47 if (ref $to eq 'ARRAY') {
48 push(@sqlf, '(', $self->_recurse_from(@$to), ')');
49 } else {
96cdbbab 50 push(@sqlf, $self->_make_as($to));
bd7efd39 51 }
52 push(@sqlf, ' ON ', $self->_join_condition($on));
53 }
54 return join('', @sqlf);
55}
56
57sub _make_as {
58 my ($self, $from) = @_;
96cdbbab 59 return join(' ', reverse each %{$self->_skip_options($from)});
73856587 60}
61
62sub _skip_options {
63 my ($self, $hash) = @_;
64 my $clean_hash = {};
65 $clean_hash->{$_} = $hash->{$_}
66 for grep {!/^-/} keys %$hash;
67 return $clean_hash;
bd7efd39 68}
69
70sub _join_condition {
71 my ($self, $cond) = @_;
72 die "no chance" unless ref $cond eq 'HASH';
73 my %j;
74 for (keys %$cond) { my $x = '= '.$cond->{$_}; $j{$_} = \$x; };
75 return $self->_recurse_where(\%j);
76}
77
78} # End of BEGIN block
79
8b445e33 80use base qw/DBIx::Class/;
81
438adc0e 82__PACKAGE__->load_components(qw/Exception AccessorGroup/);
8b445e33 83
223b8fe3 84__PACKAGE__->mk_group_accessors('simple' =>
48c69e7c 85 qw/connect_info _dbh _sql_maker debug cursor/);
8b445e33 86
87sub new {
223b8fe3 88 my $new = bless({}, ref $_[0] || $_[0]);
28927b50 89 $new->cursor("DBIx::Class::Storage::DBI::Cursor");
90 $new->debug(1) if $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG};
223b8fe3 91 return $new;
8b445e33 92}
93
94sub get_simple {
95 my ($self, $get) = @_;
96 return $self->{$get};
97}
98
99sub set_simple {
100 my ($self, $set, $val) = @_;
101 return $self->{$set} = $val;
102}
103
104=head1 NAME
105
106DBIx::Class::Storage::DBI - DBI storage handler
107
108=head1 SYNOPSIS
109
110=head1 DESCRIPTION
111
112This class represents the connection to the database
113
114=head1 METHODS
115
116=over 4
117
118=cut
119
120sub dbh {
121 my ($self) = @_;
122 my $dbh;
123 unless (($dbh = $self->_dbh) && $dbh->FETCH('Active') && $dbh->ping) {
124 $self->_populate_dbh;
125 }
126 return $self->_dbh;
127}
128
48c69e7c 129sub sql_maker {
130 my ($self) = @_;
fdc1c3d0 131 unless ($self->_sql_maker) {
bd7efd39 132 $self->_sql_maker(new DBIC::SQL::Abstract( limit_dialect => $self->dbh ));
48c69e7c 133 }
134 return $self->_sql_maker;
135}
136
8b445e33 137sub _populate_dbh {
138 my ($self) = @_;
139 my @info = @{$self->connect_info || []};
140 $self->_dbh($self->_connect(@info));
141}
142
143sub _connect {
144 my ($self, @info) = @_;
145 return DBI->connect(@info);
146}
147
148=item commit
149
150 $class->commit;
151
152Issues a commit again the current dbh
153
154=cut
155
156sub commit { $_[0]->dbh->commit; }
157
158=item rollback
159
160 $class->rollback;
161
162Issues a rollback again the current dbh
163
164=cut
165
166sub rollback { $_[0]->dbh->rollback; }
167
223b8fe3 168sub _execute {
169 my ($self, $op, $extra_bind, $ident, @args) = @_;
170 my ($sql, @bind) = $self->sql_maker->$op($ident, @args);
944f30bf 171 unshift(@bind, @$extra_bind) if $extra_bind;
223b8fe3 172 warn "$sql: @bind" if $self->debug;
173 my $sth = $self->sth($sql);
438adc0e 174 @bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
175 my $rv = $sth->execute(@bind);
223b8fe3 176 return (wantarray ? ($rv, $sth, @bind) : $rv);
177}
178
8b445e33 179sub insert {
180 my ($self, $ident, $to_insert) = @_;
20a2c954 181 $self->throw( "Couldn't insert ".join(', ', map "$_ => $to_insert->{$_}", keys %$to_insert)." into ${ident}" )
223b8fe3 182 unless ($self->_execute('insert' => [], $ident, $to_insert) > 0);
8b445e33 183 return $to_insert;
184}
185
186sub update {
223b8fe3 187 return shift->_execute('update' => [], @_);
8b445e33 188}
189
190sub delete {
223b8fe3 191 return shift->_execute('delete' => [], @_);
8b445e33 192}
193
de705b51 194sub _select {
8b445e33 195 my ($self, $ident, $select, $condition, $attrs) = @_;
223b8fe3 196 my $order = $attrs->{order_by};
197 if (ref $condition eq 'SCALAR') {
198 $order = $1 if $$condition =~ s/ORDER BY (.*)$//i;
199 }
5c91499f 200 my @args = ('select', $attrs->{bind}, $ident, $select, $condition, $order);
9229f20a 201 if ($attrs->{software_limit} ||
202 $self->sql_maker->_default_limit_syntax eq "GenericSubQ") {
203 $attrs->{software_limit} = 1;
5c91499f 204 } else {
205 push @args, $attrs->{rows}, $attrs->{offset};
206 }
de705b51 207 return $self->_execute(@args);
208}
209
210sub select {
211 my $self = shift;
212 my ($ident, $select, $condition, $attrs) = @_;
213 my ($rv, $sth, @bind) = $self->_select(@_);
223b8fe3 214 return $self->cursor->new($sth, \@bind, $attrs);
8b445e33 215}
216
1a14aa3f 217sub select_single {
de705b51 218 my $self = shift;
219 my ($rv, $sth, @bind) = $self->_select(@_);
1a14aa3f 220 return $sth->fetchrow_array;
221}
222
8b445e33 223sub sth {
224 shift->dbh->prepare(@_);
225}
226
2271;
228
229=back
230
231=head1 AUTHORS
232
daec44b8 233Matt S. Trout <mst@shadowcatsystems.co.uk>
8b445e33 234
9f19b1d6 235Andy Grundman <andy@hybridized.org>
236
8b445e33 237=head1 LICENSE
238
239You may distribute this code under the same terms as Perl itself.
240
241=cut
242