Database-Abstraction

 view release on metacpan or  search on metacpan

t/transaction.t  view on Meta::CPAN

	# Force SQL path with max_slurp_size=>0 so cache is actually consulted.
	my $db_sql = Database::test1->new(
		directory      => $DATA_DIR,
		cache          => $cache,
		cache_duration => '1 hour',
		max_slurp_size => 0,
	);

	# T4-2: first selectall_arrayref() is a MISS and populates one cache entry
	my $fresh = $db_sql->selectall_arrayref();
	cmp_ok(scalar $cache->get_keys(), '==', 1,
	    'T4-2: after first selectall_arrayref(), cache has 1 key (MISS → SET)');

	# T4-3: second identical query is a HIT — cache key count unchanged
	$db_sql->selectall_arrayref();
	cmp_ok(scalar $cache->get_keys(), '==', 1,
	    'T4-3: second identical query is a cache HIT (key count unchanged)');

	# T4-4: a parameterised selectall_arrayref produces a second cache key
	# (count() reads but never writes the cache, so we use selectall_arrayref)
	$db_sql->selectall_arrayref(entry => $ENTRY_ONE);
	cmp_ok(scalar $cache->get_keys(), '>=', 2,
	    'T4-4: parameterised selectall_arrayref produces a new cache key (MISS → SET)');

	# T4-5: cached result is structurally identical to a repeat fresh call result
	my $cached = $db_sql->selectall_arrayref();
	is_deeply($fresh, $cached,
	    'T4-5: cache HIT returns data deeply equal to the original MISS result');

	# T4-6: a second object sharing the same cache gets a HIT for a key the first populated
	my $db_sql2 = Database::test1->new(
		directory      => $DATA_DIR,
		cache          => $cache,
		cache_duration => '1 hour',
		max_slurp_size => 0,
	);
	my $pre_keys = scalar $cache->get_keys();
	$db_sql2->selectall_arrayref();
	cmp_ok(scalar $cache->get_keys(), '==', $pre_keys,
	    'T4-6: second object sharing cache gets HIT from first object\'s entry (no new key added)');
}

# ---------------------------------------------------------------------------
# Section 5: Gzip resource lifecycle — temp file born, used, and unlinked
# ---------------------------------------------------------------------------
note('Section 5: gzip temp file resource lifecycle');

{
	# Build a gzip CSV in a temp directory.
	# test1 uses '!' as sep_char and has an 'entry' key column.
	my $tmpdir = File::Temp->newdir(CLEANUP => 1);
	my $csv_plain = "entry!number\n\"one\"!1\n\"two\"!2\n\"three\"!3\n";
	my $gz_path   = File::Spec->catfile("$tmpdir", 'test1.csv.gz');
	gzip \$csv_plain => $gz_path or die "gzip failed: $GzipError";

	# T5-1: gzip CSV opens and returns the correct row count
	my $db_gz = Database::test1->new("$tmpdir");
	cmp_ok($db_gz->count(), '==', 3, 'T5-1: gzip CSV opens and count() == 3');

	# T5-2: during lifetime, _temp_fh holds a File::Temp object (decompressed copy)
	ok(defined $db_gz->{'_temp_fh'}, 'T5-2: _temp_fh is set while gzip object is alive');

	# T5-3: the temp file actually exists on disk during object lifetime
	my $tmpfile_path = $db_gz->{'_temp_fh'}->filename();
	ok(-e $tmpfile_path, 'T5-3: decompressed temp file exists on disk during object lifetime');

	# T5-4: multiple queries use the same temp file (no re-extraction between calls)
	my $path_after_q2 = do { $db_gz->selectall_arrayref(); $db_gz->{'_temp_fh'}->filename() };
	is($path_after_q2, $tmpfile_path,
	    'T5-4: same temp file path after second query (no re-extraction)');

	# T5-5: after DESTROY, _temp_fh is cleared (File::Temp auto-unlinks it)
	$db_gz->DESTROY();
	ok(!defined $db_gz->{'_temp_fh'},
	    'T5-5: _temp_fh cleared after DESTROY (temp file auto-unlinked)');
}

# ---------------------------------------------------------------------------
# Section 6: Query-builder chain idempotency
# ---------------------------------------------------------------------------
note('Section 6: query-builder chain idempotency');

{
	my $db = Database::test1->new($DATA_DIR);

	# T6-1: where→limit→all delivers the expected filtered, limited result
	my $r1 = $db->query()
	            ->where(entry => $ENTRY_ONE)
	            ->limit(5)
	            ->all();
	ok(ref $r1 eq 'ARRAY' && scalar @{$r1} == 1 && $r1->[0]{'entry'} eq $ENTRY_ONE,
	    'T6-1: where(entry=one)->limit(5)->all() returns exactly 1 matching row');

	# T6-2: executing the identical chain a second time returns a deeply equal result
	my $r2 = $db->query()
	            ->where(entry => $ENTRY_ONE)
	            ->limit(5)
	            ->all();
	is_deeply($r1, $r2, 'T6-2: identical builder chain executed twice gives deeply equal results');

	# T6-3: query-builder count() is consistent with direct count() for same params
	my $qb_count     = $db->query()->where(entry => $ENTRY_TWO)->count();
	my $direct_count = $db->count(entry => $ENTRY_TWO);
	cmp_ok($qb_count, '==', $direct_count,
	    'T6-3: query-builder count() == direct count() for identical criteria');

	# T6-4: two independent chains on the same object return independent results
	my $chain_a = $db->query()->where(entry => $ENTRY_ONE)->all();
	my $chain_b = $db->query()->where(entry => $ENTRY_TWO)->all();
	isnt($chain_a->[0]{'entry'}, $chain_b->[0]{'entry'},
	    'T6-4: two independent builder chains return distinct result sets');
}



( run in 1.061 second using v1.01-cache-2.11-cpan-14f38c9f855 )