DBIO
view release on metacpan or search on metacpan
t/debug/async_upsert_trace.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use DBIO::Test::Storage;
use DBIO::Future::Immediate;
use DBIO::Storage::DBI;
use DBIO::Storage::Async;
use DBIO::Storage::Statistics;
# Every rendering of a statement gets its own copy of the options (karr k405).
# A driver SQL maker consumes on_conflict (and insert_or) from the options it
# receives, so the statement on the wire and the rendering that resolves the
# bind attributes of a level 2 trace each see the complete options: the
# attribute list lines up with the binds, an encode_column value is masked, the
# redact_bind_value hook sees the column name, and the options of the caller
# keep what they were given.
{
package T405::SQLMaker;
use base 'DBIO::SQLMaker';
use mro 'c3';
# the shape of the driver makers: consume the keys, append a conflict tail
# with a bind of its own
sub insert {
my ($self, $table, $data, $options) = @_;
my $or = ref $options eq 'HASH' ? delete $options->{insert_or} : undef;
my $on_conflict = ref $options eq 'HASH' ? delete $options->{on_conflict} : undef;
my ($sql, @bind) = $self->next::method($table, $data, $options);
$sql =~ s/^INSERT/INSERT OR $or/ if defined $or;
if ($on_conflict) {
$sql .= ' ON CONFLICT (id) DO UPDATE SET name = ?';
push @bind, $self->{bindtype} eq 'columns'
? [ { dbic_colname => 'name' } => 'tail-value' ]
: 'tail-value';
}
return ($sql, @bind);
}
# update and delete: a key of the options is consumed
sub update {
my ($self, $table, $set, $where, $options) = @_;
delete $options->{marker} if ref $options eq 'HASH';
return $self->next::method($table, $set, $where);
}
sub delete {
my ($self, $table, $where, $options) = @_;
delete $options->{marker} if ref $options eq 'HASH';
return $self->next::method($table, $where);
}
}
{
package T405::Schema::Result::User;
use base 'DBIO::Core';
__PACKAGE__->table('users');
__PACKAGE__->add_columns(
id => { data_type => 'integer', is_auto_increment => 1 },
name => { data_type => 'varchar', size => 64, is_nullable => 1 },
password => { data_type => 'varchar', size => 255, is_nullable => 1, encode_column => 1 },
);
__PACKAGE__->set_primary_key('id');
package T405::Schema;
use base 'DBIO::Schema';
__PACKAGE__->register_class(User => 'T405::Schema::Result::User');
}
{
package T405::Backend;
use base 'DBIO::Storage::Async';
sub future_class { 'DBIO::Future::Immediate' }
sub sql_maker_class { 'T405::SQLMaker' }
sub _sql_maker_args { (quote_char => '"', name_sep => '.') }
sub _transform_sql { $_[1] }
sub _post_insert_sql { '' }
sub _query_async {
my ($self, $sql, $bind, $attrs) = @_;
push @{ $self->{seen} }, { sql => $sql, bind => $bind, attrs => $attrs };
$self->_debug_query($sql, $bind, $attrs);
return $self->future_class->done(1);
}
}
T405::Schema->storage_type('+DBIO::Test::Storage');
my $schema = T405::Schema->connect(sub { });
$schema->storage(DBIO::Test::Storage->new($schema));
my $owner = $schema->storage;
my $out = '';
open my $fh, '>', \$out or die;
my $stats = DBIO::Storage::Statistics->new;
$stats->debugfh($fh);
$owner->debugobj($stats);
my @hook_calls;
my $default_hook = $owner->redact_bind_value;
$owner->redact_bind_value(sub {
( run in 0.727 second using v1.01-cache-2.11-cpan-145b269f2f3 )