DBIx-QuickORM
view release on metacpan or search on metacpan
t/AI/caching.t view on Meta::CPAN
use Test2::V0;
use DBI;
use File::Temp qw/tempdir/;
# Verify the per-connection row identity cache documented in
# DBIx::QuickORM::Manual::Caching: one row object per primary key per
# connection, identity preserved across update, cache entry moved on PK
# change, uncached on delete, and sources without a primary key never cached.
#
# Each mutating subtest gets its own database file so subtest ordering and
# row mutations cannot bleed across tests.
BEGIN {
skip_all "DBD::SQLite is required for these tests"
unless eval { require DBD::SQLite; 1 };
}
require DBIx::QuickORM;
my $dir = tempdir(CLEANUP => 1);
my $seq = 0;
sub fresh_db {
my $file = "$dir/caching_" . ($seq++) . ".sqlite";
my $dsn = "dbi:SQLite:dbname=$file";
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE users (user_id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
$dbh->do('INSERT INTO users (user_id, name) VALUES (1, ?)', undef, 'bob');
$dbh->do('INSERT INTO users (user_id, name) VALUES (2, ?)', undef, 'alice');
# A table with no primary key cannot be deduplicated.
$dbh->do('CREATE TABLE logs (message TEXT NOT NULL)');
$dbh->do('INSERT INTO logs (message) VALUES (?)', undef, 'hello');
$dbh->do('INSERT INTO logs (message) VALUES (?)', undef, 'world');
$dbh->disconnect;
return $dsn;
}
sub connect_orm {
my $dsn = shift // fresh_db();
return DBIx::QuickORM->quick(credentials => {dsn => $dsn});
}
subtest default_manager_is_cached => sub {
my $con = connect_orm();
isa_ok($con->manager, ['DBIx::QuickORM::RowManager::Cached'], "default manager is Cached");
ok($con->manager->does_cache, "does_cache is true for the default manager");
ok($con->state_does_cache, "connection reports caching is on");
};
subtest identity_same_object => sub {
my $con = connect_orm();
my $a = $con->handle('users')->one(user_id => 1);
my $b = $con->handle('users')->one(user_id => 1);
ok($a, "fetched a row");
ref_is($a, $b, "fetching the same primary key twice returns the SAME object");
my $c = $con->handle('users')->one(user_id => 2);
ref_is_not($a, $c, "different primary keys are different objects");
};
subtest identity_preserved_across_update => sub {
my $con = connect_orm();
my $a = $con->handle('users')->one(user_id => 1);
$a->update(name => 'bobby');
my $b = $con->handle('users')->one(user_id => 1);
ref_is($a, $b, "row keeps identity after an update");
is($b->field('name'), 'bobby', "the updated value is visible through the cached object");
};
subtest cache_entry_moves_on_pk_change => sub {
my $con = connect_orm();
my $a = $con->handle('users')->one(user_id => 2);
ok($a, "fetched row with user_id 2");
$a->update(user_id => 200);
is($a->field('user_id'), 200, "primary key changed on the row");
my $by_new = $con->handle('users')->one(user_id => 200);
ref_is($a, $by_new, "cache entry moved to the new primary key");
my $by_old = $con->handle('users')->one(user_id => 2);
ok(!$by_old, "no row remains under the old primary key in the database");
# The stale key should not resolve to the moved object via the cache either.
my $cached_old = $con->state_cache_lookup('users', {user_id => 2});
ok(!$cached_old, "old primary key no longer resolves in the cache");
my $cached_new = $con->state_cache_lookup('users', {user_id => 200});
ref_is($cached_new, $a, "new primary key resolves to the row in the cache");
};
subtest delete_uncaches => sub {
my $con = connect_orm();
my $a = $con->handle('users')->one(user_id => 1);
( run in 0.566 second using v1.01-cache-2.11-cpan-5b529ec07f3 )