diff --git a/src/Connection.php b/src/Connection.php index 9909c8ac..14f02c46 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -93,6 +93,7 @@ public function reconnectWithConfig(array $config): void } + #[\NoDiscard] public function getDriver(): IDriver { return $this->driver; @@ -100,6 +101,7 @@ public function getDriver(): IDriver /** @inheritdoc */ + #[\NoDiscard] public function getConfig(): array { return $this->config; @@ -144,6 +146,7 @@ public function queryByQueryBuilder(QueryBuilder $queryBuilder): Result /** @inheritdoc */ + #[\NoDiscard] public function getLastInsertedId(string|Fqn|null $sequenceName = null) { if (!$this->connected) { @@ -154,6 +157,7 @@ public function getLastInsertedId(string|Fqn|null $sequenceName = null) /** @inheritdoc */ + #[\NoDiscard] public function getAffectedRows(): int { if (!$this->connected) { @@ -164,6 +168,7 @@ public function getAffectedRows(): int /** @inheritdoc */ + #[\NoDiscard] public function getPlatform(): IPlatform { if ($this->platform === null) { @@ -175,6 +180,7 @@ public function getPlatform(): IPlatform /** @inheritdoc */ + #[\NoDiscard] public function createQueryBuilder(): QueryBuilder { return new QueryBuilder($this->getPlatform()); @@ -254,6 +260,7 @@ public function rollbackTransaction(): void /** @inheritdoc */ + #[\NoDiscard] public function getTransactionNestedIndex(): int { return $this->nestedTransactionIndex; diff --git a/src/IConnection.php b/src/IConnection.php index 144c4586..f9a47aea 100644 --- a/src/IConnection.php +++ b/src/IConnection.php @@ -50,6 +50,7 @@ public function reconnect(): void; public function reconnectWithConfig(array $config): void; + #[\NoDiscard] public function getDriver(): IDriver; @@ -57,6 +58,7 @@ public function getDriver(): IDriver; * Returns connection configuration. * @return array */ + #[\NoDiscard] public function getConfig(): array; @@ -103,18 +105,22 @@ public function queryByQueryBuilder(QueryBuilder $queryBuilder): Result; * * @return int|string|null */ + #[\NoDiscard] public function getLastInsertedId(string|Fqn|null $sequenceName = null); /** * Returns number of affected rows. */ + #[\NoDiscard] public function getAffectedRows(): int; + #[\NoDiscard] public function getPlatform(): IPlatform; + #[\NoDiscard] public function createQueryBuilder(): QueryBuilder; @@ -158,6 +164,7 @@ public function rollbackTransaction(): void; * 1 = basic transaction * >1 = nested transaction through save-points */ + #[\NoDiscard] public function getTransactionNestedIndex(): int; diff --git a/src/Platforms/Data/Fqn.php b/src/Platforms/Data/Fqn.php index 9a52b42d..f07de066 100644 --- a/src/Platforms/Data/Fqn.php +++ b/src/Platforms/Data/Fqn.php @@ -22,6 +22,7 @@ public function __construct( } + #[\NoDiscard] public function getUnescaped(): string { if ($this->schema === '') { diff --git a/src/Platforms/IPlatform.php b/src/Platforms/IPlatform.php index d2ec2fd3..a4309a6d 100644 --- a/src/Platforms/IPlatform.php +++ b/src/Platforms/IPlatform.php @@ -22,6 +22,7 @@ interface IPlatform /** * Returns platform name. */ + #[\NoDiscard] public function getName(): string; @@ -30,6 +31,7 @@ public function getName(): string; * If no schema is provided, it uses the current schema name (search path). * @return array */ + #[\NoDiscard] public function getTables(?string $schema = null): array; @@ -37,6 +39,7 @@ public function getTables(?string $schema = null): array; * Returns list of table columns metadata, indexed by column name. * @return array */ + #[\NoDiscard] public function getColumns(string $table, ?string $schema = null): array; @@ -44,6 +47,7 @@ public function getColumns(string $table, ?string $schema = null): array; * Returns list of table foreign keys, indexed by column name. * @return array */ + #[\NoDiscard] public function getForeignKeys(string $table, ?string $schema = null): array; @@ -51,12 +55,14 @@ public function getForeignKeys(string $table, ?string $schema = null): array; * Returns primary sequence name for the table. * If not supported nor present, returns a null. */ + #[\NoDiscard] public function getPrimarySequenceName(string $table, ?string $schema = null): ?string; /** * Formats string value to SQL string. */ + #[\NoDiscard] public function formatString(string $value): string; @@ -65,60 +71,70 @@ public function formatString(string $value): string; * @param int $mode -1 = left, 0 = both, 1 = right * @return mixed */ + #[\NoDiscard] public function formatStringLike(string $value, int $mode); /** * Formats Json value to SQL string. */ + #[\NoDiscard] public function formatJson(mixed $value): string; /** * Formats boolean to SQL string. */ + #[\NoDiscard] public function formatBool(bool $value): string; /** * Formats column or dot separated identifier to SQL string. */ + #[\NoDiscard] public function formatIdentifier(string $value): string; /** * Formats time-zone aware DateTimeInterface instance to SQL string. */ + #[\NoDiscard] public function formatDateTime(DateTimeInterface $value): string; /** * Formats local DateTimeInterface instance to SQL string. */ + #[\NoDiscard] public function formatLocalDateTime(DateTimeInterface $value): string; /** * Formats local date from DateTimeInterface instance to SQL string. */ + #[\NoDiscard] public function formatLocalDate(DateTimeInterface $value): string; /** * Formats DateInterval to SQL string. */ + #[\NoDiscard] public function formatDateInterval(DateInterval $value): string; /** * Formats blob value to SQL string. */ + #[\NoDiscard] public function formatBlob(string $value): string; /** * Formats LIMIT & OFFSET values to SQL string. */ + #[\NoDiscard] public function formatLimitOffset(?int $limit, ?int $offset): string; @@ -126,6 +142,7 @@ public function formatLimitOffset(?int $limit, ?int $offset): string; * Returns SQL file parser * !!!This function requires nextras/multi-query-parser dependency!!! */ + #[\NoDiscard] public function createMultiQueryParser(): IMultiQueryParser; diff --git a/src/Result/Result.php b/src/Result/Result.php index 000b645b..26a7eef5 100644 --- a/src/Result/Result.php +++ b/src/Result/Result.php @@ -59,6 +59,7 @@ public function unbuffered(): Result } + #[\NoDiscard] public function getAdapter(): IResultAdapter { return $this->adapter; @@ -111,6 +112,7 @@ private function normalize(array &$data): void /** * @return mixed|null */ + #[\NoDiscard] public function fetchField(int $column = 0) { if (($row = $this->fetch()) !== null) { // = intentionally @@ -124,6 +126,7 @@ public function fetchField(int $column = 0) /** * @return Row[] */ + #[\NoDiscard] public function fetchAll(): array { return iterator_to_array($this); @@ -133,6 +136,7 @@ public function fetchAll(): array /** * @return array */ + #[\NoDiscard] public function fetchPairs(?string $key = null, ?string $value = null): array { if ($key === null && $value === null) { @@ -164,6 +168,7 @@ public function fetchPairs(?string $key = null, ?string $value = null): array * Returns list of column names in result. * @return list */ + #[\NoDiscard] public function getColumns(): array { return array_map( diff --git a/src/Result/Row.php b/src/Result/Row.php index 7c1fc44a..44a2fba9 100644 --- a/src/Result/Row.php +++ b/src/Result/Row.php @@ -23,6 +23,7 @@ public function __construct(array $data) /** * @return array */ + #[\NoDiscard] public function toArray(): array { return (array) $this; @@ -36,6 +37,7 @@ public function __get(string $name): mixed } + #[\NoDiscard] public function getNthField(int $offset): mixed { $slice = array_slice((array) $this, $offset, 1); diff --git a/tests/cases/integration/connection.postgres.phpt b/tests/cases/integration/connection.postgres.phpt index 68c7ae8d..871ca37e 100644 --- a/tests/cases/integration/connection.postgres.phpt +++ b/tests/cases/integration/connection.postgres.phpt @@ -38,7 +38,7 @@ class ConnectionPostgresTest extends IntegrationTestCase Assert::same(2, $this->connection->getLastInsertedId(new Fqn(schema: 'public', name: 'publishers_id_seq'))); Assert::exception(function() { - $this->connection->getLastInsertedId(); + $_ = $this->connection->getLastInsertedId(); }, InvalidArgumentException::class, 'PgsqlDriver requires passing a sequence name for getLastInsertedId() method.'); } diff --git a/tests/cases/integration/result.buffering.phpt b/tests/cases/integration/result.buffering.phpt index 21ae2323..15c54257 100644 --- a/tests/cases/integration/result.buffering.phpt +++ b/tests/cases/integration/result.buffering.phpt @@ -36,7 +36,7 @@ class ResultBufferingIntegrationTest extends IntegrationTestCase $unbuffered = $this->connection->query('SELECT * FROM books ORDER BY id')->buffered()->unbuffered(); Assert::same([1, 2, 3, 4], $unbuffered->fetchPairs(null, 'id')); Assert::throws(function () use ($unbuffered): void { - $unbuffered->fetchPairs(null, 'id'); + $_ = $unbuffered->fetchPairs(null, 'id'); }, NotSupportedException::class); $lateChanged = $this->connection->query('SELECT * FROM books ORDER BY id')->buffered(); diff --git a/tests/cases/unit/NoDiscardAttributeTest.php b/tests/cases/unit/NoDiscardAttributeTest.php new file mode 100644 index 00000000..a92626f4 --- /dev/null +++ b/tests/cases/unit/NoDiscardAttributeTest.php @@ -0,0 +1,97 @@ +assertMethodHasNoDiscard(IConnection::class, 'getDriver'); + $this->assertMethodHasNoDiscard(IConnection::class, 'getConfig'); + $this->assertMethodHasNoDiscard(IConnection::class, 'getLastInsertedId'); + $this->assertMethodHasNoDiscard(IConnection::class, 'getAffectedRows'); + $this->assertMethodHasNoDiscard(IConnection::class, 'getPlatform'); + $this->assertMethodHasNoDiscard(IConnection::class, 'createQueryBuilder'); + $this->assertMethodHasNoDiscard(IConnection::class, 'getTransactionNestedIndex'); + } + + + public function testConnectionMethodsHaveNoDiscard(): void + { + $this->assertMethodHasNoDiscard(Connection::class, 'getDriver'); + $this->assertMethodHasNoDiscard(Connection::class, 'getConfig'); + $this->assertMethodHasNoDiscard(Connection::class, 'getLastInsertedId'); + $this->assertMethodHasNoDiscard(Connection::class, 'getAffectedRows'); + $this->assertMethodHasNoDiscard(Connection::class, 'getPlatform'); + $this->assertMethodHasNoDiscard(Connection::class, 'createQueryBuilder'); + $this->assertMethodHasNoDiscard(Connection::class, 'getTransactionNestedIndex'); + } + + + public function testPlatformInterfaceMethodsHaveNoDiscard(): void + { + $this->assertMethodHasNoDiscard(IPlatform::class, 'getName'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'getTables'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'getColumns'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'getForeignKeys'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'getPrimarySequenceName'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatString'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatStringLike'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatJson'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatBool'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatIdentifier'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatDateTime'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatLocalDateTime'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatLocalDate'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatDateInterval'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatBlob'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'formatLimitOffset'); + $this->assertMethodHasNoDiscard(IPlatform::class, 'createMultiQueryParser'); + } + + + public function testResultMethodsHaveNoDiscard(): void + { + $this->assertMethodHasNoDiscard(Result::class, 'getAdapter'); + $this->assertMethodHasNoDiscard(Result::class, 'fetchField'); + $this->assertMethodHasNoDiscard(Result::class, 'fetchAll'); + $this->assertMethodHasNoDiscard(Result::class, 'fetchPairs'); + $this->assertMethodHasNoDiscard(Result::class, 'getColumns'); + } + + + public function testRowAndFqnMethodsHaveNoDiscard(): void + { + $this->assertMethodHasNoDiscard(Row::class, 'toArray'); + $this->assertMethodHasNoDiscard(Row::class, 'getNthField'); + $this->assertMethodHasNoDiscard(Fqn::class, 'getUnescaped'); + } + + + private function assertMethodHasNoDiscard(string $className, string $methodName): void + { + $method = new ReflectionMethod($className, $methodName); + Assert::same([\NoDiscard::class], array_map( + static fn($attribute): string => $attribute->getName(), + $method->getAttributes(), + )); + } +} + + +$test = new NoDiscardAttributeTest(); +$test->run(); diff --git a/tests/cases/unit/ResultTest.phpt b/tests/cases/unit/ResultTest.phpt index f9224fff..a09fa198 100644 --- a/tests/cases/unit/ResultTest.phpt +++ b/tests/cases/unit/ResultTest.phpt @@ -60,7 +60,7 @@ class ResultTest extends TestCase Assert::same('First', $result->fetchField()); Assert::same('Two', $result->fetchField(1)); Assert::throws(function () use ($result) { - $result->fetchField(2); + $_ = $result->fetchField(2); }, InvalidArgumentException::class); $adapter = Mockery::mock(IResultAdapter::class); @@ -156,7 +156,7 @@ class ResultTest extends TestCase $adapter->shouldReceive('getNormalizers')->once()->andReturn([]); $result = new Result($adapter); $result->setValueNormalization(false); - $result->fetchPairs(); + $_ = $result->fetchPairs(); }, InvalidArgumentException::class, 'Result::fetchPairs() requires defined key or value.'); }