File Coverage

blib/lib/DBIx/QuickORM/Connection.pm
Criterion Covered Total %
statement 180 295 61.0
branch 50 126 39.6
condition 31 75 41.3
subroutine 34 60 56.6
pod 45 46 97.8
total 340 602 56.4


line stmt bran cond sub pod time code
1             package DBIx::QuickORM::Connection;
2 24     24   180 use strict;
  24         58  
  24         1172  
3 24     24   13200 use warnings;
  24         66  
  24         3026  
4 24     24   222 use feature qw/state/;
  24         55  
  24         7699  
5              
6             our $VERSION = '0.000019';
7              
8 24     24   263 use Carp qw/confess croak cluck/;
  24         62  
  24         2128  
9 24     24   229 use Scalar::Util qw/blessed weaken/;
  24         71  
  24         1746  
10 24     24   159 use DBIx::QuickORM::Util qw/load_class/;
  24         51  
  24         308  
11              
12 24     24   34011 use DBIx::QuickORM::Handle;
  24         129  
  24         1123  
13 24     24   25886 use DBIx::QuickORM::Connection::Transaction;
  24         107  
  24         1601  
14              
15 24         143 use DBIx::QuickORM::Util::HashBase qw{
16             <orm
17             <dbh
18             <dialect
19             <pid
20             <schema
21             <transactions
22             +_savepoint_counter
23             +_txn_counter
24             <manager
25             <in_async
26             <asides
27             <forks
28             <default_sql_builder
29             <default_internal_txn
30             <default_handle_class
31 24     24   196 };
  24         54  
