Database-Join

 view release on metacpan or  search on metacpan

t/integration.t  view on Meta::CPAN

	my $j = Database::Join->new(
		databases => [$cust, $score], join_column => $JC, join_type => 'left',
		filters   => { 1 => { score => { '>' => 60 } } },
	);
	is($j->count(), 2,
		'filter on secondary DB excludes Carol (score=55 fails score>60)');
};

subtest 'filter: two operator hashrefs on same column combine with AND semantics' => sub {
	plan tests => 1;
	# Base filter: score > 60.  Query: score < 80.  AND: 60 < score < 80.
	# Bob (70) qualifies; Alice (95) fails < 80; Carol (55) fails the base.
	my $j = Database::Join->new(
		databases => [$cust, $score], join_column => $JC, join_type => 'left',
		filters   => { 1 => { score => { '>' => 60 } } },
	);
	my $rows = $j->selectall_arrayref(score => { '<' => 80 });
	is(scalar @{$rows}, 1,
		'AND-merged operator hashrefs: only Bob (60 < 70 < 80) survives both constraints');
};

subtest 'filter: scalar query criterion replaces base operator filter for that column' => sub {
	plan tests => 1;
	# Base filter: score > 80 (excludes Bob=70, Carol=55).
	# Query: score = 70 (plain scalar).  Scalar wins, so Bob IS returned.
	my $j = Database::Join->new(
		databases => [$cust, $score], join_column => $JC, join_type => 'left',
		filters   => { 1 => { score => { '>' => 80 } } },
	);
	my $rows = $j->selectall_arrayref(score => 70);
	is(scalar @{$rows}, 1,
		'scalar query criterion replaces base filter operator (Bob score=70 returned)');
};

subtest 'filter: add_database filter option is equivalent to constructor filters' => sub {
	plan tests => 1;
	my $via_ctor = Database::Join->new(
		databases => [$cust, $score], join_column => $JC,
		filters   => { 1 => { score => { '>' => 60 } } },
	);
	my $via_add = Database::Join->new(databases => [$cust], join_column => $JC);
	$via_add->add_database($score, filter => { score => { '>' => 60 } });
	is($via_add->count(), $via_ctor->count(),
		'add_database filter option produces the same row count as constructor filters');
};

subtest 'filter: primary-database filter constrains the primary key set' => sub {
	plan tests => 1;
	# Filtering DB 0 (intcust) to tier=gold limits the key set to Alice and Carol.
	my $j = Database::Join->new(
		databases => [$cust, $score], join_column => $JC, join_type => 'left',
		filters   => { 0 => { tier => 'gold' } },
	);
	is($j->count(), $GOLD_COUNT,
		'primary-DB filter restricts key set to gold-tier customers only');
};

diag('section 5 done') if $ENV{TEST_VERBOSE};

# ===========================================================================
# SECTION 6 -- Column removal cascade (5 subtests)
#
# remove_column must propagate to columns(), schema(), result rows, and the
# routing table.  Criteria targeting a removed column are silently carp()ed
# and dropped.  The join_column itself cannot be removed.
# ===========================================================================

subtest 'remove_column: column absent from columns(), schema(), and query results' => sub {
	plan tests => 3;
	my $j = Database::Join->new(databases => [$cust, $score], join_column => $JC);
	$j->remove_column('email');
	ok(!grep({ $_ eq 'email' } @{ $j->columns() }),
		'email absent from columns() after remove_column');
	ok(!exists $j->schema()->{email},
		'email absent from schema() after remove_column');
	my $rows = $j->selectall_arrayref();
	ok(!exists $rows->[0]{email},
		'email absent from result row after remove_column');
};

subtest 'remove_column: criterion on removed column dropped with carp warning' => sub {
	plan tests => 2;
	my $j = Database::Join->new(databases => [$cust, $score], join_column => $JC);
	$j->remove_column('email');
	my @warnings;
	local $SIG{__WARN__} = sub { push @warnings, @_ };
	my $rows = $j->selectall_arrayref(email => 'alice@example.com');
	is(scalar @{$rows}, $ALL_CUST,
		'all rows returned when criterion targets a removed column');
	ok(@warnings,
		'carp warning emitted when criterion targets a removed column');
};

subtest 'remove_column: cannot remove the join_column' => sub {
	plan tests => 1;
	my $j = Database::Join->new(databases => [$cust, $score], join_column => $JC);
	throws_ok { $j->remove_column($JC) }
		qr/Cannot remove join_column/,
		'remove_column() croaks when asked to remove the join key';
};

subtest 'remove_column: chaining removes multiple columns in one expression' => sub {
	plan tests => 2;
	my $j = Database::Join->new(databases => [$cust, $score], join_column => $JC);
	$j->remove_column('email')->remove_column('age_days');
	ok(!grep({ $_ eq 'email'    } @{ $j->columns() }), 'email removed by chaining');
	ok(!grep({ $_ eq 'age_days' } @{ $j->columns() }), 'age_days removed by chaining');
};

subtest 'remove_column: idempotent and safe for non-existent column names' => sub {
	plan tests => 2;
	my $j = Database::Join->new(databases => [$cust, $score], join_column => $JC);
	lives_ok { $j->remove_column('email'); $j->remove_column('email') }
		'removing the same column twice does not croak';
	lives_ok { $j->remove_column('no_such_column') }
		'removing a non-existent column does not croak';
};

diag('section 6 done') if $ENV{TEST_VERBOSE};

# ===========================================================================



( run in 0.582 second using v1.01-cache-2.11-cpan-e7c6538aa59 )