Database-Join

 view release on metacpan or  search on metacpan

t/sqlite-backend.t  view on Meta::CPAN

	}
	sub selectall_arrayref {
		my ($self, @args) = @_;
		$self->{_call_count}++;
		return $self->SUPER::selectall_arrayref(@args);
	}
	sub call_count { return $_[0]->{_call_count} }
	1;
}

subtest 'cache reuse: source DA selectall_arrayref called once, not per query' => sub {
	my $da_a = CountingDA->new(
		cols => [qw(id name)],
		rows => [
			{ id => 'k1', name => 'Alice' },
			{ id => 'k2', name => 'Bob' },
		],
	);
	my $da_b = CountingDA->new(
		cols => [qw(id score)],
		rows => [
			{ id => 'k1', score => 95 },
			{ id => 'k2', score => 72 },
		],
	);

	my $join = Database::Join->new(
		databases   => [$da_a, $da_b],
		join_column => $JOIN_COL,
		backend     => 'sqlite',
	);

	my $r1 = $join->selectall_arrayref();      # first call: builds cache
	my $r2 = $join->selectall_arrayref();      # second: reuses cache
	my $r3 = $join->selectall_arrayref();      # third: reuses cache

	is $da_a->call_count, 1,
		'primary DA: selectall_arrayref called once (cache build only)';
	is $da_b->call_count, 1,
		'secondary DA: selectall_arrayref called once (cache build only)';
	is scalar @{$r1}, 2, 'first query returns 2 rows';
	is scalar @{$r2}, 2, 'second query returns 2 rows (cache reused)';
	is scalar @{$r3}, 2, 'third query returns 2 rows (cache reused)';
};

# ===========================================================================
# S17: Cache invalidation — rebuilt when any source updated() changes
# The cache tracks updated() timestamps; a changed timestamp forces a full
# rebuild so queries see the new source data.
# ===========================================================================

{
	package UpdatableDA;
	use parent -norequire, 'CountingDA';
	sub new {
		my ($class, %args) = @_;
		my $self = $class->SUPER::new(%args);
		$self->{_ts} = $args{ts} // 1000;
		return $self;
	}
	sub updated    { return $_[0]->{_ts} }
	sub set_updated { $_[0]->{_ts} = $_[1] }
	sub set_rows    { $_[0]->{_rows} = $_[1] }
	1;
}

subtest 'cache invalidation: cache rebuilt when source updated() timestamp changes' => sub {
	my $da_a = UpdatableDA->new(
		cols => [qw(id name)],
		rows => [{ id => 'k1', name => 'Alice' }],
		ts   => 1000,
	);
	my $da_b = UpdatableDA->new(
		cols => [qw(id score)],
		rows => [{ id => 'k1', score => 10 }],
		ts   => 2000,
	);

	my $join = Database::Join->new(
		databases   => [$da_a, $da_b],
		join_column => $JOIN_COL,
		backend     => 'sqlite',
	);

	my $r1 = $join->selectall_arrayref();
	is $r1->[0]{score}, 10, 'initial query: score=10';
	is $da_b->call_count, 1, 'secondary DA called once for initial build';

	# Simulate source update: change data and bump the timestamp.
	$da_b->set_rows([{ id => 'k1', score => 99 }]);
	$da_b->set_updated(2001);

	my $r2 = $join->selectall_arrayref();
	is $r2->[0]{score}, 99, 'after update: cache rebuilt, score=99';
	is $da_b->call_count, 2, 'secondary DA called again after timestamp change';
};

# ===========================================================================
# S18: ATTACH with query-time criteria
# The old implementation blocked ATTACH when criteria existed (!%criteria guard).
# The new implementation removes that restriction: ATTACH is unconditional, and
# query-time criteria become SQL WHERE clauses against the ATTACHed table.
# ===========================================================================

subtest 'ATTACH with criteria: zero-copy path used; WHERE filters correctly' => sub {
	require DBI;
	my $tmpdir = tempdir(CLEANUP => 1);
	my $dbfile = File::Spec->catfile($tmpdir, 'attach_crit.db');

	my $src_dbh = DBI->connect(
		"dbi:SQLite:dbname=$dbfile", '', '',
		{ RaiseError => 1, PrintError => 0, AutoCommit => 1 },
	);
	$src_dbh->do('CREATE TABLE scores (id TEXT, score INTEGER)');
	$src_dbh->do("INSERT INTO scores VALUES ('k1', 42)");
	$src_dbh->do("INSERT INTO scores VALUES ('k2', 10)");
	$src_dbh->do("INSERT INTO scores VALUES ('k3', 55)");

	my $da_src = MinimalDA->new(
		cols  => [qw(id score)],
		rows  => [



( run in 0.599 second using v1.01-cache-2.11-cpan-7da0f45c409 )