DBIO

 view release on metacpan or  search on metacpan

t/resultset/async_parity_helpers.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;
use Test::Exception;

use DBIO::Test;
use DBIO::Future::Immediate;
use DBIO::Storage::Async;
use DBIO::Storage::DBI;

# ADR 0031's own Consequences section named Row-level update_async/delete_async
# as "not added (no caller); only Row::insert_async was needed (by
# create_async). Same pattern when wanted." DBIO-Valiant's validated async
# writes are that caller now. This file gives every Row/ResultSet operation
# ADR 0031 left out a real, backend-routed async counterpart: the row-level
# primitives (update_async/delete_async), the cheap wins that fall out of
# find_async (get_from_storage_async/discard_changes_async/
# update_or_insert_async/count_literal_async), the find_async-composed
# composites (find_or_new_async/find_or_create_async/update_or_create_async/
# update_or_new_async), and results_exist_async.
#
# All of this runs on the mock storage -- no real DB, no event loop.

# --- A mock async backend that delegates to the sync storage ------------------
# Same shape as t/resultset/async_backend.t's My::Mock::RowBackend, extended
# with update_async/delete_async (which that file's mock never needed).
{
  package My::Mock::ParityBackend;
  use base 'DBIO::Storage::Async';

  sub new { my ($c, $s) = @_; bless { schema => $s, calls => [] }, $c }
  sub future_class { 'DBIO::Future::Immediate' }
  sub connect_info { my $s = shift; $s->{connect_info} = shift if @_; $s->{connect_info} }
  sub disconnect { 1 }

  sub _sync { $_[0]{schema}->storage }

  sub select_async {
    my ($self, @args) = @_;
    push @{$self->{calls}}, 'select';
    my @rows = $self->_sync->select(@args)->all;
    return DBIO::Future::Immediate->done(@rows);
  }

  sub select_single_async {
    my ($self, @args) = @_;
    push @{$self->{calls}}, 'select_single';
    my @row = $self->_sync->select_single(@args);
    return DBIO::Future::Immediate->done( @row ? [ @row ] : undef );
  }

  sub insert_async {
    my ($self, @args) = @_;
    push @{$self->{calls}}, 'insert';
    my $cols = $self->_sync->insert(@args);
    return DBIO::Future::Immediate->done($cols);
  }

  sub update_async {
    my ($self, @args) = @_;
    push @{$self->{calls}}, 'update';
    my $rows = $self->_sync->update(@args);
    return DBIO::Future::Immediate->done($rows);
  }

  sub delete_async {
    my ($self, @args) = @_;
    push @{$self->{calls}}, 'delete';
    my $rows = $self->_sync->delete(@args);
    return DBIO::Future::Immediate->done($rows);
  }

  # The transport seam for an already-rendered statement (ADR 0037 section 2:
  # results_exist executes the _exists_value_sql hook's complete statement,
  # which has no ident/select/where to hand to the CRUD entry points). Routed
  # through the sync fake storage so the statement lands in the same captured
  # query log the sync path uses -- that is what makes SQL parity assertable.
  sub _query_async {
    my ($self, $sql, $bind) = @_;
    push @{$self->{calls}}, 'query';
    my (undef, $sth) = $self->_sync->_execute_rendered($sql, $bind);
    return DBIO::Future::Immediate->done(@{ $sth->fetchall_arrayref || [] });
  }
}

DBIO::Storage::DBI->register_async_mode( parityasyncmock => 'My::Mock::ParityBackend' );

# Set the chosen mode on a mock storage exactly as connect would, clearing the
# resolved-backend cache. Mirrors the helper in t/resultset/async_backend.t.
sub set_mode {
  my ($storage, $mode) = @_;
  $storage->_async_mode($mode);
  delete $storage->{_async_storage_obj};
  return $storage;
}

# --- A local schema carrying an OnColumnChange hook -------------------------
# Isolated from DBIO::Test::Schema (which registers no hooks) so registering
# before/after callbacks here can't leak into other tests. Mirrors the
# TestOCC::Schema fixture in t/helpers/row_helpers_storage.t.
{
  package TestUAOCC::Changes;
  our @LOG;
  sub reset { @LOG = () }
  sub all   { @LOG }
}

{
  package TestUAOCC::Schema;
  use base 'DBIO::Schema';
}

{
  package TestUAOCC::Schema::Result::Account;
  use base 'DBIO::Core';

  __PACKAGE__->table('account');
  __PACKAGE__->add_columns(
    id => {



( run in 0.945 second using v1.01-cache-2.11-cpan-145b269f2f3 )