isolation = $isolation; break; default: throw new \Error("Isolation must be a valid transaction isolation level"); } $this->executor = $executor; } /** * @return bool */ public function isActive(): bool { return $this->executor !== null; } /** * @return int */ public function getIsolationLevel(): int { return $this->isolation; } /** * {@inheritdoc} */ public function query(string $sql): Promise { if ($this->executor === null) { throw new TransactionError("The transaction has been committed or rolled back"); } return $this->executor->query($sql); } /** * {@inheritdoc} */ public function prepare(string $sql): Promise { if ($this->executor === null) { throw new TransactionError("The transaction has been committed or rolled back"); } return $this->executor->prepare($sql); } /** * {@inheritdoc} */ public function execute(string $sql, ...$params): Promise { if ($this->executor === null) { throw new TransactionError("The transaction has been committed or rolled back"); } return $this->executor->execute($sql, ...$params); } /** * {@inheritdoc} */ public function notify(string $channel, string $payload = ""): Promise { if ($this->executor === null) { throw new TransactionError("The transaction has been committed or rolled back"); } return $this->executor->notify($channel, $payload); } /** * Commits the transaction and makes it inactive. * * @return \Amp\Promise<\Amp\Postgres\CommandResult> * * @throws \Amp\Postgres\TransactionError */ public function commit(): Promise { return new Coroutine($this->doCommit()); } private function doCommit(): \Generator { if ($this->executor === null) { throw new TransactionError("The transaction has been committed or rolled back"); } $executor = $this->executor; $this->executor = null; try { $result = yield $executor->query("COMMIT"); } finally { $this->complete(); } return $result; } /** * Rolls back the transaction and makes it inactive. * * @return \Amp\Promise<\Amp\Postgres\CommandResult> * * @throws \Amp\Postgres\TransactionError */ public function rollback(): Promise { return new Coroutine($this->doRollback()); } public function doRollback(): \Generator { if ($this->executor === null) { throw new TransactionError("The transaction has been committed or rolled back"); } $executor = $this->executor; $this->executor = null; try { $result = yield $executor->query("ROLLBACK"); } finally { $this->complete(); } return $result; } /** * Creates a savepoint with the given identifier. WARNING: Identifier is not sanitized, do not pass untrusted data. * * @param string $identifier Savepoint identifier. * * @return \Amp\Promise<\Amp\Postgres\CommandResult> * * @throws \Amp\Postgres\TransactionError */ public function savepoint(string $identifier): Promise { return $this->query("SAVEPOINT " . $identifier); } /** * Rolls back to the savepoint with the given identifier. WARNING: Identifier is not sanitized, do not pass * untrusted data. * * @param string $identifier Savepoint identifier. * * @return \Amp\Promise<\Amp\Postgres\CommandResult> * * @throws \Amp\Postgres\TransactionError */ public function rollbackTo(string $identifier): Promise { return $this->query("ROLLBACK TO " . $identifier); } /** * Releases the savepoint with the given identifier. WARNING: Identifier is not sanitized, do not pass untrusted * data. * * @param string $identifier Savepoint identifier. * * @return \Amp\Promise<\Amp\Postgres\CommandResult> * * @throws \Amp\Postgres\TransactionError */ public function release(string $identifier): Promise { return $this->query("RELEASE SAVEPOINT " . $identifier); } }