> */ public function select(string $sql, array $params = []): array; /** @return array|null */ public function selectOne(string $sql, array $params = []): ?array; /** Executes a write and returns the number of affected rows. */ public function execute(string $sql, array $params = []): int; /** Inserts a row and returns the new auto-increment ID. */ public function insert(string $table, array $row): int; /** * Inserts the row unless a row with the same values in $keyColumns (a unique key of the table) already exists, and says which * happened: true = inserted, false = that unique key was taken. Only that conflict is absorbed (no error is raised, so nothing is * logged for an expected race); every other failure (other constraints, missing table, connection) still throws. * * @param array $row * @param list $keyColumns */ public function insertIfAbsent(string $table, array $row, array $keyColumns): bool; /** * Runs $fn inside a transaction. Rolls back and rethrows on any throwable. * * @template T * @param callable(): T $fn * @return T */ public function transaction(callable $fn): mixed; public function table(string $name): string; /** 'sqlite' or 'mysql'. */ public function driver(): string; /** True when the last failed write was a unique-key violation. */ public function isUniqueViolation(\Throwable $e): bool; }