DBIx-QuickORM
view release on metacpan or search on metacpan
t/AI/batch_introspect_roundtrips.t view on Meta::CPAN
use Test2::V0;
use DBI;
use File::Temp qw/tempdir/;
use lib 't/lib';
use DBIx::QuickORM::Test qw/psql mysql/;
# Batch schema introspection issues a CONSTANT number of database round trips
# regardless of how many tables the database has (one sweep per metadata kind),
# instead of the old query-per-table behavior. This asserts that the round-trip
# count for a 2-table database equals the count for a 25-table database, and
# that it is far below the table count (i.e. O(1), not O(N)).
require DBIx::QuickORM;
# Introspect through the ORM with query-counting callbacks on the connection;
# return (round_trip_count, table_count). $open returns a fresh raw dbh.
sub introspect_queries {
my ($open) = @_;
my $count = 0;
my $con = DBIx::QuickORM->quick(
connect => sub {
my $dbh = $open->();
$dbh->{Callbacks} = {
map { $_ => sub { $count++; return } }
qw/prepare do selectrow_array selectrow_arrayref selectall_arrayref selectcol_arrayref/
};
return $dbh;
},
);
my @tables = $con->schema->tables;
return ($count, scalar @tables);
}
sub make_range {
my ($dbh, $from, $to, %c) = @_;
my $id = $c{id} // 'INTEGER PRIMARY KEY';
my $a = $c{a} // 'TEXT';
for my $i ($from .. $to) {
$dbh->do("CREATE TABLE t$i (id $id, a $a NOT NULL, b INTEGER)");
$dbh->do("CREATE INDEX t${i}_b ON t$i(b)");
$dbh->do("CREATE UNIQUE INDEX t${i}_a ON t$i(a)");
}
}
# Build a 2-table db, count introspection round trips; grow it to 25 tables,
# count again. The two counts must be equal (constant) and well under 25.
sub check_flavor {
my %a = @_;
subtest $a{name} => sub {
{ my $dbh = $a{open}->(); make_range($dbh, 1, 2, %{$a{cols} // {}}); $dbh->disconnect; }
my ($q2, $t2) = introspect_queries($a{open});
{ my $dbh = $a{open}->(); make_range($dbh, 3, 25, %{$a{cols} // {}}); $dbh->disconnect; }
my ($q25, $t25) = introspect_queries($a{open});
is($t2, 2, "2 tables introspected");
is($t25, 25, "25 tables introspected");
is($q2, $q25, "round-trip count is constant: $q2 (2 tables) == $q25 (25 tables)");
cmp_ok($q25, '<', $t25, "sub-linear: $q25 round trips for $t25 tables (was O(N) per-table)");
};
}
# SQLite (always available; the default backend).
SKIP: {
skip "DBD::SQLite required" unless eval { require DBD::SQLite; 1 };
my $dir = tempdir(CLEANUP => 1);
my $dsn = "dbi:SQLite:dbname=$dir/rt.sqlite";
check_flavor(
name => 'sqlite',
open => sub { DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0, AutoCommit => 1}) },
);
( run in 1.390 second using v1.01-cache-2.11-cpan-85f18b9d64f )