Skip to content

Commit d8e66a1

Browse files
committed
test: cover batch operation review cases
- document that explicit batches and deferred writes can be combined - skip database persistence when there are no prepared rows - add cross-class and empty-input coverage for batch operations Signed-off-by: memleakd <121398829+memleakd@users.noreply.github.com>
1 parent 00a41fb commit d8e66a1

5 files changed

Lines changed: 201 additions & 2 deletions

File tree

docs/configuration.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ Handlers like `database` and `file` support deferred writes. When `deferWrites`
3232
are batched and persisted efficiently at the end of the request during the `post_system` event. This minimizes the number of
3333
database queries or file I/O operations, improving performance for write-heavy operations.
3434

35-
This is separate from the explicit `setMany()` and `forgetMany()` APIs. Batch APIs allow callers to group multiple settings in
36-
one method call, while deferred writes decide whether writes are persisted immediately or at the end of the request.
35+
!!! note
36+
This is separate from the explicit `setMany()` and `forgetMany()` APIs. Batch APIs allow callers to group multiple settings
37+
in one method call, while deferred writes decide whether writes are persisted immediately or at the end of the request.
38+
The two features are independent and can be combined.
3739

3840
### Multiple handlers
3941

src/Handlers/DatabaseHandler.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,10 @@ private function prepareDeleteRows(array $settings, ?string $context): array
386386
*/
387387
private function persistRows(array $upserts, array $deletes): void
388388
{
389+
if ($upserts === [] && $deletes === []) {
390+
return;
391+
}
392+
389393
$this->db->transStart();
390394

391395
// Handle upserts: fetch existing records matching our pending data

tests/DatabaseHandlerTest.php

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,25 @@ public function testSetManyWithContext(): void
355355
$this->assertSame('ContextName', $this->settings->get('Example.siteName', 'environment:test'));
356356
}
357357

358+
public function testSetManyStoresDifferentClasses(): void
359+
{
360+
$this->settings->setMany([
361+
'Example.siteName' => 'BatchName',
362+
'Nada.siteName' => 'NadaName',
363+
]);
364+
365+
$this->seeInDatabase($this->table, [
366+
'class' => 'Tests\Support\Config\Example',
367+
'key' => 'siteName',
368+
'value' => 'BatchName',
369+
]);
370+
$this->seeInDatabase($this->table, [
371+
'class' => 'Nada',
372+
'key' => 'siteName',
373+
'value' => 'NadaName',
374+
]);
375+
}
376+
358377
public function testForgetManyDeletesRows(): void
359378
{
360379
$this->settings->setMany([
@@ -383,6 +402,28 @@ public function testForgetManyDeletesRows(): void
383402
]);
384403
}
385404

405+
public function testForgetManyDeletesDifferentClasses(): void
406+
{
407+
$this->settings->setMany([
408+
'Example.siteName' => 'BatchName',
409+
'Nada.siteName' => 'NadaName',
410+
]);
411+
412+
$this->settings->forgetMany([
413+
'Example.siteName',
414+
'Nada.siteName',
415+
]);
416+
417+
$this->dontSeeInDatabase($this->table, [
418+
'class' => 'Tests\Support\Config\Example',
419+
'key' => 'siteName',
420+
]);
421+
$this->dontSeeInDatabase($this->table, [
422+
'class' => 'Nada',
423+
'key' => 'siteName',
424+
]);
425+
}
426+
386427
/**
387428
* @see https://github.com/codeigniter4/settings/issues/20
388429
*/
@@ -449,6 +490,38 @@ public function testDeferredSetManyPersistsAfterPersist(): void
449490
]);
450491
}
451492

493+
public function testDeferredSetManyPersistsDifferentClassesAfterPersist(): void
494+
{
495+
$deferredSettings = $this->createDeferredSettings();
496+
497+
$deferredSettings->setMany([
498+
'Example.siteName' => 'DeferredName',
499+
'Nada.siteName' => 'DeferredNada',
500+
]);
501+
502+
$this->dontSeeInDatabase($this->table, [
503+
'class' => 'Tests\Support\Config\Example',
504+
'key' => 'siteName',
505+
]);
506+
$this->dontSeeInDatabase($this->table, [
507+
'class' => 'Nada',
508+
'key' => 'siteName',
509+
]);
510+
511+
$this->persistDeferredWrites($deferredSettings);
512+
513+
$this->seeInDatabase($this->table, [
514+
'class' => 'Tests\Support\Config\Example',
515+
'key' => 'siteName',
516+
'value' => 'DeferredName',
517+
]);
518+
$this->seeInDatabase($this->table, [
519+
'class' => 'Nada',
520+
'key' => 'siteName',
521+
'value' => 'DeferredNada',
522+
]);
523+
}
524+
452525
public function testDeferredForgetManyDeletesAfterPersist(): void
453526
{
454527
$this->settings->setMany([
@@ -484,6 +557,41 @@ public function testDeferredForgetManyDeletesAfterPersist(): void
484557
]);
485558
}
486559

