| 1 | package Catalyst::Model::Jifty::DBI; |
|---|
| 2 | |
|---|
| 3 | use strict; |
|---|
| 4 | use warnings; |
|---|
| 5 | use Carp; |
|---|
| 6 | use base qw( Catalyst::Model Class::Accessor::Fast ); |
|---|
| 7 | |
|---|
| 8 | our $VERSION = '0.03'; |
|---|
| 9 | |
|---|
| 10 | use NEXT; |
|---|
| 11 | use UNIVERSAL::require; |
|---|
| 12 | use Jifty::DBI::Handle; |
|---|
| 13 | use Module::Find; |
|---|
| 14 | |
|---|
| 15 | __PACKAGE__->mk_accessors(qw( handles connect_infos schema_base )); |
|---|
| 16 | |
|---|
| 17 | sub new { |
|---|
| 18 | my $self = shift->NEXT::new(@_); |
|---|
| 19 | |
|---|
| 20 | my $class = ref $self; |
|---|
| 21 | my $model_name = $class; |
|---|
| 22 | $model_name =~ s/^[\w:]+::(?:Model|M):://; |
|---|
| 23 | |
|---|
| 24 | $self->schema_base($class) unless $self->schema_base; |
|---|
| 25 | $self->connect_infos({}); |
|---|
| 26 | $self->handles({}); |
|---|
| 27 | |
|---|
| 28 | # let's see connect_info; we may have several. |
|---|
| 29 | if ( ref $self->{connect_info} eq 'HASH' ) { |
|---|
| 30 | $self->connect_infos->{_} = $self->{connect_info}; |
|---|
| 31 | |
|---|
| 32 | # if we have only one connect_info, then why don't we connect? |
|---|
| 33 | my $handle = Jifty::DBI::Handle->new; |
|---|
| 34 | $handle->connect( %{ $self->{connect_info} } ); |
|---|
| 35 | |
|---|
| 36 | $self->handles->{_} = $handle; |
|---|
| 37 | } |
|---|
| 38 | elsif ( ref $self->{databases} eq 'ARRAY' ) { |
|---|
| 39 | foreach my $database ( @{ $self->{databases} } ) { |
|---|
| 40 | croak "connect_info should be a hash reference" |
|---|
| 41 | unless ref $database->{connect_info} eq 'HASH'; |
|---|
| 42 | |
|---|
| 43 | my $name = $database->{name} |
|---|
| 44 | || $database->{connect_info}->{database}; |
|---|
| 45 | |
|---|
| 46 | croak "database should have a unique name" |
|---|
| 47 | if !$name || $self->connect_infos->{$name}; |
|---|
| 48 | |
|---|
| 49 | $self->connect_infos->{$name} = $database->{connect_info}; |
|---|
| 50 | } |
|---|
| 51 | # as we may have multiple connect_info, we should just prepare |
|---|
| 52 | # and wait until we really need to connect. |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | no strict 'refs'; |
|---|
| 56 | my $schema_base = $self->schema_base; |
|---|
| 57 | foreach my $moniker ( findsubmod $schema_base ) { |
|---|
| 58 | next if $moniker =~ /Collection$/; |
|---|
| 59 | $moniker =~ s/^$schema_base\:://; |
|---|
| 60 | |
|---|
| 61 | *{"${class}::${moniker}::ACCEPT_CONTEXT"} = sub { |
|---|
| 62 | shift; |
|---|
| 63 | shift->model( $model_name )->record( $moniker ); |
|---|
| 64 | }; |
|---|
| 65 | |
|---|
| 66 | my $collection_moniker = $moniker.'Collection'; |
|---|
| 67 | *{"${class}::${collection_moniker}::ACCEPT_CONTEXT"} = sub { |
|---|
| 68 | shift; |
|---|
| 69 | shift->model( $model_name )->collection( $collection_moniker ); |
|---|
| 70 | }; |
|---|
| 71 | } |
|---|
| 72 | return $self; |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | sub _select_name { |
|---|
| 76 | my ($self, %options) = @_; |
|---|
| 77 | |
|---|
| 78 | return $options{name} if $options{name}; |
|---|
| 79 | return $options{from} if $options{from}; |
|---|
| 80 | return $self->default_handle_name; |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | sub default_handle_name { |
|---|
| 84 | my $self = shift; |
|---|
| 85 | |
|---|
| 86 | if ( @_ ) { |
|---|
| 87 | my $new_handle = shift; |
|---|
| 88 | unless ( $self->connect_infos->{$new_handle} ) { |
|---|
| 89 | croak "$new_handle doesn't have connect_info"; |
|---|
| 90 | } |
|---|
| 91 | $self->{default_handle} = $new_handle; |
|---|
| 92 | } |
|---|
| 93 | unless ( $self->{default_handle} ) { |
|---|
| 94 | $self->{default_handle} = ( $self->databases )[0]; |
|---|
| 95 | } |
|---|
| 96 | $self->{default_handle}; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | sub handle { |
|---|
| 100 | my ($self, %options) = @_; |
|---|
| 101 | |
|---|
| 102 | my $name = $self->_select_name(%options); |
|---|
| 103 | my $handle = $self->handles->{$name}; |
|---|
| 104 | |
|---|
| 105 | unless ( $handle and $handle->dbh and $handle->dbh->{Active} ) { |
|---|
| 106 | my $connect_info = $self->connect_infos->{$name}; |
|---|
| 107 | croak "database $name doesn't have connect_info" |
|---|
| 108 | unless ref $connect_info eq 'HASH'; |
|---|
| 109 | |
|---|
| 110 | $handle = Jifty::DBI::Handle->new; |
|---|
| 111 | $handle->connect( %$connect_info ); |
|---|
| 112 | $self->handles->{$name} = $handle; |
|---|
| 113 | } |
|---|
| 114 | $handle; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | sub disconnect { |
|---|
| 118 | my ($self, %options) = @_; |
|---|
| 119 | |
|---|
| 120 | my $name = $self->_select_name(%options); |
|---|
| 121 | my $handle = $self->handles->{$name}; |
|---|
| 122 | |
|---|
| 123 | if ( $handle and $handle->dbh ) { |
|---|
| 124 | $handle->disconnect if $handle->dbh->{Active}; |
|---|
| 125 | } |
|---|
| 126 | else { |
|---|
| 127 | carp "database $name doesn't exist or open"; |
|---|
| 128 | } |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | sub database { |
|---|
| 132 | my ($self, %options) = @_; |
|---|
| 133 | |
|---|
| 134 | my $name = $self->_select_name(%options); |
|---|
| 135 | |
|---|
| 136 | if ( $self->connect_infos->{$name} ) { |
|---|
| 137 | return $self->connect_infos->{$name}->{database}; |
|---|
| 138 | } |
|---|
| 139 | else { |
|---|
| 140 | croak "database $name doesn't exist"; |
|---|
| 141 | } |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | sub databases { |
|---|
| 145 | my $self = shift; |
|---|
| 146 | return sort keys %{ $self->connect_infos }; |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | sub setup_database { |
|---|
| 150 | my $self = shift; |
|---|
| 151 | |
|---|
| 152 | my $handle = $self->handle( @_ ); |
|---|
| 153 | |
|---|
| 154 | require Jifty::DBI::SchemaGenerator; |
|---|
| 155 | my $generator = Jifty::DBI::SchemaGenerator->new( $handle ); |
|---|
| 156 | |
|---|
| 157 | foreach my $schema ( findsubmod $self->schema_base ) { |
|---|
| 158 | $schema->require or croak "Can't load $schema: $@"; |
|---|
| 159 | $generator->add_model( $schema ); |
|---|
| 160 | } |
|---|
| 161 | my @statements = $generator->create_table_sql_statements; |
|---|
| 162 | $handle->begin_transaction; |
|---|
| 163 | $handle->simple_query( $_ ) foreach @statements; |
|---|
| 164 | $handle->commit; |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | sub record { |
|---|
| 168 | my ($self, $moniker, %options) = @_; |
|---|
| 169 | |
|---|
| 170 | my $handle = $self->handle( %options ); |
|---|
| 171 | |
|---|
| 172 | my $package = $self->schema_base.'::'.$moniker; |
|---|
| 173 | $package->require or croak "Can't load $package: $@"; |
|---|
| 174 | $package->new( handle => $handle ); |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | sub collection { |
|---|
| 178 | my ($self, $moniker, %options) = @_; |
|---|
| 179 | |
|---|
| 180 | my $handle = $self->handle( %options ); |
|---|
| 181 | |
|---|
| 182 | # XXX: this may be double-edged |
|---|
| 183 | $moniker .= 'Collection' unless $moniker =~ /Collection$/; |
|---|
| 184 | |
|---|
| 185 | my $package = $self->schema_base.'::'.$moniker; |
|---|
| 186 | $package->require; |
|---|
| 187 | if ($@) { |
|---|
| 188 | # perhaps you're too lazy to create Collection class. |
|---|
| 189 | # now we should try creating default one! |
|---|
| 190 | my $package_body = <<"EOT"; |
|---|
| 191 | package $package; |
|---|
| 192 | use strict; |
|---|
| 193 | use base qw( Jifty::DBI::Collection ); |
|---|
| 194 | 1; |
|---|
| 195 | EOT |
|---|
| 196 | eval $package_body; |
|---|
| 197 | croak "Can't load $package: $@" if $@; |
|---|
| 198 | } |
|---|
| 199 | $package->new( handle => $handle ); |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | sub begin_transaction { shift->handle( @_ )->begin_transaction } |
|---|
| 203 | sub commit { shift->handle( @_ )->commit } |
|---|
| 204 | sub rollback { shift->handle( @_ )->rollback } |
|---|
| 205 | |
|---|
| 206 | sub simple_query { shift->handle->simple_query( @_ ) } |
|---|
| 207 | sub fetch_result { shift->handle->fetch_result( @_ ) } |
|---|
| 208 | |
|---|
| 209 | 1; |
|---|
| 210 | |
|---|
| 211 | __END__ |
|---|
| 212 | |
|---|
| 213 | =head1 NAME |
|---|
| 214 | |
|---|
| 215 | Catalyst::Model::Jifty::DBI - Jifty::DBI Model Class with some magic on top |
|---|
| 216 | |
|---|
| 217 | =head1 SYNOPSIS |
|---|
| 218 | |
|---|
| 219 | In your model class: |
|---|
| 220 | |
|---|
| 221 | package MyApp::Model: |
|---|
| 222 | use strict; |
|---|
| 223 | use base qw( Catalyst::Model::Jifty::DBI ); |
|---|
| 224 | __PACKAGE__->config({ |
|---|
| 225 | schema_base => 'MyApp::Schema', |
|---|
| 226 | connect_info => { |
|---|
| 227 | driver => 'SQLite', |
|---|
| 228 | database => 'myapp.db', |
|---|
| 229 | }, |
|---|
| 230 | }); |
|---|
| 231 | 1; |
|---|
| 232 | |
|---|
| 233 | Or you may want to have multiple databases (for partitioning): |
|---|
| 234 | |
|---|
| 235 | package MyApp::Model: |
|---|
| 236 | use strict; |
|---|
| 237 | use base qw( Catalyst::Model::Jifty::DBI ); |
|---|
| 238 | __PACKAGE__->config({ |
|---|
| 239 | schema_base => 'MyApp::Schema', |
|---|
| 240 | databases => [ |
|---|
| 241 | { |
|---|
| 242 | name => 'database1', |
|---|
| 243 | connect_info => { |
|---|
| 244 | driver => 'SQLite', |
|---|
| 245 | database => 'myapp1.db', |
|---|
| 246 | }, |
|---|
| 247 | }, |
|---|
| 248 | { |
|---|
| 249 | name => 'database2', |
|---|
| 250 | connect_info => { |
|---|
| 251 | driver => 'SQLite', |
|---|
| 252 | database => 'myapp2.db', |
|---|
| 253 | }, |
|---|
| 254 | }, |
|---|
| 255 | ], |
|---|
| 256 | }); |
|---|
| 257 | 1; |
|---|
| 258 | |
|---|
| 259 | Then in a controller: |
|---|
| 260 | |
|---|
| 261 | my $record = $c->model('JDBI::Book'); |
|---|
| 262 | $record->load_by_cols( name => 'foo' ); |
|---|
| 263 | |
|---|
| 264 | my $collection = $c->model('JDBI::BookCollection'); |
|---|
| 265 | $collection->limit( column => 'name', value => 'bar', |
|---|
| 266 | operator => 'MATCHES' ); |
|---|
| 267 | |
|---|
| 268 | Or, you may want to do more explicitly |
|---|
| 269 | |
|---|
| 270 | my $record = $c->model('JDBI')->record('Book'); |
|---|
| 271 | $record->load_by_cols( name => 'foo' ); |
|---|
| 272 | |
|---|
| 273 | my $collection = $c->model('JDBI')->collection('BookCollection'); |
|---|
| 274 | $collection->limit( column => 'name', value => 'bar', |
|---|
| 275 | operator => 'MATCHES' ); |
|---|
| 276 | |
|---|
| 277 | If you want some partitioning: |
|---|
| 278 | |
|---|
| 279 | my $record_1 = $c->model('JDBI') |
|---|
| 280 | ->record('Book', from => 'database1'); |
|---|
| 281 | my $record_2 = $c->model('JDBI') |
|---|
| 282 | ->record('Book', from => 'database2'); |
|---|
| 283 | |
|---|
| 284 | my $collection_1 = $c->model('JDBI') |
|---|
| 285 | ->collection('BookCollection', |
|---|
| 286 | from => 'database1'); |
|---|
| 287 | my $collection_2 = $c->model('JDBI') |
|---|
| 288 | ->collection('BookCollection', |
|---|
| 289 | from => 'database2'); |
|---|
| 290 | |
|---|
| 291 | You can also setup a database: |
|---|
| 292 | |
|---|
| 293 | my $database = $c->model('JDBI')->database; |
|---|
| 294 | if ( -f $database ) { |
|---|
| 295 | $c->model('JDBI')->disconnect; |
|---|
| 296 | unlink $database; |
|---|
| 297 | } |
|---|
| 298 | $c->model('JDBI')->setup_database; |
|---|
| 299 | |
|---|
| 300 | You want more? or you don't want any more magic? |
|---|
| 301 | |
|---|
| 302 | my $handle = $c->model('JDBI')->handle; |
|---|
| 303 | my $sth = $handle->simple_query( $sql_statement, @binds ); |
|---|
| 304 | |
|---|
| 305 | # Also you can write like this if you use a default handle: |
|---|
| 306 | my $sth = $c->model('JDBI') |
|---|
| 307 | ->simple_query( $sql_statement, @binds ); |
|---|
| 308 | |
|---|
| 309 | =head1 BACKWARD INCOMPATIBILITY |
|---|
| 310 | |
|---|
| 311 | Current version of Catalyst::Model::Jifty::DBI was once called Catalyst::Model::JDBI::Schemas, which then replaced the original version written by Marcus Ramberg, by the request of Matt S. Trout (Catalyst Core team) to avoid future confusion. I wonder if anyone used the previous one, but note that APIs have been revamped and backward incompatible since 0.03. |
|---|
| 312 | |
|---|
| 313 | =head1 DESCRIPTION |
|---|
| 314 | |
|---|
| 315 | This is a Catalyst model for Jifty::DBI-based schemas, which may or may not be placed under your model class (if you don't want to place them under the model class, pass "schema_base" option to the model). The model class automatically detect/load your schemas, like Catalyst::Model::DBIC::Schema does. |
|---|
| 316 | |
|---|
| 317 | This model also provides several features for laziness. You don't have to create simple Collection classes (they'll be created on the fly a la Jifty). No more writing schema in other language just to set up databases; C::M::Jifty::DBI takes care of it, on the fly if you want (of course from the perl schemas you prepared; converting raw SQLs to a database to perl schemas is not our way). You may want to use multiple databases of the same schema, or, you may prefer bloody raw SQL statements to complicated object chains. Here you are. Have fun! |
|---|
| 318 | |
|---|
| 319 | =head1 CONFIG |
|---|
| 320 | |
|---|
| 321 | =head2 schema_base |
|---|
| 322 | |
|---|
| 323 | The namespace to look for schema definitions in. All the schemas just below this namespace would be counted. |
|---|
| 324 | |
|---|
| 325 | =head2 connect_info |
|---|
| 326 | |
|---|
| 327 | A hash reference, which would be converted to a hash, then be passed to Jifty::DBI::Handle->new. See L<Jifty::DBI::Handle> for details. |
|---|
| 328 | |
|---|
| 329 | =head2 databases |
|---|
| 330 | |
|---|
| 331 | You may want to use multiple databases (for log rotation, load balancing etc). In this case you can provide multiple "connect_info" hash references under here, as shown in the SYNOPSIS. Actually, above "connect_info" hash reference would be moved in this "databases" array reference internally, with a default name "_" (underscore). |
|---|
| 332 | |
|---|
| 333 | =head1 METHODS |
|---|
| 334 | |
|---|
| 335 | =head2 new |
|---|
| 336 | |
|---|
| 337 | creates a model. Database connection may be or not be prepared, according to the number of connect_info. See above for the configuration. |
|---|
| 338 | |
|---|
| 339 | =head2 record |
|---|
| 340 | |
|---|
| 341 | creates and returns a corresponding (new) Jifty::DBI::Record object. Note that this is just a Record, not a Collection or a RecordSet of DBIC. That means, this object holds one and only single record, and usually you shouldn't reuse this object to let it hold another record. See examples: |
|---|
| 342 | |
|---|
| 343 | # this works. |
|---|
| 344 | my $record = $c->model('JDBI')->record('Book'); |
|---|
| 345 | $record->load_by_cols( id => 1 ); |
|---|
| 346 | $record->set_name( 'new name' ); # now inserted/updated |
|---|
| 347 | |
|---|
| 348 | # this may or may not work as you wish, |
|---|
| 349 | # depending on what you really want to do. |
|---|
| 350 | $c->model('JDBI')->record('Book')->load_by_cols( id => 1 ); |
|---|
| 351 | $c->model('JDBI')->record('Book')->set_name( 'new name' ); |
|---|
| 352 | |
|---|
| 353 | You can pass an optional hash, as shown in the SYNOPSIS. |
|---|
| 354 | |
|---|
| 355 | # this tries to fetch a record from a table named 'books' |
|---|
| 356 | # in a database named 'database'. |
|---|
| 357 | my $record = $c->model('JDBI')->record('Book', from => 'database'); |
|---|
| 358 | |
|---|
| 359 | You can omit "->record" when you fetch from a default database. |
|---|
| 360 | |
|---|
| 361 | # both do the same thing |
|---|
| 362 | my $record = $c->model('JDBI')->record('Book'); |
|---|
| 363 | my $record = $c->model('JDBI::Book'); |
|---|
| 364 | |
|---|
| 365 | =head2 collection |
|---|
| 366 | |
|---|
| 367 | creates and returns a corresponding (new) Jifty::DBI::Collection object. If you haven't created a Collection class but only a Schema/Record class, this model creates a plain Collection class on the fly. I recommend not to omit the obvious 'Collection' part of the class name, but if you prefer, you can spare that part when you explicitly call model("Model")->collection("Schema") (you can't omit if you follow the model("Model::Schema") convention). Other general usage and caveats are the same as ->record. |
|---|
| 368 | |
|---|
| 369 | # this works. |
|---|
| 370 | my $collection = $c->model('JDBI')->collection('BookCollection'); |
|---|
| 371 | $collection->unlimit; |
|---|
| 372 | $collection->limit( column => 'name', value => 'bar', |
|---|
| 373 | operator => 'MATCHES' ); |
|---|
| 374 | |
|---|
| 375 | # this may or may not work as you wish, |
|---|
| 376 | # depending on what you really want to do. |
|---|
| 377 | $c->model('JDBI')->collection('BookCollection')->limit; |
|---|
| 378 | $c->model('JDBI')->collection('BookCollection')->first; |
|---|
| 379 | |
|---|
| 380 | You can pass an optional hash, as shown in the SYNOPSIS. |
|---|
| 381 | |
|---|
| 382 | # this tries to fetch a collection from a table named 'books' |
|---|
| 383 | # in a database named 'database'. |
|---|
| 384 | my $collection = $c->model('JDBI') |
|---|
| 385 | ->collection('BookCollection', |
|---|
| 386 | from => 'database'); |
|---|
| 387 | |
|---|
| 388 | You can omit "->collection" when you fetch from a default database. |
|---|
| 389 | |
|---|
| 390 | # both do the same thing |
|---|
| 391 | my $collection = $c->model('JDBI')->collection('BookCollection'); |
|---|
| 392 | my $collection = $c->model('JDBI::BookCollection'); |
|---|
| 393 | |
|---|
| 394 | =head2 simple_query |
|---|
| 395 | |
|---|
| 396 | When you want to do something irrelevant to a specific table, or something too complicated for Jifty::DBI, you can execute arbitrary statements with "simple_query", which is almost equivalent to DBI's $dbh->do or ->prepare. Note that this is supposed to use a default handle. If you want to use other handles, get the handle first with ->handle described below. |
|---|
| 397 | |
|---|
| 398 | # fetch something from "tables" table, |
|---|
| 399 | # described in "(Your::Schema::)Table" schema/record class. |
|---|
| 400 | my $statement = 'select * from tables where id = ?'; |
|---|
| 401 | my $sth = $c->model('JDBI')->simple_query( $statement, 1 ); |
|---|
| 402 | return $sth ? $sth->fetchrow : undef; |
|---|
| 403 | |
|---|
| 404 | # Above is equivalent to: |
|---|
| 405 | my $handle = $c->model('JDBI')->handle; |
|---|
| 406 | my $sth = $handle->simple_query( $statement, 1 ); |
|---|
| 407 | return $sth ? $sth->fetchrow : undef; |
|---|
| 408 | |
|---|
| 409 | =head2 fetch_result |
|---|
| 410 | |
|---|
| 411 | This is a lazier shortcut to realize the example just shown above. |
|---|
| 412 | |
|---|
| 413 | my $statement = 'select * from tables where id = ?'; |
|---|
| 414 | my $row = $c->model('JDBI')->fetch_result( $statement, 1 ); |
|---|
| 415 | |
|---|
| 416 | =head2 handle |
|---|
| 417 | |
|---|
| 418 | C::M::Jifty::DBI may have multiple JDBI handles. You can choose one you want to use like this: |
|---|
| 419 | |
|---|
| 420 | my $handle = $c->model('JDBI')->handle( name => 'sample.db' ); |
|---|
| 421 | |
|---|
| 422 | You can use "from" instead of "name". Also, you can use an alias to the real database name (connect_info->{database}) if you set "name" option in the config. |
|---|
| 423 | |
|---|
| 424 | my $handle = $c->model('JDBI')->handle( from => 'alias' ); |
|---|
| 425 | |
|---|
| 426 | By default, this returns a default handle. |
|---|
| 427 | |
|---|
| 428 | =head2 default_handle_name |
|---|
| 429 | |
|---|
| 430 | returns (or sets) a default handle/database name. |
|---|
| 431 | |
|---|
| 432 | =head2 databases |
|---|
| 433 | |
|---|
| 434 | returns all the database names/aliases registered in the config. |
|---|
| 435 | |
|---|
| 436 | # See if all the registered SQLite databases have been set up. |
|---|
| 437 | foreach my $name ( $c->model('JDBI')->databases ) { |
|---|
| 438 | my $dbfile = $c->model('JDBI')->database( name => $name ); |
|---|
| 439 | warn "database $db does not exist" unless -f $dbfile; |
|---|
| 440 | warn "database $db is blank" unless -s $dbfile; |
|---|
| 441 | } |
|---|
| 442 | |
|---|
| 443 | =head2 database |
|---|
| 444 | |
|---|
| 445 | returns a database name (or an actual path to the database for SQLite). See above for an example. You can pass an optional hash to specify database alias explicitly. |
|---|
| 446 | |
|---|
| 447 | $c->model('JDBI')->database( name => 'alias' ); |
|---|
| 448 | |
|---|
| 449 | =head2 setup_database |
|---|
| 450 | |
|---|
| 451 | You can set up database on the fly with your perl schema. You can pass an optional hash to specify target database. |
|---|
| 452 | |
|---|
| 453 | $c->model('JDBI')->setup_database( name => 'database' ); |
|---|
| 454 | |
|---|
| 455 | =head2 begin_transaction |
|---|
| 456 | |
|---|
| 457 | =head2 commit |
|---|
| 458 | |
|---|
| 459 | =head2 rollback |
|---|
| 460 | |
|---|
| 461 | These three are shortcuts to ->handle->(method_name). You can pass an optional hash to specify target database. |
|---|
| 462 | |
|---|
| 463 | =head2 disconnect |
|---|
| 464 | |
|---|
| 465 | This also is a shortcut to ->handle->disconnect. You can pass an optional hash to specify target database. |
|---|
| 466 | |
|---|
| 467 | =head1 SEE ALSO |
|---|
| 468 | |
|---|
| 469 | L<Jifty::DBI> |
|---|
| 470 | |
|---|
| 471 | =head1 AUTHOR |
|---|
| 472 | |
|---|
| 473 | Kenichi Ishigaki, E<lt>ishigaki@cpan.orgE<gt> |
|---|
| 474 | |
|---|
| 475 | original version is written by Marcus Ramberg, E<lt>mramberg@cpan.orgE<gt> |
|---|
| 476 | |
|---|
| 477 | =head1 COPYRIGHT AND LICENSE |
|---|
| 478 | |
|---|
| 479 | Copyright (C) 2007 by Kenichi Ishigaki. |
|---|
| 480 | |
|---|
| 481 | This program is free software; you can redistribute it and/or |
|---|
| 482 | modify it under the same terms as Perl itself. |
|---|
| 483 | |
|---|
| 484 | =cut |
|---|