feat: add CachedService with cached collections and delta

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-10-07 22:02:45 -04:00
parent 4e12d41ee9
commit 852ead324f
10 changed files with 750 additions and 215 deletions
+83
View File
@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace KTXT\ProviderImap\Tests\Support;
use KTXM\ProviderImap\Providers\CollectionResource;
use KTXM\ProviderImap\Stores\MailboxStore;
/**
* In-memory MailboxStore: documents, state, change sequence and a single lock.
*/
final class FakeMailboxStore extends MailboxStore
{
/** @var array<string, array> */
public array $documents = [];
public ?string $lockOwner = null;
/** Fixed time for listedAt; null = now */
public ?int $clock = null;
public function upsert(string $tenantId, string $serviceId, CollectionResource $collection): void
{
$name = (string) $collection->identifier();
$this->documents[$name] = [
...($this->documents[$name] ?? self::STATE_DEFAULTS),
...$collection->toCacheMeta(),
'listedAt' => $this->clock ?? time(),
];
}
public function fetch(string $serviceId, string $name): ?array
{
return $this->documents[$name] ?? null;
}
public function list(string $serviceId): array
{
return $this->documents;
}
public function updateState(string $serviceId, string $name, array $state): void
{
$this->documents[$name] = array_replace($this->documents[$name], array_intersect_key($state, self::STATE_DEFAULTS));
}
public function acquireLock(string $serviceId, string $name, string $owner, int $ttl): bool
{
if ($this->lockOwner !== null && $this->lockOwner !== $owner) {
return false;
}
$this->lockOwner = $owner;
return true;
}
public function releaseLock(string $serviceId, string $name, string $owner): void
{
if ($this->lockOwner === $owner) {
$this->lockOwner = null;
}
}
public function reserveSequence(string $serviceId, string $name, int $count = 1): int
{
$this->documents[$name]['changeSeq'] += $count;
return $this->documents[$name]['changeSeq'] - $count + 1;
}
public function state(string $serviceId, string $name): array
{
return array_replace(self::STATE_DEFAULTS, array_intersect_key($this->documents[$name] ?? [], self::STATE_DEFAULTS));
}
public function listedAt(string $serviceId): ?int
{
$times = array_filter(array_column($this->documents, 'listedAt'));
return $times === [] ? null : max($times);
}
public function delete(string $serviceId, string $name): void
{
unset($this->documents[$name]);
}
}