560+
public function testDeferredForgetManyDeletesDifferentClassesAfterPersist(): void
561+
{
562+
$this->settings->setMany([
563+
'Example.siteName' => 'BatchName',
564+
'Nada.siteName' => 'NadaName',
565+
]);
566+
567+
$deferredSettings = $this->createDeferredSettings();
568+
569+
$deferredSettings->forgetMany([
570+
'Example.siteName',
571+
'Nada.siteName',
572+
]);
573+
574+
$this->seeInDatabase($this->table, [
575+
'class' => 'Tests\Support\Config\Example',
576+
'key' => 'siteName',
577+
]);
578+
$this->seeInDatabase($this->table, [
579+
'class' => 'Nada',
580+
'key' => 'siteName',
581+
]);
582+
583+
$this->persistDeferredWrites($deferredSettings);
584+
585+
$this->dontSeeInDatabase($this->table, [
586+
'class' => 'Tests\Support\Config\Example',
587+
'key' => 'siteName',
588+
]);
589+
$this->dontSeeInDatabase($this->table, [
590+
'class' => 'Nada',
591+
'key' => 'siteName',
592+
]);
593+
}
594+
487595
public function testDeferredWritesReducesDatabaseQueries(): void
488596
{
489597
// Create new settings instance with deferred writes enabled

tests/FileHandlerTest.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ private function createDeferredSettings(): Settings
6868
return new Settings($config);
6969
}
7070

71+
/**
72+
* Creates a new Settings instance for reading persisted file values.
73+
*/
74+
private function createSettings(): Settings
75+
{
76+
/** @var ConfigSettings $config */
77+
$config = config('Settings');
78+
$config->handlers = ['file'];
79+
$config->file['path'] = $this->path;
80+
$config->file['deferWrites'] = false;
81+
82+
return new Settings($config);
83+
}
84+
7185
/**
7286
* Manually triggers deferred writes for a Settings instance.
7387
*/
@@ -346,6 +360,22 @@ public function testForgetManyRemovesMultipleProperties(): void
346360
$this->assertSame('BatchTitle', $this->settings->get('Example.siteTitle'));
347361
}
348362

363+
public function testForgetManyRemovesDifferentClasses(): void
364+
{
365+
$this->settings->setMany([
366+
'Example.siteName' => 'BatchName',
367+
'Nada.siteName' => 'NadaName',
368+
]);
369+
370+
$this->settings->forgetMany([
371+
'Example.siteName',
372+
'Nada.siteName',
373+
]);
374+
375+
$this->assertSame('Settings Test', $this->settings->get('Example.siteName'));
376+
$this->assertNull($this->settings->get('Nada.siteName'));
377+
}
378+
349379
public function testDifferentClassesCreateDifferentFiles(): void
350380
{
351381
$this->settings->set('Example.siteName', 'Foo');
@@ -652,6 +682,26 @@ public function testDeferredSetManyPersistsAfterPersist(): void
652682
$this->assertSame('deferred@example.com', $data['siteEmail']['value']);
653683
}
654684

685+
public function testDeferredSetManyPersistsDifferentClassesAfterPersist(): void
686+
{
687+
$deferredSettings = $this->createDeferredSettings();
688+
689+
$deferredSettings->setMany([
690+
'Example.siteName' => 'DeferredName',
691+
'Nada.siteName' => 'DeferredNada',
692+
]);
693+
694+
$files = glob($this->path . '*.php', GLOB_NOSORT);
695+
$this->assertEmpty($files);
696+
697+
$this->persistDeferredWrites($deferredSettings);
698+
699+
$settings = $this->createSettings();
700+
701+
$this->assertSame('DeferredName', $settings->get('Example.siteName'));
702+
$this->assertSame('DeferredNada', $settings->get('Nada.siteName'));
703+
}
704+
655705
public function testDeferredForgetManyDeletesAfterPersist(): void
656706
{
657707
$this->settings->setMany([
@@ -679,4 +729,29 @@ public function testDeferredForgetManyDeletesAfterPersist(): void
679729
$this->assertArrayNotHasKey('siteName', $data);
680730
$this->assertArrayNotHasKey('siteEmail', $data);
681731
}
732+
733+
public function testDeferredForgetManyDeletesDifferentClassesAfterPersist(): void
734+
{
735+
$this->settings->setMany([
736+
'Example.siteName' => 'BatchName',
737+
'Nada.siteName' => 'NadaName',
738+
]);
739+
740+
$deferredSettings = $this->createDeferredSettings();
741+
742+
$deferredSettings->forgetMany([
743+
'Example.siteName',
744+
'Nada.siteName',
745+
]);
746+
747+
$this->assertSame('BatchName', $this->settings->get('Example.siteName'));
748+
$this->assertSame('NadaName', $this->settings->get('Nada.siteName'));
749+
750+
$this->persistDeferredWrites($deferredSettings);
751+
752+
$settings = $this->createSettings();
753+
754+
$this->assertSame('Settings Test', $settings->get('Example.siteName'));
755+
$this->assertNull($settings->get('Nada.siteName'));
756+
}
682757
}

tests/SettingsTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ public function testSetManyUsesLastNormalizedKey(): void
9090
$this->assertSame('FullName', $this->settings->get('Example.siteName'));
9191
}
9292

93+
public function testBatchMethodsAcceptEmptyArrays(): void
94+
{
95+
$this->settings->set('Example.siteName', 'ExistingName');
96+
97+
$this->settings->setMany([]);
98+
$this->settings->forgetMany([]);
99+
100+
$this->assertSame('ExistingName', $this->settings->get('Example.siteName'));
101+
}
102+
93103
public function testGetWithoutContextUsesGlobal(): void
94104
{
95105
$this->settings->set('Example.siteName', 'NoContext');

0 commit comments

Comments
 (0)