view release on metacpan or search on metacpan
- Rename select to query
- Rename sqla-source to query-source
- Work on eliminating the assumption that SQLAbstract will always do the work
0.000010 2025-05-07 06:36:38-07:00 America/Los_Angeles (TRIAL RELEASE)
- Still felshing out functionality after the rewrite
- Add 'forked' async emulation
- Add 'aside' async functionality
- Add more txn callbacks
0.000009 2025-05-06 08:17:08-07:00 America/Los_Angeles (TRIAL RELEASE)
0.000008 2025-05-02 01:20:14-07:00 America/Los_Angeles (TRIAL RELEASE)
0.000007 2025-05-02 01:04:21-07:00 America/Los_Angeles (TRIAL RELEASE)
0.000006 2025-05-02 01:02:32-07:00 America/Los_Angeles
0.000005 2025-05-02 00:19:35-07:00 America/Los_Angeles (TRIAL RELEASE)
lib/DBIx/QuickORM/Connection.pm view on Meta::CPAN
my $txn = DBIx::QuickORM::Connection::Transaction->new(
id => $self->{+_TXN_COUNTER}++,
savepoint => $sp,
trace => \@caller,
on_fail => $params{on_fail},
on_success => $params{on_success},
on_completion => $params{on_completion},
);
$self->_txn_attach_relative_callbacks($txn, \%params);
push @{$txns} => $txn;
weaken($txns->[-1]);
my $finalize = $self->_txn_finalizer($sp);
unless($cb) {
$txn->set_no_last(1);
$txn->set_finalize($finalize);
return $txn;
lib/DBIx/QuickORM/Connection.pm view on Meta::CPAN
}
croak "A transaction is already open, but it is not controlled by DBIx::QuickORM" if $dialect->in_txn;
$dialect->start_txn;
return undef;
}
=pod
=item $con->_txn_attach_relative_callbacks($txn, \%params)
Attaches C<on_parent_*> callbacks to the current innermost transaction and
C<on_root_*> callbacks to the outermost one. Called before C<$txn> is pushed
onto the stack.
=cut
sub _txn_attach_relative_callbacks {
my $self = shift;
my ($txn, $params) = @_;
my $txns = $self->{+TRANSACTIONS};
# With an empty stack the new txn is its own root, but it has no parent;
# on_parent_* callbacks are documented as no-ops in that case. Stack
# entries are weak references, so check definedness before using them.
my $parent = @$txns ? $txns->[-1] : undef;
my $root = @$txns ? $txns->[0] : $txn;
if ($parent) {
$parent->add_fail_callback($params->{'on_parent_fail'}) if $params->{on_parent_fail};
$parent->add_success_callback($params->{'on_parent_success'}) if $params->{on_parent_success};
$parent->add_completion_callback($params->{'on_parent_completion'}) if $params->{on_parent_completion};
}
lib/DBIx/QuickORM/Connection.pm view on Meta::CPAN
return;
}
=pod
=item $cb = $con->_txn_finalizer($savepoint_or_undef)
Builds the one-shot finalize callback that pops the transaction off the
stack, commits or rolls back (savepoint or real transaction), and fires the
transaction's callbacks via C<terminate>.
=cut
sub _txn_finalizer {
my $self = shift;
my ($sp) = @_;
my $txns = $self->{+TRANSACTIONS};
my $dialect = $self->dialect;
lib/DBIx/QuickORM/Connection/Transaction.pm view on Meta::CPAN
=encoding UTF-8
=head1 NAME
DBIx::QuickORM::Connection::Transaction - One transaction or savepoint on a
DBIx::QuickORM connection.
=head1 DESCRIPTION
Represents a single transaction (or savepoint) and the callbacks queued
against it. C<commit> and C<rollback> record the outcome and break out of the
enclosing C<QORM_TRANSACTION> loop; C<terminate> records the final result and
fires the queued success / fail / completion callbacks. An optional finalize
callback runs when the transaction completes or, as a safety net, when the
object is destroyed while still pending.
=head1 SYNOPSIS
QORM_TRANSACTION: {
my $txn = DBIx::QuickORM::Connection::Transaction->new(id => $id);
$txn->add_success_callback(sub { ... });
...
$txn->commit;
lib/DBIx/QuickORM/Connection/Transaction.pm view on Meta::CPAN
The savepoint name when this transaction is implemented as a savepoint, undef
for a top-level transaction. Use C<is_savepoint> for a boolean check.
=item on_success
=item on_fail
=item on_completion
Callback queues (arrayrefs, or a single coderef normalized to one) fired by
C<terminate>. Success or fail callbacks run depending on the outcome,
followed by completion callbacks in both cases.
=item verbose
When true, C<commit> / C<rollback> warn a trace line. A string longer than
one character is used as the transaction name in that warning.
=item result
Undef while open; 1 on success, 0 on failure once terminated.
lib/DBIx/QuickORM/Connection/Transaction.pm view on Meta::CPAN
no warnings 'exiting';
last QORM_TRANSACTION;
}
=pod
=item ($ok, $errors) = $txn->terminate($res, $err)
Records the final result, clears the callback queues, then runs the
success-or-fail callbacks followed by the completion callbacks. Returns a
list: a boolean for whether all callbacks succeeded, and an arrayref of any
callback errors (undef when none). The savepoint name is retained so
post-completion callbacks can still see C<is_savepoint>.
=cut
sub terminate {
my $self = shift;
my ($res, $err) = @_;
$self->{+RESULT} = $res ? 1 : 0;
$self->{+ERRORS} = $res ? undef : $err;
lib/DBIx/QuickORM/Dialect.pm view on Meta::CPAN
# {{{ Schema Builder Code
###############################################################################
=pod
=item $schema = $dialect->build_schema_from_db(%params)
Introspects the live database and returns a L<DBIx::QuickORM::Schema>.
Requires an C<autofill> object. After all tables are built it runs the
autofill C<tables> hook with the complete name-to-table hashref under the
C<tables> key, giving callbacks one place to inspect or adjust the full set.
=cut
sub build_schema_from_db {
my $self = shift;
my %params = @_;
croak "No autofill object provided" unless $params{autofill};
my $dbh = $self->dbh;
lib/DBIx/QuickORM/Manual.pm view on Meta::CPAN
Fetch, create, update, and delete rows with handles: where clauses, ordering,
limiting, iterators, and more.
=item L<DBIx::QuickORM::Manual::Relations>
Define links (foreign keys) and follow them between rows, plus joins.
=item L<DBIx::QuickORM::Manual::Transactions>
Transactions, nested transactions and savepoints, callbacks, and automatic
retry.
=item L<DBIx::QuickORM::Manual::Async>
Asynchronous, aside, and forked queries, and other multi-connection work.
=item L<DBIx::QuickORM::Manual::Types>
Inflating and deflating column values (JSON, UUID, ...) and writing your own
type classes.
lib/DBIx/QuickORM/Manual/Features.pm view on Meta::CPAN
Fetch, create, update, and delete rows with handles (where/order/limit/
iterators). See L<DBIx::QuickORM::Manual::Querying>.
=item Relations
Define links (foreign keys) and follow them between rows, plus joins. See
L<DBIx::QuickORM::Manual::Relations>.
=item Transactions
Transactions, nested transactions / savepoints, callbacks, and auto-retry.
See L<DBIx::QuickORM::Manual::Transactions>.
=item Async, aside, and forked queries
Run queries asynchronously, on a side connection, or in a forked child. See
L<DBIx::QuickORM::Manual::Async>.
=item Caching / row identity
One in-memory copy of each row per connection. See
lib/DBIx/QuickORM/Manual/QuickStart.pm view on Meta::CPAN
The full handle interface: where clauses, ordering, limiting, iterators,
create, update, and delete.
=item L<DBIx::QuickORM::Manual::Relations>
Define links (foreign keys), follow them, and join across them.
=item L<DBIx::QuickORM::Manual::Transactions>
Nested transactions, savepoints, callbacks, and automatic retry.
=item L<DBIx::QuickORM::Manual>
The documentation hub, linking every tutorial, guide, and reference.
=back
=head1 SOURCE
The source code repository for DBIx-QuickORM can be found at
lib/DBIx/QuickORM/Manual/Recipes.pm view on Meta::CPAN
=item L<DBIx::QuickORM::Manual::Querying>
Fetch, create, update, and delete rows with handles.
=item L<DBIx::QuickORM::Manual::Relations>
Define links (foreign keys) and follow them between rows, plus joins.
=item L<DBIx::QuickORM::Manual::Transactions>
Transactions, nested transactions and savepoints, callbacks, and automatic
retry.
=item L<DBIx::QuickORM::Manual::Async>
Asynchronous, aside, and forked queries, and other multi-connection work.
=item L<DBIx::QuickORM::Manual::Types>
Inflating and deflating column values (JSON, UUID, ...) and writing your own
type classes.
lib/DBIx/QuickORM/Manual/Transactions.pm view on Meta::CPAN
=head1 NAME
DBIx::QuickORM::Manual::Transactions - A guide to transactions in
L<DBIx::QuickORM>.
=head1 DESCRIPTION
This guide covers transactions in L<DBIx::QuickORM>: starting a transaction,
nesting transactions as savepoints, queuing success / fail / completion
callbacks, controlling a transaction by hand, and automatically retrying work
when a connection is lost.
Transactions are controlled through the connection
(L<DBIx::QuickORM::Connection>). Each transaction or savepoint is represented
by a L<DBIx::QuickORM::Connection::Transaction> object.
This is part of the L<DBIx::QuickORM> documentation; see
L<DBIx::QuickORM::Manual> for the documentation hub.
=head1 BASIC TRANSACTIONS
lib/DBIx/QuickORM/Manual/Transactions.pm view on Meta::CPAN
# rolling this back undoes only $bar's insert
});
$baz->insert(...);
}); # commit happens here
Use C<is_savepoint> on a transaction object to tell which kind it is.
=head1 CALLBACKS
You can queue callbacks to run when a transaction finishes. They are fired
after the underlying commit or rollback has been issued.
=over 4
=item on_success
Runs only if the transaction commits.
=item on_fail
lib/DBIx/QuickORM/Manual/Transactions.pm view on Meta::CPAN
Pass them as parameters to C<txn()>:
$con->txn(
on_success => sub { my $txn = shift; ... },
on_fail => sub { my $txn = shift; ... },
on_completion => sub { my $txn = shift; ... },
action => sub { my $txn = shift; ... },
);
You can also queue callbacks against an existing transaction object directly
with C<add_success_callback>, C<add_fail_callback>, and
C<add_completion_callback>.
=head2 PARENT AND ROOT CALLBACKS
When you are inside a nested transaction you can attach callbacks to an outer
transaction instead of the current one. This is useful when a savepoint wants
to defer work until the enclosing transaction actually commits.
The C<on_parent_*> variants attach to the immediate parent transaction; the
C<on_root_*> variants attach to the outermost (root) transaction no matter how
deeply nested you are:
$con->txn(
on_parent_success => sub { ... },
on_parent_fail => sub { ... },
on_parent_completion => sub { ... },
on_root_success => sub { ... },
on_root_fail => sub { ... },
on_root_completion => sub { ... },
action => sub { ... },
);
When there is no parent or root transaction above the current one, the
corresponding parent / root callbacks are simply no-ops.
=head1 LONG-LIVED TRANSACTIONS
If you need a transaction that is not bound to a single callback, call C<txn()>
without an action. It returns a live L<DBIx::QuickORM::Connection::Transaction>
object that you control by hand:
my $txn = $con->txn();
...
$txn->commit; # or $txn->rollback;
lib/DBIx/QuickORM/Schema/Autofill.pm view on Meta::CPAN
=pod
=encoding UTF-8
=head1 NAME
DBIx::QuickORM::Schema::Autofill - Autofill configuration for schema introspection.
=head1 DESCRIPTION
Holds the type maps, affinity callbacks, and hooks used while autofilling a
schema from a live database. It maps introspected SQL types to
L<DBIx::QuickORM::Type> classes, runs user-supplied hooks at well-known points,
and generates field and link accessors on autovivified row classes.
=head1 SYNOPSIS
my $autofill = DBIx::QuickORM::Schema::Autofill->new(
types => {...},
affinities => {...},
hooks => {...},
lib/DBIx/QuickORM/Schema/Autofill.pm view on Meta::CPAN
=head1 ATTRIBUTES
=over 4
=item types
Hashref mapping SQL type names to type objects/classes.
=item affinities
Hashref mapping affinity names to arrayrefs of callbacks.
=item hooks
Hashref mapping hook names to arrayrefs of callbacks.
=item autorow
The autovivified row class configuration.
=item skip
Nested hashref describing what to skip during autofill.
=back
=cut
# Maps each valid hook name to its seed key: the args key whose value is
# threaded through the callbacks registered for that hook.
my %HOOKS = (
column => 'column',
columns => 'columns',
index => 'index',
indexes => 'indexes',
links => 'links',
post_column => 'column',
post_table => 'table',
pre_column => 'column',
pre_table => 'table',
lib/DBIx/QuickORM/Schema/Autofill.pm view on Meta::CPAN
=pod
=item $out = $autofill->hook($name, \%args, $seed)
Run every callback registered for the named hook as a pipeline. Each hook has
a designated seed key in C<\%args> (for example C<table> for the table hooks,
C<name> for the accessor hooks). Every callback is called with the args (plus
C<autofill>) with the running value under the seed key, and its return value
becomes the running value passed to the next callback and ultimately returned.
A callback that modifies the seed in place must still return it so the
callbacks after it (and the caller) see the same value. The pipeline starts
from C<$seed> when given, otherwise from the seed key's value in C<\%args>;
with a single registered callback this matches the old single-callback
behavior exactly.
=cut
sub hook {
my $self = shift;
my ($hook, $args, $seed) = @_;
lib/DBIx/QuickORM/Schema/Autofill.pm view on Meta::CPAN
$from = $from->{$arg} or return 0;
}
return $from;
}
=pod
=item $autofill->process_column(\%col)
Resolve the column's scalar-ref type into a real type object, using the type map
first and then affinity callbacks. Updates the column's C<type> and C<affinity>
in place when a match is found.
=cut
sub process_column {
my $self = shift;
my ($col) = @_;
my $type = $col->{type};
my $tref = ref($type);
t/AI/transaction_audit.t view on Meta::CPAN
ok($txn->rolled_back, "transaction rolled back");
is(scalar(@{$con->transactions}), 0, "transaction stack is clean");
ok(!$con->dialect->in_txn, "no transaction left open on the database");
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
my ($count) = $dbh->selectrow_array("SELECT COUNT(*) FROM things WHERE name = 'wedge'");
$dbh->disconnect;
is($count, 0, "the insert really was rolled back");
};
subtest on_parent_callbacks => sub {
my $con = connect_orm();
my %fired;
my $ok = eval {
$con->txn(
on_parent_fail => sub { $fired{parent_fail}++ },
on_parent_completion => sub { $fired{parent_completion}++ },
on_root_fail => sub { $fired{root_fail}++ },
on_root_completion => sub { $fired{root_completion}++ },
action => sub { die "boom\n" },
t/AI/transaction_audit.t view on Meta::CPAN
ok(!$ok, "root transaction failed");
is(\%fired, {root_fail => 1, root_completion => 1}, "on_parent_* are no-ops without a parent, on_root_* fire on self");
%fired = ();
$con->txn(sub {
$con->txn(
on_parent_success => sub { $fired{parent_success}++ },
on_parent_completion => sub { $fired{parent_completion}++ },
action => sub { 1 },
);
is(\%fired, {}, "parent callbacks have not fired before the parent completes");
});
is(\%fired, {parent_success => 1, parent_completion => 1}, "on_parent_* attach to the real parent when nested");
};
subtest already_complete_croaks => sub {
my $con = connect_orm();
my $txn = $con->txn();
$txn->commit;
ok($txn->complete, "transaction completed");
t/AI/transaction_audit.t view on Meta::CPAN
my $con = connect_orm();
my $saw;
$con->txn(sub {
$con->txn(
on_completion => sub { my $t = shift; $saw = $t->is_savepoint },
action => sub { 1 },
);
});
is($saw, 1, "post-completion callbacks still see is_savepoint true for a savepoint txn");
};
done_testing;
t/AI/transaction_extra.t view on Meta::CPAN
$con->handle('items')->insert({name => 'outer_keep2'});
});
is(
disk_names(),
[sort(@$before, 'outer_keep', 'outer_keep2')],
"outer changes persisted, inner savepoint rollback discarded only its row",
);
};
subtest callbacks_on_commit => sub {
my %seen;
$con->txn(
action => sub { $seen{action}++ },
on_success => sub { $seen{success}++ },
on_fail => sub { $seen{fail}++ },
on_completion => sub { $seen{completion}++ },
);
is(\%seen, {action => 1, success => 1, completion => 1}, "commit fires success+completion, not fail");
};
subtest callbacks_on_rollback => sub {
my %seen;
$con->txn(
action => sub { $seen{action}++; $_[0]->rollback },
on_success => sub { $seen{success}++ },
on_fail => sub { $seen{fail}++ },
on_completion => sub { $seen{completion}++ },
);
is(\%seen, {action => 1, fail => 1, completion => 1}, "rollback fires fail+completion, not success");
};
subtest callbacks_added_to_object => sub {
my %seen;
$con->txn(sub {
my $t = shift;
$t->add_success_callback(sub { $seen{success}++ });
$t->add_fail_callback(sub { $seen{fail}++ });
$t->add_completion_callback(sub { $seen{completion}++ });
});
is(\%seen, {success => 1, completion => 1}, "add_*_callback success path");
};