32              
33             sub init {
34 23     23 0 63 my $self = shift;
35              
36 23 50       163 my $orm = $self->{+ORM} or croak "An orm is required";
37 23         123 my $db = $orm->db;
38              
39 23   50     294 $self->{+_SAVEPOINT_COUNTER} //= 1;
40 23   50     284 $self->{+_TXN_COUNTER} //= 1;
41              
42 23         237 $self->{+PID} = $$;
43              
44 23         161 $self->{+DBH} = $db->new_dbh;
45              
46 23         258 $self->{+DIALECT} = $db->dialect->new(dbh => $self->{+DBH}, db_name => $db->db_name);
47              
48 23   50     267 $self->{+DEFAULT_INTERNAL_TXN} //= 1;
49              
50 23         73 $self->{+ASIDES} = {};
51 23         98 $self->{+FORKS} = {};
52              
53 23   50     509 $self->{+DEFAULT_HANDLE_CLASS} //= $orm->default_handle_class // 'DBIx::QuickORM::Handle';
      33        
54              
55 23   33     266 $self->{+DEFAULT_SQL_BUILDER} //= do {
56 23         18260 require DBIx::QuickORM::SQLBuilder::SQLAbstract;
57 23         193 DBIx::QuickORM::SQLBuilder::SQLAbstract->new();
58             };
59              
60 23         7371 my $txns = $self->{+TRANSACTIONS} = [];
61 23   50     217 my $manager = $self->{+MANAGER} // 'DBIx::QuickORM::RowManager::Cached';
62 23 50       154 if (blessed($manager)) {
63 0         0 $manager->set_connection($self);
64 0         0 $manager->set_transactions($txns);
65             }
66             else {
67 23 50       230 my $class = load_class($manager) or die $@;
68 23         223 $self->{+MANAGER} = $class->new(transactions => $txns, connection => $self);
69             }
70              
71 23 100       264 if (my $autofill = $orm->autofill) {
72 22         420 my $schema = $self->{+DIALECT}->build_schema_from_db(autofill => $autofill);
73              
74 22 100       270 if (my $schema2 = $orm->schema) {
75 3         20 $self->{+SCHEMA} = $schema->merge($schema2);
76             }
77             else {
78 19         121 $self->{+SCHEMA} = $schema->clone;
79             }
80             }
81             else {
82 1         9 $self->{+SCHEMA} = $orm->schema->clone;
83             }
84             }
85              
86             ########################
87             # {{{ Async/Aside/Fork #
88             ########################
89              
90             sub set_async {
91 0     0 1 0 my $self = shift;
92 0         0 my ($async) = @_;
93              
94 0 0 0     0 croak "There is already an async query in progress" if $self->{+IN_ASYNC} && !$self->{+IN_ASYNC}->done;
95              
96 0         0 $self->{+IN_ASYNC} = $async;
97 0         0 weaken($self->{+IN_ASYNC});
98              
99 0         0 return $async;
100             }
101              
102             sub add_aside {
103 0     0 1 0 my $self = shift;
104 0         0 my ($aside) = @_;
105              
106 0         0 $self->{+ASIDES}->{$aside} = $aside;
107 0         0 weaken($self->{+ASIDES}->{$aside});
108              
109 0         0 return $aside;
110             }
111              
112             sub add_fork {
113 5     5 1 90 my $self = shift;
114 5         16 my ($fork) = @_;
115              
116 5         208 $self->{+FORKS}->{$fork} = $fork;
117 5         48 weaken($self->{+FORKS}->{$fork});
118              
119 5         53 return $fork;
120             }
121              
122             sub clear_async {
123 0     0 1 0 my $self = shift;
124 0         0 my ($async) = @_;
125              
126 0 0       0 croak "Not currently running an async query" unless $self->{+IN_ASYNC};
127              
128             croak "Mismatch, we are in an async query, but not the one we are trying to clear"
129 0 0       0 unless $async == $self->{+IN_ASYNC};
130              
131 0         0 delete $self->{+IN_ASYNC};
132             }
133              
134             sub clear_aside {
135 0     0 1 0 my $self = shift;
136 0         0 my ($aside) = @_;
137              
138 0 0       0 croak "Not currently running that aside query" unless $self->{+ASIDES}->{$aside};
139              
140 0         0 delete $self->{+ASIDES}->{$aside};
141             }
142              
143             sub clear_fork {
144 5     5 1 13 my $self = shift;
145 5         14 my ($fork) = @_;
146              
147 5 50       30 croak "Not currently running that fork query" unless $self->{+FORKS}->{$fork};
148              
149 5         39 delete $self->{+FORKS}->{$fork};
150             }
151              
152             ########################
153             # }}} Async/Aside/Fork #
154             ########################
155              
156             #####################
157             # {{{ SANITY CHECKS #
158             #####################
159              
160             sub pid_and_async_check {
161 240     240 1 564 my $self = shift;
162 240   33     1766 return $self->pid_check && $self->async_check;
163             }
164              
165             sub pid_check {
166 291     291 1 569 my $self = shift;
167 291 50       6883 confess "Connections cannot be used across multiple processes, you must reconnect post-fork" unless $$ == $self->{+PID};
168 291         1489 return 1;
169             }
170              
171             sub async_check {
172 240     240 1 502 my $self = shift;
173              
174 240 50       1131 my $async = $self->{+IN_ASYNC} or return 1;
175 0 0       0 confess "There is currently an async query running, it must be completed before you run another query" unless $async->done;
176 0         0 delete $self->{+IN_ASYNC};
177 0         0 return 1;
178             }
179              
180             #####################
181             # }}} SANITY CHECKS #
182             #####################
183              
184             ########################
185             # {{{ SIMPLE ACCESSORS #
186             ########################
187              
188 0     0 1 0 sub db { $_[0]->{+ORM}->db }
189 0     0 1 0 sub aside_dbh { $_[0]->{+ORM}->db->new_dbh }
190              
191             ########################
192             # }}} SIMPLE ACCESSORS #
193             ########################
194              
195             #####################
196             # {{{ STATE CHANGES #
197             #####################
198              
199             sub reconnect {
200 0     0 1 0 my $self = shift;
201              
202 0         0 my $dbh = delete $self->{+DBH};
203 0 0       0 $dbh->{InactiveDestroy} = 1 unless $self->{+PID} == $$;
204 0         0 $dbh->disconnect;
205              
206 0         0 $self->{+PID} = $$;
207 0         0 $self->{+DBH} = $self->{+ORM}->db->new_dbh;
208              
209              
210             }
211              
212             #####################
213             # }}} STATE CHANGES #
214             #####################
215              
216             ###########################
217             # {{{ TRANSACTION METHODS #
218             ###########################
219              
220             {
221 24     24   249 no warnings 'once';
  24         74  
  24         38476  
222             *transaction = \&txn;
223             }
224             sub txn {
225 27     27 1 68163 my $self = shift;
226 27         127 $self->pid_check;
227              
228 27         120 my @caller = caller;
229              
230 27         70 my $txns = $self->{+TRANSACTIONS};
231              
232 27 100 100     193 my $cb = (@_ && ref($_[0]) eq 'CODE') ? shift : undef;
233 27         72 my %params = @_;
234 27   100     78 $cb //= $params{action};
235              
236 27 50 33     90 croak "Cannot start a transaction while there is an active async query" if $self->{+IN_ASYNC} && !$self->{+IN_ASYNC}->done;
237              
238 27 50       109 unless ($params{force}) {
239 27 50       90 unless ($params{ignore_aside}) {
240 27 0 50     53 my $count = grep { $_ && !$_->done } values %{$self->{+ASIDES} // {}};
  0         0  
  27         125  
241 27 50       70 croak "Cannot start a transaction while there is an active aside query (unless you use ignore_aside => 1, or force => 1)" if $count;
242             }
243              
244 27 50       54 unless ($params{ignore_forks}) {
245 27 0 50     47 my $count = grep { $_ && !$_->done } values %{$self->{+FORKS} // {}};
  0         0  
  27         92  
246 27 50       73 croak "Cannot start a transaction while there is an active forked query (unless you use ignore_forked => 1, or force => 1)" if $count;
247             }
248             }
249              
250 27         67 my $id = $self->{+_TXN_COUNTER}++;
251              
252 27         89 my $dialect = $self->dialect;
253              
254 27         52 my $sp;
255 27 100       189 if (@$txns) {
    50          
256 4         30 $sp = "SAVEPOINT_${$}_" . $self->{+_SAVEPOINT_COUNTER}++;
257 4         20 $dialect->create_savepoint(savepoint => $sp);
258             }
259             elsif ($self->dialect->in_txn) {
260 0         0 croak "A transaction is already open, but it is not controlled by DBIx::QuickORM";
261             }
262             else {
263 23         130 $dialect->start_txn;
264             }
265              
266             my $txn = DBIx::QuickORM::Connection::Transaction->new(
267             id => $id,
268             savepoint => $sp,
269             trace => \@caller,
270             on_fail => $params{on_fail},
271             on_success => $params{on_success},
272             on_completion => $params{on_completion},
273 27         1117 );
274              
275 27 100       126 my ($root, $parent) = @$txns ? (@{$txns}[0,-1]) : ($txn, $txn);
  4         11  
276              
277 27 50       57 $parent->add_fail_callback($params{'on_parent_fail'}) if $params{on_parent_fail};
278 27 50       70 $parent->add_success_callback($params{'on_parent_success'}) if $params{on_parent_success};
279 27 50       71 $parent->add_completion_callback($params{'on_parent_completion'}) if $params{on_parent_completion};
280 27 50       48 $root->add_fail_callback($params{'on_root_fail'}) if $params{on_root_fail};
281 27 50       99 $root->add_success_callback($params{'on_root_success'}) if $params{on_root_success};
282 27 50       58 $root->add_completion_callback($params{'on_root_completion'}) if $params{on_root_completion};
283              
284 27         57 push @{$txns} => $txn;
  27         47  
285 27         80 weaken($txns->[-1]);
286              
287 27         7086 my $ran = 0;
288             my $finalize = sub {
289 27     27   95 my ($txnx, $ok, @errors) = @_;
290              
291 27 50       82 return if $ran++;
292              
293             $txnx->throw("Cannot stop a transaction while there is an active async query")
294 27 50 33     105 if $self->{+IN_ASYNC} && !$self->{+IN_ASYNC}->done;
295              
296 27 50 66     279 $txnx->throw("Internal Error: Transaction stack mismatch")
      33        
      33        
297             unless @$txns && ($txnx->in_destroy && !$txns->[-1]) || $txns->[-1] == $txnx;
298              
299 27         57 pop @$txns;
300              
301 27         77 my $rolled_back = $txnx->rolled_back;
302 27   100     97 my $res = $ok && !$rolled_back;
303              
304 27 100       60 if ($sp) {
305 4 100       8 if ($res) { $dialect->commit_savepoint(savepoint => $sp) }
  3         13  
306 1         7 else { $dialect->rollback_savepoint(savepoint => $sp) }
307             }
308             else {
309 23 100       52 if ($res) { $dialect->commit_txn }
  15         94  
310 8         43 else { $dialect->rollback_txn }
311             }
312              
313 27         456 my ($ok2, $err2) = $txnx->terminate($res, \@errors);
314 27 50       82 unless ($ok2) {
315 0         0 $ok = 0;
316 0         0 push @errors => @$err2;
317             }
318              
319 27 100       123 return if $ok;
320 3         24 $txnx->throw(join "\n" => @errors);
321 27         168 };
322              
323 27 100       86 unless($cb) {
324 3         11 $txn->set_no_last(1);
325 3         15 $txn->set_finalize($finalize);
326 3         10 return $txn;
327             }
328              
329 24         44 local $@;
330 24         59 my $ok = eval {
331 24         45 QORM_TRANSACTION: { $cb->($txn) };
  24         82  
332 21         23309 1;
333             };
334              
335 24         2243 $finalize->($txn, $ok, $@);
336              
337 21         409 return $txn;
338             }
339              
340             {
341 24     24   3277 no warnings 'once';
  24         57  
  24         7024  
342             *in_transaction = \&in_txn;
343             }
344             sub in_txn {
345 9     9 1 9208 my $self = shift;
346 9   66     38 return $self->current_txn // $self->dialect->in_txn;
347             }
348              
349             {
350 24     24   225 no warnings 'once';
  24         85  
  24         81708  
351             *current_transaction = \&current_txn;
352             }
353             sub current_txn {
354 22     22 1 47 my $self = shift;
355 22         85 $self->pid_check;
356              
357 22 50       95 if (my $txns = $self->{+TRANSACTIONS}) {
358 22 100       86 return $txns->[-1] if @$txns;
359             }
360              
361 18         129 return undef;
362             }
363              
364             sub auto_retry_txn {
365 0     0 1 0 my $self = shift;
366 0         0 $self->pid_check;
367 0         0 $self->async_check;
368              
369 0         0 my $count;
370             my %params;
371              
372 0 0 0     0 if (!@_) {
    0          
    0          
373 0         0 croak "Not enough arguments";
374             }
375             elsif (@_ == 1 && ref($_[0]) eq 'CODE') {
376 0         0 $count = 1;
377 0         0 $params{action} = $_[0];
378             }
379             elsif (@_ == 2) {
380 0         0 my $ref = ref($_[1]);
381 0 0       0 if ($ref eq 'CODE') {
    0          
382 0         0 $count = $_[0];
383 0         0 $params{action} = $_[1];
384             }
385             elsif ($ref eq 'HASH') {
386 0         0 $count = $_[0];
387 0         0 %params = %{$_[1]};
  0         0  
388             }
389             else {
390 0         0 croak "Not sure what to do with second argument '$_[0]'";
391             }
392             }
393             else {
394 0         0 %params = @_;
395 0         0 $count = delete $params{count};
396             }
397              
398 0   0     0 $count ||= 1;
399              
400 0     0   0 $self->auto_retry($count => sub { $self->txn(%params) });
  0         0  
401             }
402              
403             ###########################
404             # }}} TRANSACTION METHODS #
405             ###########################
406              
407             #######################
408             # {{{ UTILITY METHODS #
409             #######################
410              
411             sub auto_retry {
412 0     0 1 0 my $self = shift;
413 0         0 my $cb = pop;
414 0   0     0 my $count = shift || 1;
415 0         0 $self->pid_check;
416 0         0 $self->async_check;
417              
418 0 0       0 croak "Cannot use auto_retry inside a transaction" if $self->in_txn;
419              
420 0         0 my ($ok, $out);
421 0         0 for (0 .. $count) {
422 0         0 $ok = eval { $out = $cb->(); 1 };
  0         0  
  0         0  
423 0 0       0 last if $ok;
424 0         0 warn "Error encountered in auto-retry, will retry...\n Exception was: $@\n";
425 0 0 0     0 $self->reconnect unless $self->{+DBH} && $self->{+DBH}->ping;
426             }
427              
428 0 0       0 croak "auto_retry did not succeed (attempted " . ($count + 1) . " times)"
429             unless $ok;
430              
431 0         0 return $out;
432             }
433              
434             sub source {
435 56     56 1 137 my $self = shift;
436 56         334 my ($in, %params) = @_;
437              
438 56 50       240 if (blessed($in)) {
439 0 0       0 return $in if $in->DOES('DBIx::QuickORM::Role::Source');
440 0 0       0 return undef if $params{no_fatal};
441 0         0 croak "'$in' does not implement the 'DBIx::QuickORM::Role::Source' role";
442             }
443              
444 56 50       211 if (my $r = ref($in)) {
445 0 0       0 if ($r eq 'SCALAR') {
446 0         0 require DBIx::QuickORM::LiteralSource;
447 0         0 return DBIx::QuickORM::LiteralSource->new($in);
448             }
449              
450 0 0       0 return undef if $params{no_fatal};
451 0         0 croak "Not sure what to do with '$r'";
452             }
453              
454 56         630 my $source = $self->schema->table($in);
455 56 50       457 return $source if $source;
456              
457 0 0       0 return undef if $params{no_fatal};
458 0         0 croak "Could not find the '$in' table in the schema";
459             }
460              
461             #######################
462             # }}} UTILITY METHODS #
463             #######################
464              
465             #########################
466             # {{{ HANDLE OPERATIONS #
467             #########################
468              
469             sub handle {
470 79     79 1 2665 my $self = shift;
471 79         442 my ($in, @args) = @_;
472              
473 79         202 my $handle;
474 79 50 66     2775 if ((blessed($in) || !ref($in)) && ($in->isa('DBIx::QuickORM::Handle') || $in->DOES('DBIx::QuickORM::Role::Handle'))) {
      33        
      33        
475 0 0       0 return $in unless @args;
476 0         0 return $in->handle(@args);
477             }
478              
479 79         1466 return $self->{+DEFAULT_HANDLE_CLASS}->handle(connection => $self, @_);
480             }
481              
482 0     0 1 0 sub async { shift->handle(@_)->async }
483 0     0 1 0 sub aside { shift->handle(@_)->aside }
484 0     0 1 0 sub forked { shift->handle(@_)->forked }
485              
486 0     0 1 0 sub all { shift->handle(@_)->all }
487 0     0 1 0 sub iterator { shift->handle(@_)->iterator }
488 0     0 1 0 sub any { shift->handle(@_)->any }
489 0     0 1 0 sub first { shift->handle(@_)->first }
490 0     0 1 0 sub one { shift->handle(@_)->one }
491 2     2 1 1575 sub count { shift->handle(@_)->count }
492 0     0 1 0 sub delete { shift->handle(@_)->delete }
493              
494 0     0 1 0 sub by_id { my $arg = pop; shift->handle(@_)->by_id($arg) }
  0         0  
495 0     0 1 0 sub iterate { my $arg = pop; shift->handle(@_)->iterate($arg) }
  0         0  
496 21     21 1 123 sub insert { my $arg = pop; shift->handle(@_)->insert($arg) }
  21         135  
497 0     0 1 0 sub vivify { my $arg = pop; shift->handle(@_)->vivify($arg) }
  0         0  
498 10     10 1 27 sub update { my $arg = pop; shift->handle(@_)->update($arg) }
  10         54  
499              
500 0     0 1 0 sub update_or_insert { my $arg = pop; shift->handle(@_)->update_or_insert($arg) }
  0         0  
501 0     0 1 0 sub find_or_insert { my $arg = pop; shift->handle(@_)->update_or_insert($arg) }
  0         0  
502              
503             sub by_ids {
504 0     0 1 0 my $self = shift;
505 0         0 my ($from, @ids) = @_;
506              
507 0         0 my $handle;
508 0 0 0     0 if (blessed($from) && $from->isa('DBIx::QuickORM::Handle')) {
509 0         0 $handle = $from;
510             }
511             else {
512 0         0 $handle = $self->handle(source => $from);
513             }
514              
515 0         0 return $handle->by_ids(@ids);
516             }
517              
518             #########################
519             # }}} HANDLE OPERATIONS #
520             #########################
521              
522             ########################
523             # {{{ STATE OPERATIONS #
524             ########################
525              
526 16     16 1 101 sub state_does_cache { $_[0]->{+MANAGER}->does_cache }
527 8     8 1 22 sub state_delete_row { my $self = shift; $self->{+MANAGER}->delete(connection => $self, @_) }
  8         84  
528 79     79 1 215 sub state_insert_row { my $self = shift; $self->{+MANAGER}->insert(connection => $self, @_) }
  79         1208  
529 62     62 1 152 sub state_select_row { my $self = shift; $self->{+MANAGER}->select(connection => $self, @_) }
  62         655  
530 12     12 1 33 sub state_update_row { my $self = shift; $self->{+MANAGER}->update(connection => $self, @_) }
  12         186  
531 2     2 1 7 sub state_vivify_row { my $self = shift; $self->{+MANAGER}->vivify(connection => $self, @_) }
  2         34  
532 0     0 1 0 sub state_invalidate { my $self = shift; $self->{+MANAGER}->invalidate(connection => $self, @_) }
  0         0  
533 6     6 1 36 sub state_cache_lookup { $_[0]->{+MANAGER}->do_cache_lookup($_[1], undef, undef, $_[2]) }
534              
535             ########################
536             # }}} STATE OPERATIONS #
537             ########################
538              
539             1;
540              
541             __END__
542              
543             =head1 NAME
544              
545             DBIx::QuickORM::Connection - ORM connection to database.
546              
547             =head1 DESCRIPTION
548              
549             This module is the primary interface when using the ORM to connect to a
550             database. This contains the database connection itself, a clone of the original
551             schema along with any connection specific changes (temp tables, etc). You use
552             this class to interact with the database, manage transactions, and get
553             L<DBIx::QuickORM::Handle> objects that can be used to make queries against the
554             database.
555              
556             =head1 SYNOPSIS
557              
558             use My::Orm qw/orm/;
559              
560             # Get a connection to the orm
561             # Note: This will return the same connection each time, no need to cache it yourself.
562             my $orm = orm('my_orm');
563              
564             # Do something to all rows in the 'people' table.
565             my $people_handle = $orm->handle('people');
566             for my $person ($people_handle->all) {
567             ...
568             }
569              
570             # Find all people with the surname 'smith' and print their first names.
571             my $smith_handle = $people_handle->where({surname => 'smith'});
572             for my $person ($handle->all) {
573             print $person->field('first_name') . "\n"
574             }
575              
576             # Do a transaction that is managed by the ORM.
577             $con->txn(sub {
578             my $txn = shift;
579              
580             ...
581              
582             if (good()) {
583             # Can call commit or rollback manually. Or, if all is good just let
584             # the sub exit and the transaction will commit itself.
585             $txn->commit; # This will exit the subroutine
586             }
587             else {
588             # Can call rollback manually, or if the sub exits due to an
589             # exception being thrown, rollback will happen automatically.
590             $txn->rollback; # This will exit the subroutine
591             }
592             });
593              
594             =head1 METHODS
595              
596             =head2 HANDLE OPERATIONS
597              
598             See L<DBIx::QuickORM::Handle> for more information on handles
599              
600             =over 4
601              
602             =item $h = $con->handle(...)
603              
604             Get an L<DBIx::QuickORM::Handle> object with that operates on this connection.
605             Any argument accepted by the C<new()> or C<handle()> methods on
606             L<DBIx::QuickORM::Handle> can be provided here as arguments.
607              
608             =item $h = $con->async(@handle_constructor_args)
609              
610             =item $h = $con->aside(@handle_constructor_args)
611              
612             =item $h = $con->forked(@handle_constructor_args)
613              
614             =item $h = $con->all(@handle_constructor_args)
615              
616             =item $h = $con->iterator(@handle_constructor_args)
617              
618             =item $h = $con->any(@handle_constructor_args)
619              
620             =item $h = $con->first(@handle_constructor_args)
621              
622             =item $h = $con->one(@handle_constructor_args)
623              
624             =item $h = $con->count(@handle_constructor_args)
625              
626             =item $h = $con->delete(@handle_constructor_args)
627              
628             These are convenience methods that simply proxy to handle objects:
629              
630             my $h = $con->handle(@handle_constructor_args)->NAME();
631              
632             See the methods in L<DBIx::QuickORM::Handle> for more info.
633              
634             =item $h = $con->by_id(@handle_constructor_args, $method_arg)
635              
636             =item $h = $con->iterate(@handle_constructor_args, $method_arg)
637              
638             =item $h = $con->insert(@handle_constructor_args, $method_arg)
639              
640             =item $h = $con->vivify(@handle_constructor_args, $method_arg)
641              
642             =item $h = $con->update(@handle_constructor_args, $method_arg)
643              
644             =item $h = $con->update_or_insert(@handle_constructor_args, $method_arg)
645              
646             =item $h = $con->find_or_insert(@handle_constructor_args, $method_arg)
647              
648             These are convenience methods that simply proxy to handle objects:
649              
650             my $h = $con->handle(@handle_constructor_args)->NAME($method_arg);
651              
652             See the methods in L<DBIx::QuickORM::Handle> for more info.
653              
654             =item $rows_arrayref = $con->by_ids($source, @ids)
655              
656             Fetch rows in the specified source by their ids.
657              
658             B<NOTE:> If all the specified rows are already cached, no DB query will occur.
659              
660             C<$source> can be a table name, or any object that implements L<DBIx::QuickORM::Role::Source>.
661              
662             C<@ids> contains one or more row primary keys. The keys may be a scalar value
663             such as C<12> if the primary key is a single column. If the source has a
664             compound primary key you may provide an arrayref with all the key field values,
665             or a hashref with the C<< field => val >> pairs.
666              
667             An arrayref of L<DBIx::QuickORM::Row> objects will be returned.
668              
669             This is a convenience method that boild down to this:
670              
671             $con->handle($source)->by_ids(@ids);
672              
673             =back
674              
675             =head2 TRANSACTION MANAGEMENT
676              
677             =over 4
678              
679             =item $txn = $con->transaction(sub { my $txn = shift; ... })
680              
681             =item $txn = $con->txn(sub { my $txn = shift; ... })
682              
683             =item $txn = $con->transaction(%params)
684              
685             =item $txn = $con->txn(%params)
686              
687             This will start a transaction or create a savepoint to emulate nested
688             transactions. Call to this method can be nested.
689              
690             $con->txn(sub {
691             $con->txn(sub { ... }); # Nested! uses savepoints
692             });
693              
694             If an action sub is provided then the transaction will be started, and the
695             action sub will be executed. If the action sub returns then the transaction
696             will be commited. If the action sub throws an exception the transaction will be
697             rolled back.
698              
699             You can also manually commit/rollback which will exit the action subroutine.
700              
701             $txn->commmit;
702             $txn->rollback;
703              
704             If you need to start a transaction that is not limited to a single subroutine,
705             you can call this method without an action sub, it will return an
706             L<DBIx::QuickORM::Connection::Transaction> instance that can be used to commmit
707             or rollback the transaction when you are ready. If the object falls completely
708             out of scope and is destroyed then the transaction will be rolled back.
709              
710             All possible arguments:
711              
712             my $txn = $con->txn(
713             # Action sub for this transaction, transaction ends when sub does.
714             action => sub { my $txn = shift; ... },
715              
716             # Used to force a transaction even if there are aside or forked queries running.
717             force => $BOOL, # Basically a combination of the next 2 options
718             ignore_aside => $BOOL, # Allow a transaction even if an aside query is active
719             ignore_forks => $BOOL, # Allow a transaction even if a forked query is active
720              
721             # Things to run at the end of the transaction.
722             on_fail => sub { ... }, # Only runs if the txn is rolled back
723             on_success => sub { ... }, # Only runs if the txn is commited
724             on_completion => sub { ... }, # Runs whent he txn is done regardless of status.
725              
726             # Same as above, except you are adding them to a direct parent txn (if one exists, otherwise they are no-ops)
727             on_parent_fail => sub { ... },
728             on_parent_success => sub { ... },
729             on_parent_completion => sub { ... },
730              
731             # Same as above, except they are applied to the root transaction, no
732             # matter how deeply nested it is.
733             on_root_fail => sub { ... },
734             on_root_success => sub { ... },
735             on_root_completion => sub { ... },
736             );
737              
738             An L<DBIx::QuickORM::Connection::Transaction> instance is always returned. If
739             an action callback was provided then the instance will already be complete, but
740             you can check and see what the status was. If you did not provide an action
741             callback then the txn will be "live" and you can use the instance to commit it
742             or roll it back.
743              
744             =item $bool_or_txn = $con->in_transaction
745              
746             =item $bool_or_txn = $con->in_txn
747              
748             Returns true if there is a transaction active. If the transaction is managed by
749             L<DBIx::QuickORM> then the L<DBIx::QuickORM::Connection::Transaction> object
750             will be returned.
751              
752             =item $txn = $con->current_transaction
753              
754             =item $txn = $con->current_txn
755              
756             Return the current L<DBIx::QuickORM::Connection::Transaction> if one is active.
757              
758             B<Note:> Do not use this to check for a transaction, it will return false if
759             there is a transaction that is not managed by L<DBIx::QuickORM>.
760              
761             =item $con->auto_retry_txn(sub { my $txn = shift; ... })
762              
763             =item $con->auto_retry_txn(\%params, sub { my $txn = shift; ... })
764              
765             =item $con->auto_retry_txn(%params, action => sub { my $txn = shift; ... })
766              
767             Run the specified action in a transaction, retry if an exception is thrown.
768              
769             Run the subroutine is a convenience method that boild down to:
770              
771             $con->auto_retry(sub { $con->txn(sub { ... }) });
772              
773             C<< count => $NUM >> can be used to specify a maximum number of retries, the default is 1.
774              
775             All other params are passed to C<txn()>.
776              
777             =back
778              
779             =head2 UTILITY
780              
781             =over 4
782              
783             =item $db = $con->db
784              
785             Shortcut for C<< $con->orm->db >>.
786              
787             This returns an L<DBIx::QuickORM::DB> object.
788              
789             =item $dbh = $con->dbh
790              
791             Shortcut for C<< $con->orm->dbh >>.
792              
793             Returns the $dbh object used for this connection.
794              
795             =item $dbh = $con->aside_dbh
796              
797             Shortcut for C<< $con->orm->db->new_db >>.
798              
799             Returns a completely new and independant $dbh connected to the database.h
800              
801             =item $res = $con->auto_retry(sub { ... })
802              
803             =item $res = $con->auto_retry($count, sub { ... })
804              
805             Run the provided sub multiple times until it succeeds or the count is exceeded.
806              
807             Default count is 1.
808              
809             An exception will be thrown if it never succeeds.
810              
811             Cannot be used inside a transaction.
812              
813             Returns whatever the provided coderef returns, scalar context is always
814             assumed.
815              
816             =item $class = $con->default_handle_class
817              
818             Get the default handle class for this connection. Default is
819             L<DBIx::QuickORM::Handle>.
820              
821             =item $bool = $con->default_internal_txn
822              
823             Used by handles to know if they should default to allowing internal
824             transactions, that is temporary transactions the handles use under the hood
825             without the user necessarily being aware of them.
826              
827             =item $class = $con->default_sql_builder
828              
829             Default SQL Builder class to use. Normally
830             L<DBIx::QuickORM::SQLBuilder::SQLAbstract>.
831              
832             =item $dialect = $con->dialect
833              
834             Returns the L<DBIx::QuickORM::Dialect> subclass for the connection.
835              
836             =item $manager = $con->manager
837              
838             Returns the L<DBIx::QuickORM::RowManager> subclass to use for managing cache
839             and other row state.
840              
841             =item $orm = $con->orm
842              
843             Returns the L<DBIx::QuickORM::ORM> object associated with this connection.
844              
845             =item $pid = $con->pid
846              
847             Retusn the PID the connection is associated with.
848              
849             =item $schema = $con->schema
850              
851             Returns the L<DBIx::QuickORM::Schema> object for this connection. This is a
852             deep clone of the one from the L<DBIx::QuickORM::ORM>'s schema object, with
853             connections pecific changes such as local tables being added.
854              
855             Modifying this will B<NOT> modify the schema in the root ORM object.
856              
857             =item $source = $con->source
858              
859             Returns the soure object. The source object should implement the
860             L<DBIx::QuickORM::Role::Source> role. It will usually be an
861             L<DBIx::QuickORM::Schema::Table> instance, but could also be an
862             L<DBIx::QuickORM::Join> or other object implementing the role.
863              
864             This is B<NOT> like calling C<source()> from L<DBIx::Class>, you cannot use the
865             source directly to make queries, look at the C<handle()> method instead.
866              
867             =back
868              
869             =head2 SANITY CHECKS
870              
871             These are sanity checks that will throw exceptions if invalid conditions are
872             detected.
873              
874             =over 4
875              
876             =item $con->pid_check
877              
878             Throws an exception if the current PID does not match the connections PID.
879              
880             =item $con->async_check
881              
882             Throws an exception if there is an async query running.
883              
884             =item $con->pid_and_async_check
885              
886             Throws an exception if the PID does not match, or if there is an async query
887             running.
888              
889             =back
890              
891             =head2 INTERNAL STATE MANAGEMENT
892              
893             =over 4
894              
895             =item $con->set_async($async)
896              
897             Change state to be inside an async query, argument must be an
898             L<DBIx::QuickORM::STH::Async> instance.
899              
900             =item $con->clear_async($async)
901              
902             Change state to be outside of an async query. The argument must be an
903             L<DBIx::QuickORM::STH::Async> instance, and it must be the same object as the
904             one returned by C<in_async()>.
905              
906             =item $obj = $con->in_async
907              
908             Returns the active L<DBIx::QuickORM::STH::Async> object if there is an active
909             async query. Returns undef if there is no active async query.
910              
911             =item $con->add_aside($aside)
912              
913             =item $con->asides
914              
915             =item $con->clear_aside($aside)
916              
917             Used to add or clear 'aside' queries.
918              
919             =item $con->add_fork($fork)
920              
921             =item $con->forks
922              
923             =item $con->clear_fork($fork)
924              
925             Used to add or clear 'forked' queries.
926              
927             =item $con->reconnect
928              
929             Used to reconnect after forking.
930              
931             =item $arrayref = $con->transactions
932              
933             For internal use only.
934              
935             =back
936              
937             =head1 ROW STATE MANAGEMENT
938              
939             =over 4
940              
941             =item $bool = $con->state_does_cache
942              
943             Check if the current rowmanager handles caching of rows.
944              
945             =item $row = $con->state_cache_lookup($source, $pk)
946              
947             Find an in-cache row by source and primary key. Source can be a table name or
948             object that implements L<DBIx::QuickORM::Role::Source>.
949              
950             The primary key should be a hashref:
951              
952             {pk_field1 => $pk_val1, pk_field2 => $pk_val2, ... }
953              
954             =item $con->state_delete_row(...)
955              
956             =item $con->state_insert_row(...)
957              
958             =item $con->state_select_row(...)
959              
960             =item $con->state_update_row(...)
961              
962             =item $con->state_vivify_row(...)
963              
964             =item $con->state_invalidate(...)
965              
966             These are shortcuts for:
967              
968             $self->manager->METHOD(connection => $self, ...);
969              
970             =back
971              
972             =head1 SOURCE
973              
974             The source code repository for DBIx-QuickORM can be found at
975             L<http://github.com/exodist/DBIx-QuickORM/>.
976              
977             =head1 MAINTAINERS
978              
979             =over 4
980              
981             =item Chad Granum E<lt>exodist@cpan.orgE<gt>
982              
983             =back
984              
985             =head1 AUTHORS
986              
987             =over 4
988              
989             =item Chad Granum E<lt>exodist@cpan.orgE<gt>
990              
991             =back
992              
993             =head1 COPYRIGHT
994              
995             Copyright Chad Granum E<lt>exodist7@gmail.comE<gt>.
996              
997             This program is free software; you can redistribute it and/or
998             modify it under the same terms as Perl itself.
999              
1000             See L<http://dev.perl.org/licenses/>
1001              
1002             =cut