Skip to content

PdoCassetteStore

A PDO-backed ListableCassetteStoreInterface: a pod’s filesystem does not survive a restart/eviction, so a team without an object-store backend keeps cassettes in the database it already has instead.

Portable across PostgreSQL and SQLite only (INSERT ... ON CONFLICT, matching PdoRateLimiterStorage’s and queue-db’s own documented scope for this class of hand-rolled SQL) — MySQL/MariaDB support would need ON DUPLICATE KEY UPDATE instead and is not implemented. The gzip-encoded cassette payload CassetteCodec produces is not valid UTF-8, so it is base64-encoded into a plain TEXT column rather than a driver-specific BYTEA/BLOB type — the same portability trick PdoRateLimiterStorage::save() already uses for its own binary-ish payload, needed because a single CREATE TABLE string cannot name a binary column type both engines accept.

recorded_at/route/status/trigger_reason are extracted from the cassette at write time into their own indexed-by-nothing-yet columns — not because a query here uses them (slugs() still returns every id, and cassette:list/cassette:prune decode-and-filter in PHP exactly as they do against FileCassetteStore, so both stores share one filtering implementation) but so the raw table is legible and directly queryable by hand (SELECT * FROM quiote_cassettes WHERE status >= 500) without decoding a payload column first.

Schema (see PdoCassetteStore::schema()): CREATE TABLE quiote_cassettes ( slug VARCHAR(64) PRIMARY KEY, raw_id VARCHAR(255) NOT NULL, recorded_at VARCHAR(32) NULL, route VARCHAR(255) NULL, status INTEGER NULL, trigger_reason VARCHAR(32) NULL, payload TEXT NOT NULL );

final readonly class PdoCassetteStore implements ListableCassetteStoreInterface

ImplementsListableCassetteStoreInterface
SourcePdoCassetteStore.php

public function __construct(PDO $pdo, string $table = 'quiote_cassettes', CassetteCodec $codec = new CassetteCodec(…)): mixed

ParameterTypeDescription
$pdoPDO
$tablestring
$codecCassetteCodec

Returns mixed

MethodDescription
delete(CassetteId $id): voidRemoves the cassette at $id.
get(CassetteId $id): ?CassetteNull when no cassette is stored under this id.
has(CassetteId $id): bool
put(CassetteId $id, Cassette $cassette): void
schema(string $table = 'quiote_cassettes'): stringDDL to create the backing table (PostgreSQL / SQLite compatible).
slugs(): list<string>Every cassette slug in the table.

public function delete(CassetteId $id): void

Removes the cassette at $id.

Best-effort: an id that does not exist is not an error.

ParameterTypeDescription
$idCassetteId
ThrowsWhen
StorageExceptionif the delete does not succeed.

public function get(CassetteId $id): ?Cassette

Null when no cassette is stored under this id.

ParameterTypeDescription
$idCassetteId

Returns ?Cassette

ThrowsWhen
StorageExceptionif the read does not succeed.

public function has(CassetteId $id): bool

ParameterTypeDescription
$idCassetteId

Returns bool

ThrowsWhen
StorageExceptionif the read does not succeed.

public function put(CassetteId $id, Cassette $cassette): void

ParameterTypeDescription
$idCassetteId
$cassetteCassette
ThrowsWhen
StorageExceptionif the write does not succeed.

public static function schema(string $table = 'quiote_cassettes'): string

DDL to create the backing table (PostgreSQL / SQLite compatible).

ParameterTypeDescription
$tablestring

Returns string

public function slugs(): list<string>

Every cassette slug in the table.

A failed query raises rather than returning an empty list. Reporting an error as “the store * is empty” is the worst available answer for the two callers this has: cassette:list would print “No cassettes found” for a table it could not read, and cassette:prune would decide there was nothing to prune.

Returns list``<``string``>

ThrowsWhen
StorageExceptionif the listing does not succeed.