diff --git a/apps/dav/tests/unit/BackgroundJob/CleanupInvitationTokenJobTest.php b/apps/dav/tests/unit/BackgroundJob/CleanupInvitationTokenJobTest.php index 61f39e0a8d9b2..df4096d94ee08 100644 --- a/apps/dav/tests/unit/BackgroundJob/CleanupInvitationTokenJobTest.php +++ b/apps/dav/tests/unit/BackgroundJob/CleanupInvitationTokenJobTest.php @@ -11,6 +11,7 @@ use OCA\DAV\BackgroundJob\CleanupInvitationTokenJob; use OCP\AppFramework\Utility\ITimeFactory; use OCP\DB\QueryBuilder\IExpressionBuilder; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use PHPUnit\Framework\MockObject\MockObject; @@ -46,9 +47,12 @@ public function testRun(): void { ->willReturn($queryBuilder); $queryBuilder->method('expr') ->willReturn($expr); + $parameter = $this->createMock(IParameter::class); + $parameter->method('__toString') + ->willReturn('namedParameter1337'); $queryBuilder->method('createNamedParameter') ->willReturnMap([ - [1337, \PDO::PARAM_STR, null, 'namedParameter1337'] + [1337, \PDO::PARAM_STR, null, $parameter], ]); $function = 'function1337'; diff --git a/apps/dav/tests/unit/Controller/InvitationResponseControllerTest.php b/apps/dav/tests/unit/Controller/InvitationResponseControllerTest.php index 3b535ceed22fc..95d6fab7b7e24 100644 --- a/apps/dav/tests/unit/Controller/InvitationResponseControllerTest.php +++ b/apps/dav/tests/unit/Controller/InvitationResponseControllerTest.php @@ -15,6 +15,7 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\DB\IResult; use OCP\DB\QueryBuilder\IExpressionBuilder; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\IRequest; @@ -415,9 +416,12 @@ private function buildQueryExpects(string $token, ?array $return, int $time): vo ->willReturn($queryBuilder); $queryBuilder->method('expr') ->willReturn($expr); + $parameter = $this->createMock(IParameter::class); + $parameter->method('__toString') + ->willReturn('namedParameterToken'); $queryBuilder->method('createNamedParameter') ->willReturnMap([ - [$token, \PDO::PARAM_STR, null, 'namedParameterToken'] + [$token, \PDO::PARAM_STR, null, $parameter] ]); $stmt->expects($this->once()) diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 371f575b9a25e..09e4d881ef15d 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -3173,7 +3173,6 @@ - @@ -3503,42 +3502,6 @@ - - - functionBuilder->lower($x)]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - l($type, $timestamp, [ @@ -4256,13 +4219,4 @@ - - - - - - - - - diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php index b922c8616305f..dd7705f2344bf 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php @@ -5,62 +5,43 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + +declare(strict_types=1); + namespace OC\DB\QueryBuilder\ExpressionBuilder; use Doctrine\DBAL\Query\Expression\ExpressionBuilder as DoctrineExpressionBuilder; use OC\DB\ConnectionAdapter; use OC\DB\QueryBuilder\CompositeExpression; -use OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder; use OC\DB\QueryBuilder\Literal; use OC\DB\QueryBuilder\QueryFunction; use OC\DB\QueryBuilder\QuoteHelper; use OCP\DB\QueryBuilder\ICompositeExpression; use OCP\DB\QueryBuilder\IExpressionBuilder; +use OCP\DB\QueryBuilder\IFunctionBuilder; use OCP\DB\QueryBuilder\ILiteral; use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; -use OCP\IDBConnection; +use Override; use Psr\Log\LoggerInterface; class ExpressionBuilder implements IExpressionBuilder { - /** @var \Doctrine\DBAL\Query\Expression\ExpressionBuilder */ - protected $expressionBuilder; - - /** @var QuoteHelper */ - protected $helper; - - /** @var IDBConnection */ - protected $connection; - - /** @var LoggerInterface */ - protected $logger; - - /** @var FunctionBuilder */ - protected $functionBuilder; - - public function __construct(ConnectionAdapter $connection, IQueryBuilder $queryBuilder, LoggerInterface $logger) { - $this->connection = $connection; - $this->logger = $logger; + protected \Doctrine\DBAL\Query\Expression\ExpressionBuilder $expressionBuilder; + protected QuoteHelper $helper; + protected IFunctionBuilder $functionBuilder; + + public function __construct( + protected readonly ConnectionAdapter $connection, + IQueryBuilder $queryBuilder, + protected readonly LoggerInterface $logger, + ) { $this->helper = new QuoteHelper(); $this->expressionBuilder = new DoctrineExpressionBuilder($connection->getInner()); $this->functionBuilder = $queryBuilder->func(); } - /** - * Creates a conjunction of the given boolean expressions. - * - * Example: - * - * [php] - * // (u.type = ?) AND (u.role = ?) - * $expr->andX('u.type = ?', 'u.role = ?')); - * - * @param mixed ...$x Optional clause. Defaults = null, but requires - * at least one defined when converting to string. - * - * @return \OCP\DB\QueryBuilder\ICompositeExpression - */ + #[Override] public function andX(...$x): ICompositeExpression { if (empty($x)) { $this->logger->debug('Calling ' . IQueryBuilder::class . '::' . __FUNCTION__ . ' without parameters is deprecated and will throw soon.', ['exception' => new \Exception('No parameters in call to ' . __METHOD__)]); @@ -68,20 +49,7 @@ public function andX(...$x): ICompositeExpression { return new CompositeExpression(CompositeExpression::TYPE_AND, $x); } - /** - * Creates a disjunction of the given boolean expressions. - * - * Example: - * - * [php] - * // (u.type = ?) OR (u.role = ?) - * $qb->where($qb->expr()->orX('u.type = ?', 'u.role = ?')); - * - * @param mixed ...$x Optional clause. Defaults = null, but requires - * at least one defined when converting to string. - * - * @return \OCP\DB\QueryBuilder\ICompositeExpression - */ + #[Override] public function orX(...$x): ICompositeExpression { if (empty($x)) { $this->logger->debug('Calling ' . IQueryBuilder::class . '::' . __FUNCTION__ . ' without parameters is deprecated and will throw soon.', ['exception' => new \Exception('No parameters in call to ' . __METHOD__)]); @@ -89,106 +57,35 @@ public function orX(...$x): ICompositeExpression { return new CompositeExpression(CompositeExpression::TYPE_OR, $x); } - /** - * Creates a comparison expression. - * - * @param mixed $x The left expression. - * @param string $operator One of the IExpressionBuilder::* constants. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ + #[Override] public function comparison($x, string $operator, $y, $type = null): string { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->comparison($x, $operator, $y); } - /** - * Creates an equality comparison expression with the given arguments. - * - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a = . Example: - * - * [php] - * // u.id = ? - * $expr->eq('u.id', '?'); - * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ - public function eq($x, $y, $type = null): string { + #[Override] + public function eq(string|ILiteral|IQueryFunction|IParameter $x, IQueryFunction|ILiteral|IParameter|string $y, int|string|null $type = null): string { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->eq($x, $y); } - /** - * Creates a non equality comparison expression with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a <> . Example: - * - * [php] - * // u.id <> 1 - * $q->where($q->expr()->neq('u.id', '1')); - * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ - public function neq($x, $y, $type = null): string { + #[Override] + public function neq(string|ILiteral|IQueryFunction|IParameter $x, string|ILiteral|IQueryFunction|IParameter $y, int|string|null $type = null): string { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->neq($x, $y); } - /** - * Creates a lower-than comparison expression with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a < . Example: - * - * [php] - * // u.id < ? - * $q->where($q->expr()->lt('u.id', '?')); - * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ + #[Override] public function lt($x, $y, $type = null): string { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->lt($x, $y); } - /** - * Creates a lower-than-equal comparison expression with the given arguments. - * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a <= . Example: - * - * [php] - * // u.id <= ? - * $q->where($q->expr()->lte('u.id', '?')); - * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ + #[Override] public function lte($x, $y, $type = null): string { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); @@ -239,193 +136,93 @@ public function gte($x, $y, $type = null): string { return $this->expressionBuilder->gte($x, $y); } - /** - * Creates an IS NULL expression with the given arguments. - * - * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be restricted by IS NULL. - * - * @return string - */ + #[Override] public function isNull($x): string { $x = $this->helper->quoteColumnName($x); return $this->expressionBuilder->isNull($x); } - /** - * Creates an IS NOT NULL expression with the given arguments. - * - * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be restricted by IS NOT NULL. - * - * @return string - */ + #[Override] public function isNotNull($x): string { $x = $this->helper->quoteColumnName($x); return $this->expressionBuilder->isNotNull($x); } - /** - * Creates a LIKE() comparison expression with the given arguments. - * - * @param ILiteral|IParameter|IQueryFunction|string $x Field in string format to be inspected by LIKE() comparison. - * @param mixed $y Argument to be used in LIKE() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ - public function like($x, $y, $type = null): string { + #[Override] + public function like(ILiteral|IParameter|IQueryFunction|string $x, mixed $y, mixed $type = null): string { $x = $this->helper->quoteColumnName($x); $y = $this->helper->quoteColumnName($y); return $this->expressionBuilder->like($x, $y); } - /** - * Creates a ILIKE() comparison expression with the given arguments. - * - * @param string $x Field in string format to be inspected by ILIKE() comparison. - * @param mixed $y Argument to be used in ILIKE() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - * @since 9.0.0 - */ - public function iLike($x, $y, $type = null): string { - return $this->expressionBuilder->like($this->functionBuilder->lower($x), $this->functionBuilder->lower($y)); + #[Override] + public function iLike(string|IParameter|ILiteral|IQueryFunction $x, mixed $y, mixed $type = null): string { + return $this->expressionBuilder->like((string)$this->functionBuilder->lower($x), (string)$this->functionBuilder->lower($y)); } - /** - * Creates a NOT LIKE() comparison expression with the given arguments. - * - * @param ILiteral|IParameter|IQueryFunction|string $x Field in string format to be inspected by NOT LIKE() comparison. - * @param mixed $y Argument to be used in NOT LIKE() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ - public function notLike($x, $y, $type = null): string { + #[Override] + public function notLike(string|IParameter|ILiteral|IQueryFunction $x, mixed $y, mixed $type = null): string { $x = $this->helper->quoteColumnName($x); $y = $this->helper->quoteColumnName($y); return $this->expressionBuilder->notLike($x, $y); } - /** - * Creates a IN () comparison expression with the given arguments. - * - * @param ILiteral|IParameter|IQueryFunction|string $x The field in string format to be inspected by IN() comparison. - * @param ILiteral|IParameter|IQueryFunction|string|array $y The placeholder or the array of values to be used by IN() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ - public function in($x, $y, $type = null): string { + #[Override] + public function in(ILiteral|IParameter|IQueryFunction|string $x, ILiteral|IParameter|IQueryFunction|string|array $y, mixed $type = null): string { $x = $this->helper->quoteColumnName($x); $y = $this->helper->quoteColumnNames($y); return $this->expressionBuilder->in($x, $y); } - /** - * Creates a NOT IN () comparison expression with the given arguments. - * - * @param ILiteral|IParameter|IQueryFunction|string $x The field in string format to be inspected by NOT IN() comparison. - * @param ILiteral|IParameter|IQueryFunction|string|array $y The placeholder or the array of values to be used by NOT IN() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility - * - * @return string - */ - public function notIn($x, $y, $type = null): string { + #[Override] + public function notIn(ILiteral|IParameter|IQueryFunction|string $x, ILiteral|IParameter|IQueryFunction|string|array $y, mixed $type = null): string { $x = $this->helper->quoteColumnName($x); $y = $this->helper->quoteColumnNames($y); return $this->expressionBuilder->notIn($x, $y); } - /** - * Creates a $x = '' statement, because Oracle needs a different check - * - * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be inspected by the comparison. - * @return string - * @since 13.0.0 - */ - public function emptyString($x): string { + #[Override] + public function emptyString(string|ILiteral|IParameter|IQueryFunction $x): string { return $this->eq($x, $this->literal('', IQueryBuilder::PARAM_STR)); } - /** - * Creates a `$x <> ''` statement, because Oracle needs a different check - * - * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be inspected by the comparison. - * @return string - * @since 13.0.0 - */ - public function nonEmptyString($x): string { + #[Override] + public function nonEmptyString(string|ILiteral|IParameter|IQueryFunction $x): string { return $this->neq($x, $this->literal('', IQueryBuilder::PARAM_STR)); } - /** - * Binary AND Operator copies a bit to the result if it exists in both operands. - * - * @param string|ILiteral $x The field or value to check - * @param int $y Bitmap that must be set - * @return IQueryFunction - * @since 12.0.0 - */ + #[Override] public function bitwiseAnd($x, int $y): IQueryFunction { return new QueryFunction($this->connection->getDatabasePlatform()->getBitAndComparisonExpression( $this->helper->quoteColumnName($x), - $y + (string)$y )); } - /** - * Binary OR Operator copies a bit if it exists in either operand. - * - * @param string|ILiteral $x The field or value to check - * @param int $y Bitmap that must be set - * @return IQueryFunction - * @since 12.0.0 - */ + #[Override] public function bitwiseOr($x, int $y): IQueryFunction { return new QueryFunction($this->connection->getDatabasePlatform()->getBitOrComparisonExpression( $this->helper->quoteColumnName($x), - $y + (string)$y )); } - /** - * Quotes a given input parameter. - * - * @param mixed $input The parameter to be quoted. - * @param int $type One of the IQueryBuilder::PARAM_* constants - * - * @return ILiteral - */ - public function literal($input, $type = IQueryBuilder::PARAM_STR): ILiteral { + #[Override] + public function literal($input, int|string $type = IQueryBuilder::PARAM_STR): ILiteral { return new Literal($this->expressionBuilder->literal($input, $type)); } - /** - * Returns a IQueryFunction that casts the column to the given type - * - * @param string|IQueryFunction $column - * @param mixed $type One of IQueryBuilder::PARAM_* - * @psalm-param IQueryBuilder::PARAM_* $type - * @return IQueryFunction - */ - public function castColumn($column, $type): IQueryFunction { + #[Override] + public function castColumn(string|IQueryFunction|ILiteral|IParameter $column, int|string $type): IQueryFunction { return new QueryFunction( $this->helper->quoteColumnName($column) ); } /** - * @param mixed $column - * @param mixed|null $type - * @return array|IQueryFunction|string + * @param IQueryBuilder::PARAM_* $type */ - protected function prepareColumn($column, $type) { + protected function prepareColumn(IQueryFunction|ILiteral|IParameter|string|array $column, int|string|null $type): array|string { return $this->helper->quoteColumnNames($column); } } diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php index 0227c3154e3d8..db801a0f8239f 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/MySqlExpressionBuilder.php @@ -5,12 +5,18 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + +declare(strict_types=1); + namespace OC\DB\QueryBuilder\ExpressionBuilder; use OC\DB\ConnectionAdapter; use OC\DB\QueryBuilder\QueryFunction; +use OCP\DB\QueryBuilder\ILiteral; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; +use Override; use Psr\Log\LoggerInterface; class MySqlExpressionBuilder extends ExpressionBuilder { @@ -19,35 +25,25 @@ class MySqlExpressionBuilder extends ExpressionBuilder { public function __construct(ConnectionAdapter $connection, IQueryBuilder $queryBuilder, LoggerInterface $logger) { parent::__construct($connection, $queryBuilder, $logger); + /** @psalm-suppress InternalMethod */ $params = $connection->getInner()->getParams(); + /** @psalm-suppress InvalidArrayOffset collation is sometime defined */ $this->collation = $params['collation'] ?? (($params['charset'] ?? 'utf8') . '_general_ci'); } - /** - * @inheritdoc - */ - public function iLike($x, $y, $type = null): string { + #[Override] + public function iLike(string|IParameter|ILiteral|IQueryFunction $x, mixed $y, mixed $type = null): string { $x = $this->helper->quoteColumnName($x); $y = $this->helper->quoteColumnName($y); return $this->expressionBuilder->comparison($x, ' COLLATE ' . $this->collation . ' LIKE', $y); } - /** - * Returns a IQueryFunction that casts the column to the given type - * - * @param string|IQueryFunction $column - * @param mixed $type One of IQueryBuilder::PARAM_* - * @psalm-param IQueryBuilder::PARAM_* $type - * @return IQueryFunction - */ - public function castColumn($column, $type): IQueryFunction { - switch ($type) { - case IQueryBuilder::PARAM_STR: - return new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS CHAR)'); - case IQueryBuilder::PARAM_JSON: - return new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS JSON)'); - default: - return parent::castColumn($column, $type); - } + #[Override] + public function castColumn(string|IParameter|ILiteral|IQueryFunction $column, int|string $type): IQueryFunction { + return match ($type) { + IQueryBuilder::PARAM_STR => new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS CHAR)'), + IQueryBuilder::PARAM_JSON => new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS JSON)'), + default => parent::castColumn($column, $type), + }; } } diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php index 20308b2455004..683b75dc8feb3 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/OCIExpressionBuilder.php @@ -12,14 +12,11 @@ use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; +use Override; class OCIExpressionBuilder extends ExpressionBuilder { - /** - * @param mixed $column - * @param mixed|null $type - * @return array|IQueryFunction|string - */ - protected function prepareColumn($column, $type) { + #[Override] + protected function prepareColumn(IQueryFunction|ILiteral|IParameter|string|array $column, int|string|null $type): array|string { if ($type === IQueryBuilder::PARAM_STR && !is_array($column) && !($column instanceof IParameter) && !($column instanceof ILiteral)) { $column = $this->castColumn($column, $type); } @@ -27,10 +24,8 @@ protected function prepareColumn($column, $type) { return parent::prepareColumn($column, $type); } - /** - * @inheritdoc - */ - public function eq($x, $y, $type = null): string { + #[Override] + public function eq(IQueryFunction|ILiteral|IParameter|string $x, IQueryFunction|ILiteral|IParameter|string $y, int|string|null $type = null): string { if ($type === IQueryBuilder::PARAM_JSON) { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); @@ -40,9 +35,7 @@ public function eq($x, $y, $type = null): string { return parent::eq($x, $y, $type); } - /** - * @inheritdoc - */ + #[Override] public function neq($x, $y, $type = null): string { if ($type === IQueryBuilder::PARAM_JSON) { $x = $this->prepareColumn($x, $type); @@ -53,57 +46,34 @@ public function neq($x, $y, $type = null): string { return parent::neq($x, $y, $type); } - /** - * @inheritdoc - */ - public function in($x, $y, $type = null): string { + #[Override] + public function in(ILiteral|IParameter|IQueryFunction|string $x, ILiteral|IParameter|IQueryFunction|string|array $y, mixed $type = null): string { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->in($x, $y); } - /** - * @inheritdoc - */ - public function notIn($x, $y, $type = null): string { + #[Override] + public function notIn(ILiteral|IParameter|IQueryFunction|string $x, ILiteral|IParameter|IQueryFunction|string|array $y, mixed $type = null): string { $x = $this->prepareColumn($x, $type); $y = $this->prepareColumn($y, $type); return $this->expressionBuilder->notIn($x, $y); } - /** - * Creates a $x = '' statement, because Oracle needs a different check - * - * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be inspected by the comparison. - * @return string - * @since 13.0.0 - */ - public function emptyString($x): string { + #[Override] + public function emptyString(string|ILiteral|IParameter|IQueryFunction $x): string { return $this->isNull($x); } - /** - * Creates a `$x <> ''` statement, because Oracle needs a different check - * - * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be inspected by the comparison. - * @return string - * @since 13.0.0 - */ - public function nonEmptyString($x): string { + #[Override] + public function nonEmptyString(string|ILiteral|IParameter|IQueryFunction $x): string { return $this->isNotNull($x); } - /** - * Returns a IQueryFunction that casts the column to the given type - * - * @param string|IQueryFunction $column - * @param mixed $type One of IQueryBuilder::PARAM_* - * @psalm-param IQueryBuilder::PARAM_* $type - * @return IQueryFunction - */ - public function castColumn($column, $type): IQueryFunction { + #[Override] + public function castColumn(string|IQueryFunction|ILiteral|IParameter $column, mixed $type): IQueryFunction { if ($type === IQueryBuilder::PARAM_STR) { $column = $this->helper->quoteColumnName($column); return new QueryFunction('to_char(' . $column . ')'); @@ -116,17 +86,13 @@ public function castColumn($column, $type): IQueryFunction { return parent::castColumn($column, $type); } - /** - * @inheritdoc - */ - public function like($x, $y, $type = null): string { + #[Override] + public function like(ILiteral|IParameter|IQueryFunction|string $x, mixed $y, mixed $type = null): string { return parent::like($x, $y, $type) . " ESCAPE '\\'"; } - /** - * @inheritdoc - */ - public function iLike($x, $y, $type = null): string { + #[Override] + public function iLike(string|IParameter|ILiteral|IQueryFunction $x, mixed $y, mixed $type = null): string { return $this->like($this->functionBuilder->lower($x), $this->functionBuilder->lower($y)); } } diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/PgSqlExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/PgSqlExpressionBuilder.php index f30fccadb1fbd..4ed231c31ade3 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/PgSqlExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/PgSqlExpressionBuilder.php @@ -12,32 +12,20 @@ use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; +use Override; class PgSqlExpressionBuilder extends ExpressionBuilder { - /** - * Returns a IQueryFunction that casts the column to the given type - * - * @param string|IQueryFunction $column - * @param mixed $type One of IQueryBuilder::PARAM_* - * @psalm-param IQueryBuilder::PARAM_* $type - * @return IQueryFunction - */ - public function castColumn($column, $type): IQueryFunction { - switch ($type) { - case IQueryBuilder::PARAM_INT: - return new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS BIGINT)'); - case IQueryBuilder::PARAM_STR: - case IQueryBuilder::PARAM_JSON: - return new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS TEXT)'); - default: - return parent::castColumn($column, $type); - } + #[Override] + public function castColumn(string|IQueryFunction|ILiteral|IParameter $column, string|int $type): IQueryFunction { + return match ($type) { + IQueryBuilder::PARAM_INT => new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS BIGINT)'), + IQueryBuilder::PARAM_STR, IQueryBuilder::PARAM_JSON => new QueryFunction('CAST(' . $this->helper->quoteColumnName($column) . ' AS TEXT)'), + default => parent::castColumn($column, $type), + }; } - /** - * @inheritdoc - */ - protected function prepareColumn($column, $type) { + #[Override] + protected function prepareColumn(IQueryFunction|ILiteral|IParameter|string|array $column, int|string|null $type): string|array { if ($type === IQueryBuilder::PARAM_JSON && !is_array($column) && !($column instanceof IParameter) && !($column instanceof ILiteral)) { $column = $this->castColumn($column, $type); } @@ -45,10 +33,8 @@ protected function prepareColumn($column, $type) { return parent::prepareColumn($column, $type); } - /** - * @inheritdoc - */ - public function iLike($x, $y, $type = null): string { + #[Override] + public function iLike(string|IParameter|ILiteral|IQueryFunction $x, mixed $y, mixed $type = null): string { $x = $this->helper->quoteColumnName($x); $y = $this->helper->quoteColumnName($y); return $this->expressionBuilder->comparison($x, 'ILIKE', $y); diff --git a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php index 52f82db2232f8..28dcaed248e1e 100644 --- a/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php +++ b/lib/private/DB/QueryBuilder/ExpressionBuilder/SqliteExpressionBuilder.php @@ -11,44 +11,35 @@ use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; +use Override; class SqliteExpressionBuilder extends ExpressionBuilder { - /** - * @inheritdoc - */ - public function like($x, $y, $type = null): string { + #[Override] + public function like(ILiteral|IParameter|IQueryFunction|string $x, mixed $y, mixed $type = null): string { return parent::like($x, $y, $type) . " ESCAPE '\\'"; } - public function iLike($x, $y, $type = null): string { + #[Override] + public function iLike(string|IParameter|ILiteral|IQueryFunction $x, mixed $y, mixed $type = null): string { return $this->like($this->functionBuilder->lower($x), $this->functionBuilder->lower($y), $type); } - /** - * @param mixed $column - * @param mixed|null $type - * @return array|IQueryFunction|string - */ - protected function prepareColumn($column, $type) { - if ($type !== null - && !is_array($column) - && !($column instanceof IParameter) + #[Override] + protected function prepareColumn(IQueryFunction|ILiteral|IParameter|string|array $column, int|string|null $type): string|array { + if (!($column instanceof IParameter) + && !($column instanceof IQueryFunction) && !($column instanceof ILiteral) + && !is_array($column) + && is_string($type) && (str_starts_with($type, 'date') || str_starts_with($type, 'time'))) { - return $this->castColumn($column, $type); + return (string)$this->castColumn($column, $type); } return parent::prepareColumn($column, $type); } - /** - * Returns a IQueryFunction that casts the column to the given type - * - * @param string $column - * @param mixed $type One of IQueryBuilder::PARAM_* - * @return IQueryFunction - */ - public function castColumn($column, $type): IQueryFunction { + #[Override] + public function castColumn(string|IQueryFunction|ILiteral|IParameter $column, string|int $type): IQueryFunction { switch ($type) { case IQueryBuilder::PARAM_DATE_MUTABLE: case IQueryBuilder::PARAM_DATE_IMMUTABLE: diff --git a/lib/private/DB/QueryBuilder/ExtendedQueryBuilder.php b/lib/private/DB/QueryBuilder/ExtendedQueryBuilder.php index 9230c55c28c86..2b2c4aecf2c09 100644 --- a/lib/private/DB/QueryBuilder/ExtendedQueryBuilder.php +++ b/lib/private/DB/QueryBuilder/ExtendedQueryBuilder.php @@ -9,284 +9,349 @@ namespace OC\DB\QueryBuilder; use OCP\DB\IResult; +use OCP\DB\QueryBuilder\ICompositeExpression; +use OCP\DB\QueryBuilder\IExpressionBuilder; +use OCP\DB\QueryBuilder\IFunctionBuilder; +use OCP\DB\QueryBuilder\ILiteral; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\QueryBuilder\IQueryFunction; use OCP\IDBConnection; +use Override; /** * Base class for creating classes that extend the builtin query builder */ abstract class ExtendedQueryBuilder implements IQueryBuilder { public function __construct( - protected IQueryBuilder $builder, + protected readonly IQueryBuilder $builder, ) { } - public function automaticTablePrefix($enabled) { + #[Override] + public function automaticTablePrefix(bool $enabled): void { $this->builder->automaticTablePrefix($enabled); - return $this; } - public function expr() { + #[Override] + public function expr(): IExpressionBuilder { return $this->builder->expr(); } - public function func() { + #[Override] + public function func(): IFunctionBuilder { return $this->builder->func(); } - public function getType() { + #[Override] + public function getType(): int { return $this->builder->getType(); } - public function getConnection() { + #[Override] + public function getConnection(): IDBConnection { return $this->builder->getConnection(); } - public function getState() { + #[Override] + public function getState(): int { return $this->builder->getState(); } - public function getSQL() { + #[Override] + public function getSQL(): string { return $this->builder->getSQL(); } - public function setParameter($key, $value, $type = null) { + #[Override] + public function setParameter(string|int $key, mixed $value, string|null|int $type = null): self { $this->builder->setParameter($key, $value, $type); return $this; } - public function setParameters(array $params, array $types = []) { + #[Override] + public function setParameters(array $params, array $types = []): self { $this->builder->setParameters($params, $types); return $this; } - public function getParameters() { + #[Override] + public function getParameters(): array { return $this->builder->getParameters(); } - public function getParameter($key) { + #[Override] + public function getParameter(int|string $key): mixed { return $this->builder->getParameter($key); } - public function getParameterTypes() { + #[Override] + public function getParameterTypes(): array { return $this->builder->getParameterTypes(); } - public function getParameterType($key) { + #[Override] + public function getParameterType(int|string $key): mixed { return $this->builder->getParameterType($key); } - public function setFirstResult($firstResult) { + #[Override] + public function setFirstResult(int $firstResult): self { $this->builder->setFirstResult($firstResult); return $this; } - public function getFirstResult() { + #[Override] + public function getFirstResult(): int { return $this->builder->getFirstResult(); } - public function setMaxResults($maxResults) { + #[Override] + public function setMaxResults(?int $maxResults): self { $this->builder->setMaxResults($maxResults); return $this; } - public function getMaxResults() { + #[Override] + public function getMaxResults(): ?int { return $this->builder->getMaxResults(); } - public function select(...$selects) { + #[Override] + public function select(...$selects): self { $this->builder->select(...$selects); return $this; } - public function selectAlias($select, $alias) { + #[Override] + public function selectAlias(string|IQueryFunction|IParameter|ILiteral $select, string $alias): self { $this->builder->selectAlias($select, $alias); return $this; } - public function selectDistinct($select) { + #[Override] + public function selectDistinct(string|array $select): self { $this->builder->selectDistinct($select); return $this; } - public function addSelect(...$select) { - $this->builder->addSelect(...$select); + #[Override] + public function addSelect(...$selects): self { + $this->builder->addSelect(...$selects); return $this; } - public function delete($delete = null, $alias = null) { + #[Override] + public function delete(string $delete, ?string $alias = null): self { $this->builder->delete($delete, $alias); return $this; } - public function update($update = null, $alias = null) { + #[Override] + public function update(string $update, ?string $alias = null): self { $this->builder->update($update, $alias); return $this; } - public function insert($insert = null) { + #[Override] + public function insert(string $insert): self { $this->builder->insert($insert); return $this; } - public function from($from, $alias = null) { + #[Override] + public function from(string|IQueryFunction $from, ?string $alias = null): self { $this->builder->from($from, $alias); return $this; } - public function join($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function join(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->builder->join($fromAlias, $join, $alias, $condition); return $this; } - public function innerJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function innerJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->builder->innerJoin($fromAlias, $join, $alias, $condition); return $this; } - public function leftJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function leftJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->builder->leftJoin($fromAlias, $join, $alias, $condition); return $this; } - public function rightJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function rightJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->builder->rightJoin($fromAlias, $join, $alias, $condition); return $this; } - public function set($key, $value) { + #[Override] + public function set(string $key, ILiteral|IParameter|IQueryFunction|string $value): self { $this->builder->set($key, $value); return $this; } - public function where(...$predicates) { + #[Override] + public function where(...$predicates): self { $this->builder->where(...$predicates); return $this; } - public function andWhere(...$where) { + #[Override] + public function andWhere(...$where): self { $this->builder->andWhere(...$where); return $this; } - public function orWhere(...$where) { + #[Override] + public function orWhere(...$where): self { $this->builder->orWhere(...$where); return $this; } - public function groupBy(...$groupBys) { + #[Override] + public function groupBy(...$groupBys): self { $this->builder->groupBy(...$groupBys); return $this; } - public function addGroupBy(...$groupBy) { + #[Override] + public function addGroupBy(...$groupBy): self { $this->builder->addGroupBy(...$groupBy); return $this; } - public function setValue($column, $value) { + #[Override] + public function setValue(string $column, ILiteral|IParameter|IQueryFunction|string $value): self { $this->builder->setValue($column, $value); return $this; } - public function values(array $values) { + #[Override] + public function values(array $values): self { $this->builder->values($values); return $this; } - public function having(...$having) { + #[Override] + public function having(...$having): self { $this->builder->having(...$having); return $this; } - public function andHaving(...$having) { + #[Override] + public function andHaving(...$having): self { $this->builder->andHaving(...$having); return $this; } - public function orHaving(...$having) { + #[Override] + public function orHaving(...$having): self { $this->builder->orHaving(...$having); return $this; } - public function orderBy($sort, $order = null) { + #[Override] + public function orderBy(string|ILiteral|IParameter|IQueryFunction $sort, ?string $order = null): self { $this->builder->orderBy($sort, $order); return $this; } - public function addOrderBy($sort, $order = null) { + #[Override] + public function addOrderBy(string|ILiteral|IParameter|IQueryFunction $sort, ?string $order = null): self { $this->builder->addOrderBy($sort, $order); return $this; } - public function getQueryPart($queryPartName) { + #[Override] + public function getQueryPart(string $queryPartName): mixed { return $this->builder->getQueryPart($queryPartName); } - public function getQueryParts() { + #[Override] + public function getQueryParts(): array { return $this->builder->getQueryParts(); } - public function resetQueryParts($queryPartNames = null) { + #[Override] + public function resetQueryParts(?array $queryPartNames = null): self { $this->builder->resetQueryParts($queryPartNames); return $this; } - public function resetQueryPart($queryPartName) { + #[Override] + public function resetQueryPart(string $queryPartName): self { $this->builder->resetQueryPart($queryPartName); return $this; } - public function createNamedParameter($value, $type = self::PARAM_STR, $placeHolder = null) { + #[Override] + public function createNamedParameter(mixed $value, mixed $type = self::PARAM_STR, $placeHolder = null): IParameter { return $this->builder->createNamedParameter($value, $type, $placeHolder); } - public function createPositionalParameter($value, $type = self::PARAM_STR) { + #[Override] + public function createPositionalParameter(mixed $value, mixed $type = self::PARAM_STR): IParameter { return $this->builder->createPositionalParameter($value, $type); } - public function createParameter($name) { + #[Override] + public function createParameter(string $name): IParameter { return $this->builder->createParameter($name); } - public function createFunction($call) { + #[Override] + public function createFunction(string $call): IQueryFunction { return $this->builder->createFunction($call); } + #[Override] public function getLastInsertId(): int { return $this->builder->getLastInsertId(); } - public function getTableName($table) { + #[Override] + public function getTableName(string|IQueryFunction $table): string { return $this->builder->getTableName($table); } - public function getColumnName($column, $tableAlias = '') { + #[Override] + public function getColumnName(string $column, string $tableAlias = ''): string { return $this->builder->getColumnName($column, $tableAlias); } + #[Override] public function executeQuery(?IDBConnection $connection = null): IResult { return $this->builder->executeQuery($connection); } + #[Override] public function executeStatement(?IDBConnection $connection = null): int { return $this->builder->executeStatement($connection); } + #[Override] public function hintShardKey(string $column, mixed $value, bool $overwrite = false): self { $this->builder->hintShardKey($column, $value, $overwrite); return $this; } + #[Override] public function runAcrossAllShards(): self { $this->builder->runAcrossAllShards(); return $this; } + #[Override] public function getOutputColumns(): array { return $this->builder->getOutputColumns(); } + #[Override] public function prefixTableName(string $table): string { return $this->builder->prefixTableName($table); } diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php index 48dc1da6330b8..d70c7e0032c8d 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php @@ -6,35 +6,28 @@ */ namespace OC\DB\QueryBuilder\FunctionBuilder; -use OC\DB\Connection; +use OC\DB\ConnectionAdapter; use OC\DB\QueryBuilder\QueryFunction; use OC\DB\QueryBuilder\QuoteHelper; use OCP\DB\QueryBuilder\IFunctionBuilder; +use OCP\DB\QueryBuilder\ILiteral; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; -use OCP\IDBConnection; class FunctionBuilder implements IFunctionBuilder { - /** @var IDBConnection|Connection */ - protected $connection; - - /** @var IQueryBuilder */ - protected $queryBuilder; - - /** @var QuoteHelper */ - protected $helper; - - public function __construct(IDBConnection $connection, IQueryBuilder $queryBuilder, QuoteHelper $helper) { - $this->connection = $connection; - $this->queryBuilder = $queryBuilder; - $this->helper = $helper; + public function __construct( + protected readonly ConnectionAdapter $connection, + protected readonly IQueryBuilder $queryBuilder, + protected readonly QuoteHelper $helper, + ) { } public function md5($input): IQueryFunction { return new QueryFunction('MD5(' . $this->helper->quoteColumnName($input) . ')'); } - public function concat($x, ...$expr): IQueryFunction { + public function concat(string|ILiteral|IParameter|IQueryFunction $x, ...$expr): IQueryFunction { $args = func_get_args(); $list = []; foreach ($args as $item) { diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php index 354a2b126d758..d6c7774cf0168 100644 --- a/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php +++ b/lib/private/DB/QueryBuilder/FunctionBuilder/PgSqlFunctionBuilder.php @@ -9,8 +9,10 @@ use OC\DB\QueryBuilder\QueryFunction; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; +use Override; class PgSqlFunctionBuilder extends FunctionBuilder { + #[Override] public function concat($x, ...$expr): IQueryFunction { $args = func_get_args(); $list = []; @@ -20,6 +22,7 @@ public function concat($x, ...$expr): IQueryFunction { return new QueryFunction(sprintf('(%s)', implode(' || ', $list))); } + #[Override] public function groupConcat($expr, ?string $separator = ','): IQueryFunction { $castedExpression = $this->queryBuilder->expr()->castColumn($expr, IQueryBuilder::PARAM_STR); diff --git a/lib/private/DB/QueryBuilder/Literal.php b/lib/private/DB/QueryBuilder/Literal.php index 3fb897328e56a..eea03f926f531 100644 --- a/lib/private/DB/QueryBuilder/Literal.php +++ b/lib/private/DB/QueryBuilder/Literal.php @@ -10,11 +10,9 @@ use OCP\DB\QueryBuilder\ILiteral; class Literal implements ILiteral { - /** @var mixed */ - protected $literal; - - public function __construct($literal) { - $this->literal = $literal; + public function __construct( + protected readonly mixed $literal, + ) { } public function __toString(): string { diff --git a/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php b/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php index 7750ce5056a8d..977e15dd861fe 100644 --- a/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php +++ b/lib/private/DB/QueryBuilder/Partitioned/PartitionedQueryBuilder.php @@ -14,9 +14,13 @@ use OC\DB\QueryBuilder\Sharded\ShardConnectionManager; use OC\DB\QueryBuilder\Sharded\ShardedQueryBuilder; use OCP\DB\IResult; +use OCP\DB\QueryBuilder\ICompositeExpression; +use OCP\DB\QueryBuilder\ILiteral; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; use OCP\IDBConnection; +use Override; /** * A special query builder that automatically splits queries that span across multiple database partitions[1]. @@ -41,7 +45,7 @@ class PartitionedQueryBuilder extends ShardedQueryBuilder { /** @var list */ private array $partitions = []; - /** @var array{'select': string|array, 'alias': ?string}[] */ + /** @var array{'select': string|IQueryFunction|IParameter, 'alias': ?string}[] */ private array $selects = []; private ?PartitionSplit $mainPartition = null; private bool $hasPositionalParameter = false; @@ -75,7 +79,7 @@ private function newQuery(): IQueryBuilder { } // we need to save selects until we know all the table aliases - public function select(...$selects) { + public function select(...$selects): self { if (count($selects) === 1 && is_array($selects[0])) { $selects = $selects[0]; } @@ -84,15 +88,13 @@ public function select(...$selects) { return $this; } - public function addSelect(...$select) { - $select = array_map(function ($select) { - return ['select' => $select, 'alias' => null]; - }, $select); - $this->selects = array_merge($this->selects, $select); + public function addSelect(...$selects): self { + $selects = array_map(static fn ($select) => ['select' => $select, 'alias' => null], $selects); + $this->selects = array_merge($this->selects, $selects); return $this; } - public function selectAlias($select, $alias) { + public function selectAlias(string|IQueryFunction|IParameter|ILiteral $select, string $alias): self { $this->selects[] = ['select' => $select, 'alias' => $alias]; return $this; } @@ -101,9 +103,6 @@ public function selectAlias($select, $alias) { * Ensure that a column is being selected by the query * * This is mainly used to ensure that the returned rows from both sides of a partition contains the columns of the join predicate - * - * @param string|IQueryFunction $column - * @return void */ private function ensureSelect(string|IQueryFunction $column, ?string $alias = null): void { $checkColumn = $alias ?: $column; @@ -190,25 +189,30 @@ private function getPartition(string $table): ?PartitionSplit { return null; } - public function from($from, $alias = null) { + #[Override] + public function from($from, $alias = null): self { if (is_string($from) && $partition = $this->getPartition($from)) { $this->mainPartition = $partition; if ($alias) { $this->mainPartition->addAlias($from, $alias); } } - return parent::from($from, $alias); + parent::from($from, $alias); + return $this; } - public function innerJoin($fromAlias, $join, $alias, $condition = null): self { + #[Override] + public function innerJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { return $this->join($fromAlias, $join, $alias, $condition); } - public function leftJoin($fromAlias, $join, $alias, $condition = null): self { + #[Override] + public function leftJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { return $this->join($fromAlias, $join, $alias, $condition, PartitionQuery::JOIN_MODE_LEFT); } - public function join($fromAlias, $join, $alias, $condition = null, $joinMode = PartitionQuery::JOIN_MODE_INNER): self { + #[Override] + public function join(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null, string $joinMode = PartitionQuery::JOIN_MODE_INNER): self { if ($join instanceof IQueryFunction) { $partition = null; $fromPartition = null; @@ -281,11 +285,14 @@ public function join($fromAlias, $join, $alias, $condition = null, $joinMode = P } else { // join within the main db or a partition if ($joinMode === PartitionQuery::JOIN_MODE_INNER) { - return parent::innerJoin($fromAlias, $join, $alias, $condition); + parent::innerJoin($fromAlias, $join, $alias, $condition); + return $this; } elseif ($joinMode === PartitionQuery::JOIN_MODE_LEFT) { - return parent::leftJoin($fromAlias, $join, $alias, $condition); + parent::leftJoin($fromAlias, $join, $alias, $condition); + return $this; } elseif ($joinMode === PartitionQuery::JOIN_MODE_RIGHT) { - return parent::rightJoin($fromAlias, $join, $alias, $condition); + parent::rightJoin($fromAlias, $join, $alias, $condition); + return $this; } else { throw new \InvalidArgumentException("Invalid join mode: $joinMode"); } @@ -333,11 +340,11 @@ private function splitPredicatesByParts(array $predicates): array { return $partitionPredicates; } - public function where(...$predicates) { + public function where(...$predicates): self { return $this->andWhere(...$predicates); } - public function andWhere(...$where) { + public function andWhere(...$where): self { if ($where) { foreach ($this->splitPredicatesByParts($where) as $alias => $predicates) { if (isset($this->splitQueries[$alias])) { @@ -380,30 +387,35 @@ private function getPartitionForPredicate(string $predicate): ?PartitionSplit { return null; } - public function update($update = null, $alias = null) { - return parent::update($update, $alias); + public function update(string $update, ?string $alias = null): self { + parent::update($update, $alias); + return $this; } - public function insert($insert = null) { - return parent::insert($insert); + public function insert(string $insert): self { + parent::insert($insert); + return $this; } - public function delete($delete = null, $alias = null) { - return parent::delete($delete, $alias); + public function delete(string $delete, ?string $alias = null): self { + parent::delete($delete, $alias); + return $this; } - public function setMaxResults($maxResults) { - if ($maxResults > 0) { - $this->limit = (int)$maxResults; + public function setMaxResults(?int $maxResults): self { + if ($maxResults !== null && $maxResults > 0) { + $this->limit = $maxResults; } - return parent::setMaxResults($maxResults); + parent::setMaxResults($maxResults); + return $this; } - public function setFirstResult($firstResult) { + public function setFirstResult(int $firstResult): self { if ($firstResult > 0) { - $this->offset = (int)$firstResult; + $this->offset = $firstResult; } - return parent::setFirstResult($firstResult); + parent::setFirstResult($firstResult); + return $this; } public function executeQuery(?IDBConnection $connection = null): IResult { @@ -444,7 +456,7 @@ public function executeStatement(?IDBConnection $connection = null): int { return parent::executeStatement($connection); } - public function getSQL() { + public function getSQL(): string { $this->applySelects(); return parent::getSQL(); } diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php index 82fc6f84117c8..0ba7cdae0acee 100644 --- a/lib/private/DB/QueryBuilder/QueryBuilder.php +++ b/lib/private/DB/QueryBuilder/QueryBuilder.php @@ -20,78 +20,46 @@ use OC\SystemConfig; use OCP\DB\IResult; use OCP\DB\QueryBuilder\ICompositeExpression; +use OCP\DB\QueryBuilder\IExpressionBuilder; +use OCP\DB\QueryBuilder\IFunctionBuilder; use OCP\DB\QueryBuilder\ILiteral; use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; use OCP\IDBConnection; +use Override; use Psr\Log\LoggerInterface; class QueryBuilder implements IQueryBuilder { - /** @var ConnectionAdapter */ - private $connection; + private \Doctrine\DBAL\Query\QueryBuilder $queryBuilder; + private QuoteHelper $helper; - /** @var SystemConfig */ - private $systemConfig; - - private LoggerInterface $logger; - - /** @var \Doctrine\DBAL\Query\QueryBuilder */ - private $queryBuilder; - - /** @var QuoteHelper */ - private $helper; - - /** @var bool */ - private $automaticTablePrefix = true; + private bool $automaticTablePrefix = true; private bool $nonEmptyWhere = false; - /** @var string */ - protected $lastInsertedTable; + protected ?string $lastInsertedTable = null; + /** @var string[] */ private array $selectedColumns = []; /** * Initializes a new QueryBuilder. - * - * @param ConnectionAdapter $connection - * @param SystemConfig $systemConfig */ - public function __construct(ConnectionAdapter $connection, SystemConfig $systemConfig, LoggerInterface $logger) { - $this->connection = $connection; - $this->systemConfig = $systemConfig; - $this->logger = $logger; + public function __construct( + private ConnectionAdapter $connection, + private readonly SystemConfig $systemConfig, + private readonly LoggerInterface $logger, + ) { $this->queryBuilder = new \Doctrine\DBAL\Query\QueryBuilder($this->connection->getInner()); $this->helper = new QuoteHelper(); } - /** - * Enable/disable automatic prefixing of table names with the oc_ prefix - * - * @param bool $enabled If set to true table names will be prefixed with the - * owncloud database prefix automatically. - * @since 8.2.0 - */ - public function automaticTablePrefix($enabled) { - $this->automaticTablePrefix = (bool)$enabled; + #[Override] + public function automaticTablePrefix(bool $enabled): void { + $this->automaticTablePrefix = $enabled; } - /** - * Gets an ExpressionBuilder used for object-oriented construction of query expressions. - * This producer method is intended for convenient inline usage. Example: - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u') - * ->from('users', 'u') - * ->where($qb->expr()->eq('u.id', 1)); - * - * - * For more complex expression construction, consider storing the expression - * builder object in a local variable. - * - * @return \OCP\DB\QueryBuilder\IExpressionBuilder - */ - public function expr() { + #[Override] + public function expr(): IExpressionBuilder { return match($this->connection->getDatabaseProvider()) { IDBConnection::PLATFORM_ORACLE => new OCIExpressionBuilder($this->connection, $this, $this->logger), IDBConnection::PLATFORM_POSTGRES => new PgSqlExpressionBuilder($this->connection, $this, $this->logger), @@ -101,23 +69,8 @@ public function expr() { }; } - /** - * Gets an FunctionBuilder used for object-oriented construction of query functions. - * This producer method is intended for convenient inline usage. Example: - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u') - * ->from('users', 'u') - * ->where($qb->fun()->md5('u.id')); - * - * - * For more complex function construction, consider storing the function - * builder object in a local variable. - * - * @return \OCP\DB\QueryBuilder\IFunctionBuilder - */ - public function func() { + #[Override] + public function func(): IFunctionBuilder { return match($this->connection->getDatabaseProvider()) { IDBConnection::PLATFORM_ORACLE => new OCIFunctionBuilder($this->connection, $this, $this->helper), IDBConnection::PLATFORM_POSTGRES => new PgSqlFunctionBuilder($this->connection, $this, $this->helper), @@ -127,37 +80,23 @@ public function func() { }; } - /** - * Gets the type of the currently built query. - * - * @return integer - */ - public function getType() { + #[Override] + public function getType(): int { return $this->queryBuilder->getType(); } - /** - * Gets the associated DBAL Connection for this query builder. - * - * @return \OCP\IDBConnection - */ - public function getConnection() { + #[Override] + public function getConnection(): IDBConnection { return $this->connection; } - /** - * Gets the state of this query builder instance. - * - * @return int Always returns 0 which is former `QueryBuilder::STATE_DIRTY` - * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update - * and we can not fix this in our wrapper. - */ - public function getState() { + #[Override] + public function getState(): int { $this->logger->debug(IQueryBuilder::class . '::' . __FUNCTION__ . ' is deprecated and will be removed soon.', ['exception' => new \Exception('Deprecated call to ' . __METHOD__)]); return $this->queryBuilder->getState(); } - private function prepareForExecute() { + private function prepareForExecute(): void { if ($this->systemConfig->getValue('log_query', false)) { try { $params = []; @@ -253,6 +192,7 @@ private function prepareForExecute() { } } + #[Override] public function executeQuery(?IDBConnection $connection = null): IResult { if ($this->getType() !== \Doctrine\DBAL\Query\QueryBuilder::SELECT) { throw new \RuntimeException('Invalid query type, expected SELECT query'); @@ -270,6 +210,7 @@ public function executeQuery(?IDBConnection $connection = null): IResult { ); } + #[Override] public function executeStatement(?IDBConnection $connection = null): int { if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::SELECT) { throw new \RuntimeException('Invalid query type, expected INSERT, DELETE or UPDATE statement'); @@ -287,181 +228,75 @@ public function executeStatement(?IDBConnection $connection = null): int { ); } - - /** - * Gets the complete SQL string formed by the current specifications of this QueryBuilder. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u') - * ->from('User', 'u') - * echo $qb->getSQL(); // SELECT u FROM User u - * - * - * @return string The SQL query string. - */ - public function getSQL() { + #[Override] + public function getSQL(): string { return $this->queryBuilder->getSQL(); } - /** - * Sets a query parameter for the query being constructed. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u') - * ->from('users', 'u') - * ->where('u.id = :user_id') - * ->setParameter(':user_id', 1); - * - * - * @param string|integer $key The parameter position or name. - * @param mixed $value The parameter value. - * @param string|null|int $type One of the IQueryBuilder::PARAM_* constants. - * - * @return $this This QueryBuilder instance. - */ - public function setParameter($key, $value, $type = null) { + #[Override] + public function setParameter(string|int $key, mixed $value, string|null|int $type = null): self { $this->queryBuilder->setParameter($key, $value, $type); return $this; } - /** - * Sets a collection of query parameters for the query being constructed. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u') - * ->from('users', 'u') - * ->where('u.id = :user_id1 OR u.id = :user_id2') - * ->setParameters(array( - * ':user_id1' => 1, - * ':user_id2' => 2 - * )); - * - * - * @param array $params The query parameters to set. - * @param array $types The query parameters types to set. - * - * @return $this This QueryBuilder instance. - */ - public function setParameters(array $params, array $types = []) { + #[Override] + public function setParameters(array $params, array $types = []): self { $this->queryBuilder->setParameters($params, $types); return $this; } - /** - * Gets all defined query parameters for the query being constructed indexed by parameter index or name. - * - * @return array The currently defined query parameters indexed by parameter index or name. - */ - public function getParameters() { + #[Override] + public function getParameters(): array { return $this->queryBuilder->getParameters(); } - /** - * Gets a (previously set) query parameter of the query being constructed. - * - * @param mixed $key The key (index or name) of the bound parameter. - * - * @return mixed The value of the bound parameter. - */ - public function getParameter($key) { + #[Override] + public function getParameter(int|string $key): mixed { return $this->queryBuilder->getParameter($key); } - /** - * Gets all defined query parameter types for the query being constructed indexed by parameter index or name. - * - * @return array The currently defined query parameter types indexed by parameter index or name. - */ - public function getParameterTypes() { + #[Override] + public function getParameterTypes(): array { return $this->queryBuilder->getParameterTypes(); } - /** - * Gets a (previously set) query parameter type of the query being constructed. - * - * @param mixed $key The key (index or name) of the bound parameter type. - * - * @return mixed The value of the bound parameter type. - */ - public function getParameterType($key) { + #[Override] + public function getParameterType(int|string $key): mixed { return $this->queryBuilder->getParameterType($key); } - /** - * Sets the position of the first result to retrieve (the "offset"). - * - * @param int $firstResult The first result to return. - * - * @return $this This QueryBuilder instance. - */ - public function setFirstResult($firstResult) { - $this->queryBuilder->setFirstResult((int)$firstResult); + #[Override] + public function setFirstResult(int $firstResult): self { + $this->queryBuilder->setFirstResult($firstResult); return $this; } - /** - * Gets the position of the first result the query object was set to retrieve (the "offset"). - * Returns 0 if {@link setFirstResult} was not applied to this QueryBuilder. - * - * @return int The position of the first result. - */ - public function getFirstResult() { + #[Override] + public function getFirstResult(): int { return $this->queryBuilder->getFirstResult(); } - /** - * Sets the maximum number of results to retrieve (the "limit"). - * - * NOTE: Setting max results to "0" will cause mixed behaviour. While most - * of the databases will just return an empty result set, Oracle will return - * all entries. - * - * @param int|null $maxResults The maximum number of results to retrieve. - * - * @return $this This QueryBuilder instance. - */ - public function setMaxResults($maxResults) { + #[Override] + public function setMaxResults(?int $maxResults): self { if ($maxResults === null) { $this->queryBuilder->setMaxResults($maxResults); } else { - $this->queryBuilder->setMaxResults((int)$maxResults); + $this->queryBuilder->setMaxResults($maxResults); } return $this; } - /** - * Gets the maximum number of results the query object was set to retrieve (the "limit"). - * Returns NULL if {@link setMaxResults} was not applied to this query builder. - * - * @return int|null The maximum number of results. - */ - public function getMaxResults() { + #[Override] + public function getMaxResults(): ?int { return $this->queryBuilder->getMaxResults(); } - /** - * Specifies an item that is to be returned in the query result. - * Replaces any previously specified selections, if any. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.id', 'p.id') - * ->from('users', 'u') - * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id'); - * - * - * @param mixed ...$selects The selection expressions. - * - * '@return $this This QueryBuilder instance. - */ - public function select(...$selects) { + #[Override] + public function select(...$selects): self { if (count($selects) === 1 && is_array($selects[0])) { $selects = $selects[0]; } @@ -474,22 +309,8 @@ public function select(...$selects) { return $this; } - /** - * Specifies an item that is to be returned with a different name in the query result. - * - * - * $qb = $conn->getQueryBuilder() - * ->selectAlias('u.id', 'user_id') - * ->from('users', 'u') - * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id'); - * - * - * @param mixed $select The selection expressions. - * @param string $alias The column alias used in the constructed query. - * - * @return $this This QueryBuilder instance. - */ - public function selectAlias($select, $alias) { + #[Override] + public function selectAlias(string|IParameter|IQueryFunction|ILiteral $select, string $alias): self { $this->queryBuilder->addSelect( $this->helper->quoteColumnName($select) . ' AS ' . $this->helper->quoteColumnName($alias) ); @@ -498,20 +319,8 @@ public function selectAlias($select, $alias) { return $this; } - /** - * Specifies an item that is to be returned uniquely in the query result. - * - * - * $qb = $conn->getQueryBuilder() - * ->selectDistinct('type') - * ->from('users'); - * - * - * @param mixed $select The selection expressions. - * - * @return $this This QueryBuilder instance. - */ - public function selectDistinct($select) { + #[Override] + public function selectDistinct(string|array $select): self { if (!is_array($select)) { $select = [$select]; } @@ -526,22 +335,8 @@ public function selectDistinct($select) { return $this; } - /** - * Adds an item that is to be returned in the query result. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.id') - * ->addSelect('p.id') - * ->from('users', 'u') - * ->leftJoin('u', 'phonenumbers', 'u.id = p.user_id'); - * - * - * @param mixed ...$selects The selection expression. - * - * @return $this This QueryBuilder instance. - */ - public function addSelect(...$selects) { + #[Override] + public function addSelect(...$selects): self { if (count($selects) === 1 && is_array($selects[0])) { $selects = $selects[0]; } @@ -570,28 +365,13 @@ private function addOutputColumns(array $columns): void { } } + #[Override] public function getOutputColumns(): array { return array_unique($this->selectedColumns); } - /** - * Turns the query being built into a bulk delete query that ranges over - * a certain table. - * - * - * $qb = $conn->getQueryBuilder() - * ->delete('users', 'u') - * ->where('u.id = :user_id'); - * ->setParameter(':user_id', 1); - * - * - * @param string $delete The table whose rows are subject to the deletion. - * @param string $alias The table alias used in the constructed query. - * - * @return $this This QueryBuilder instance. - * @since 30.0.0 Alias is deprecated and will no longer be used with the next Doctrine/DBAL update - */ - public function delete($delete = null, $alias = null) { + #[Override] + public function delete(string $delete, ?string $alias = null): self { if ($alias !== null) { $this->logger->debug('DELETE queries with alias are no longer supported and the provided alias is ignored', ['exception' => new \InvalidArgumentException('Table alias provided for DELETE query')]); } @@ -604,24 +384,8 @@ public function delete($delete = null, $alias = null) { return $this; } - /** - * Turns the query being built into a bulk update query that ranges over - * a certain table - * - * - * $qb = $conn->getQueryBuilder() - * ->update('users', 'u') - * ->set('u.password', md5('password')) - * ->where('u.id = ?'); - * - * - * @param string $update The table whose rows are subject to the update. - * @param string $alias The table alias used in the constructed query. - * - * @return $this This QueryBuilder instance. - * @since 30.0.0 Alias is deprecated and will no longer be used with the next Doctrine/DBAL update - */ - public function update($update = null, $alias = null) { + #[Override] + public function update(string $update, ?string $alias = null): self { if ($alias !== null) { $this->logger->debug('UPDATE queries with alias are no longer supported and the provided alias is ignored', ['exception' => new \InvalidArgumentException('Table alias provided for UPDATE query')]); } @@ -634,26 +398,8 @@ public function update($update = null, $alias = null) { return $this; } - /** - * Turns the query being built into an insert query that inserts into - * a certain table - * - * - * $qb = $conn->getQueryBuilder() - * ->insert('users') - * ->values( - * array( - * 'name' => '?', - * 'password' => '?' - * ) - * ); - * - * - * @param string $insert The table into which the rows should be inserted. - * - * @return $this This QueryBuilder instance. - */ - public function insert($insert = null) { + #[Override] + public function insert(string $insert): self { $this->queryBuilder->insert( $this->getTableName($insert) ); @@ -663,158 +409,66 @@ public function insert($insert = null) { return $this; } - /** - * Creates and adds a query root corresponding to the table identified by the - * given alias, forming a cartesian product with any existing query roots. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.id') - * ->from('users', 'u') - * - * - * @param string|IQueryFunction $from The table. - * @param string|null $alias The alias of the table. - * - * @return $this This QueryBuilder instance. - */ - public function from($from, $alias = null) { + #[Override] + public function from(string|IQueryFunction $from, ?string $alias = null): self { $this->queryBuilder->from( $this->getTableName($from), - $this->quoteAlias($alias) + $alias ? $this->quoteAlias($alias) : null, ); return $this; } - /** - * Creates and adds a join to the query. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->join('u', 'phonenumbers', 'p', 'p.is_primary = 1'); - * - * - * @param string $fromAlias The alias that points to a from clause. - * @param string $join The table name to join. - * @param string $alias The alias of the join table. - * @param string|ICompositeExpression|null $condition The condition for the join. - * - * @return $this This QueryBuilder instance. - */ - public function join($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function join(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->queryBuilder->join( $this->quoteAlias($fromAlias), $this->getTableName($join), - $this->quoteAlias($alias), + $alias ? $this->quoteAlias($alias) : null, $condition ); return $this; } - /** - * Creates and adds a join to the query. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->innerJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); - * - * - * @param string $fromAlias The alias that points to a from clause. - * @param string $join The table name to join. - * @param string $alias The alias of the join table. - * @param string|ICompositeExpression|null $condition The condition for the join. - * - * @return $this This QueryBuilder instance. - */ - public function innerJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function innerJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->queryBuilder->innerJoin( $this->quoteAlias($fromAlias), $this->getTableName($join), - $this->quoteAlias($alias), + $alias ? $this->quoteAlias($alias) : null, $condition ); return $this; } - /** - * Creates and adds a left join to the query. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->leftJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); - * - * - * @param string $fromAlias The alias that points to a from clause. - * @param string|IQueryFunction $join The table name or sub-query to join. - * @param string $alias The alias of the join table. - * @param string|ICompositeExpression|null $condition The condition for the join. - * - * @return $this This QueryBuilder instance. - */ - public function leftJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function leftJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->queryBuilder->leftJoin( $this->quoteAlias($fromAlias), $this->getTableName($join), - $this->quoteAlias($alias), + $alias ? $this->quoteAlias($alias) : null, $condition ); return $this; } - /** - * Creates and adds a right join to the query. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->rightJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); - * - * - * @param string $fromAlias The alias that points to a from clause. - * @param string $join The table name to join. - * @param string $alias The alias of the join table. - * @param string|ICompositeExpression|null $condition The condition for the join. - * - * @return $this This QueryBuilder instance. - */ - public function rightJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function rightJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { $this->queryBuilder->rightJoin( $this->quoteAlias($fromAlias), $this->getTableName($join), - $this->quoteAlias($alias), + $alias ? $this->quoteAlias($alias) : null, $condition ); return $this; } - /** - * Sets a new value for a column in a bulk update query. - * - * - * $qb = $conn->getQueryBuilder() - * ->update('users', 'u') - * ->set('u.password', md5('password')) - * ->where('u.id = ?'); - * - * - * @param string $key The column to set. - * @param ILiteral|IParameter|IQueryFunction|string $value The value, expression, placeholder, etc. - * - * @return $this This QueryBuilder instance. - */ - public function set($key, $value) { + #[Override] + public function set(string $key, ILiteral|IParameter|IQueryFunction|string $value): self { $this->queryBuilder->set( $this->helper->quoteColumnName($key), $this->helper->quoteColumnName($value) @@ -823,34 +477,8 @@ public function set($key, $value) { return $this; } - /** - * Specifies one or more restrictions to the query result. - * Replaces any previously specified restrictions, if any. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->where('u.id = ?'); - * - * // You can optionally programmatically build and/or expressions - * $qb = $conn->getQueryBuilder(); - * - * $or = $qb->expr()->orx( - * $qb->expr()->eq('u.id', 1), - * $qb->expr()->eq('u.id', 2), - * ); - * - * $qb->update('users', 'u') - * ->set('u.password', md5('password')) - * ->where($or); - * - * - * @param mixed ...$predicates The restriction predicates. - * - * @return $this This QueryBuilder instance. - */ - public function where(...$predicates) { + #[Override] + public function where(...$predicates): self { if ($this->nonEmptyWhere && $this->systemConfig->getValue('debug', false)) { // Only logging a warning, not throwing for now. $e = new QueryException('Using where() on non-empty WHERE part, please verify it is intentional to not call andWhere() or orWhere() instead. Otherwise consider creating a new query builder object or call resetQueryPart(\'where\') first.'); @@ -867,25 +495,8 @@ public function where(...$predicates) { return $this; } - /** - * Adds one or more restrictions to the query results, forming a logical - * conjunction with any previously specified restrictions. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u') - * ->from('users', 'u') - * ->where('u.username LIKE ?') - * ->andWhere('u.is_active = 1'); - * - * - * @param mixed ...$where The query restrictions. - * - * @return $this This QueryBuilder instance. - * - * @see where() - */ - public function andWhere(...$where) { + #[Override] + public function andWhere(...$where): self { $this->nonEmptyWhere = true; call_user_func_array( [$this->queryBuilder, 'andWhere'], @@ -895,25 +506,8 @@ public function andWhere(...$where) { return $this; } - /** - * Adds one or more restrictions to the query results, forming a logical - * disjunction with any previously specified restrictions. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->where('u.id = 1') - * ->orWhere('u.id = 2'); - * - * - * @param mixed ...$where The WHERE statement. - * - * @return $this This QueryBuilder instance. - * - * @see where() - */ - public function orWhere(...$where) { + #[Override] + public function orWhere(...$where): self { $this->nonEmptyWhere = true; call_user_func_array( [$this->queryBuilder, 'orWhere'], @@ -923,22 +517,8 @@ public function orWhere(...$where) { return $this; } - /** - * Specifies a grouping over the results of the query. - * Replaces any previously specified groupings, if any. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->groupBy('u.id'); - * - * - * @param mixed ...$groupBys The grouping expression. - * - * @return $this This QueryBuilder instance. - */ - public function groupBy(...$groupBys) { + #[Override] + public function groupBy(...$groupBys): self { if (count($groupBys) === 1 && is_array($groupBys[0])) { $groupBys = $groupBys[0]; } @@ -951,22 +531,8 @@ public function groupBy(...$groupBys) { return $this; } - /** - * Adds a grouping expression to the query. - * - * - * $qb = $conn->getQueryBuilder() - * ->select('u.name') - * ->from('users', 'u') - * ->groupBy('u.lastLogin'); - * ->addGroupBy('u.createdAt') - * - * - * @param mixed ...$groupBy The grouping expression. - * - * @return $this This QueryBuilder instance. - */ - public function addGroupBy(...$groupBy) { + #[Override] + public function addGroupBy(...$groupBy): self { call_user_func_array( [$this->queryBuilder, 'addGroupBy'], $this->helper->quoteColumnNames($groupBy) @@ -975,26 +541,8 @@ public function addGroupBy(...$groupBy) { return $this; } - /** - * Sets a value for a column in an insert query. - * - * - * $qb = $conn->getQueryBuilder() - * ->insert('users') - * ->values( - * array( - * 'name' => '?' - * ) - * ) - * ->setValue('password', '?'); - * - * - * @param string $column The column into which the value should be inserted. - * @param IParameter|string $value The value that should be inserted into the column. - * - * @return $this This QueryBuilder instance. - */ - public function setValue($column, $value) { + #[Override] + public function setValue(string $column, ILiteral|IParameter|IQueryFunction|string $value): self { $this->queryBuilder->setValue( $this->helper->quoteColumnName($column), (string)$value @@ -1003,26 +551,8 @@ public function setValue($column, $value) { return $this; } - /** - * Specifies values for an insert query indexed by column names. - * Replaces any previous values, if any. - * - * - * $qb = $conn->getQueryBuilder() - * ->insert('users') - * ->values( - * array( - * 'name' => '?', - * 'password' => '?' - * ) - * ); - * - * - * @param array $values The values to specify for the insert query indexed by column names. - * - * @return $this This QueryBuilder instance. - */ - public function values(array $values) { + #[Override] + public function values(array $values): self { $quotedValues = []; foreach ($values as $key => $value) { $quotedValues[$this->helper->quoteColumnName($key)] = $value; @@ -1033,15 +563,8 @@ public function values(array $values) { return $this; } - /** - * Specifies a restriction over the groups of the query. - * Replaces any previous having restrictions, if any. - * - * @param mixed ...$having The restriction over the groups. - * - * @return $this This QueryBuilder instance. - */ - public function having(...$having) { + #[Override] + public function having(...$having): self { call_user_func_array( [$this->queryBuilder, 'having'], $having @@ -1050,15 +573,8 @@ public function having(...$having) { return $this; } - /** - * Adds a restriction over the groups of the query, forming a logical - * conjunction with any existing having restrictions. - * - * @param mixed ...$having The restriction to append. - * - * @return $this This QueryBuilder instance. - */ - public function andHaving(...$having) { + #[Override] + public function andHaving(...$having): self { call_user_func_array( [$this->queryBuilder, 'andHaving'], $having @@ -1067,15 +583,8 @@ public function andHaving(...$having) { return $this; } - /** - * Adds a restriction over the groups of the query, forming a logical - * disjunction with any existing having restrictions. - * - * @param mixed ...$having The restriction to add. - * - * @return $this This QueryBuilder instance. - */ - public function orHaving(...$having) { + #[Override] + public function orHaving(...$having): self { call_user_func_array( [$this->queryBuilder, 'orHaving'], $having @@ -1084,17 +593,9 @@ public function orHaving(...$having) { return $this; } - /** - * Specifies an ordering for the query results. - * Replaces any previously specified orderings, if any. - * - * @param string|IQueryFunction|ILiteral|IParameter $sort The ordering expression. - * @param string $order The ordering direction. - * - * @return $this This QueryBuilder instance. - */ - public function orderBy($sort, $order = null) { - if ($order !== null && !in_array(strtoupper((string)$order), ['ASC', 'DESC'], true)) { + #[Override] + public function orderBy(string|ILiteral|IParameter|IQueryFunction $sort, ?string $order = null): self { + if ($order !== null && !in_array(strtoupper($order), ['ASC', 'DESC'], true)) { $order = null; } @@ -1106,16 +607,9 @@ public function orderBy($sort, $order = null) { return $this; } - /** - * Adds an ordering to the query results. - * - * @param string|ILiteral|IParameter|IQueryFunction $sort The ordering expression. - * @param string $order The ordering direction. - * - * @return $this This QueryBuilder instance. - */ - public function addOrderBy($sort, $order = null) { - if ($order !== null && !in_array(strtoupper((string)$order), ['ASC', 'DESC'], true)) { + #[Override] + public function addOrderBy(string|ILiteral|IParameter|IQueryFunction $sort, ?string $order = null): self { + if ($order !== null && !in_array(strtoupper($order), ['ASC', 'DESC'], true)) { $order = null; } @@ -1127,177 +621,57 @@ public function addOrderBy($sort, $order = null) { return $this; } - /** - * Gets a query part by its name. - * - * @param string $queryPartName - * - * @return mixed - * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update - * and we can not fix this in our wrapper. Please track the details you need, outside the object. - */ - public function getQueryPart($queryPartName) { + #[Override] + public function getQueryPart(string $queryPartName): mixed { $this->logger->debug(IQueryBuilder::class . '::' . __FUNCTION__ . ' is deprecated and will be removed soon.', ['exception' => new \Exception('Deprecated call to ' . __METHOD__)]); return $this->queryBuilder->getQueryPart($queryPartName); } - /** - * Gets all query parts. - * - * @return array - * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update - * and we can not fix this in our wrapper. Please track the details you need, outside the object. - */ - public function getQueryParts() { + #[Override] + public function getQueryParts(): array { $this->logger->debug(IQueryBuilder::class . '::' . __FUNCTION__ . ' is deprecated and will be removed soon.', ['exception' => new \Exception('Deprecated call to ' . __METHOD__)]); return $this->queryBuilder->getQueryParts(); } - /** - * Resets SQL parts. - * - * @param array|null $queryPartNames - * - * @return $this This QueryBuilder instance. - * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update - * and we can not fix this in our wrapper. Please create a new IQueryBuilder instead. - */ - public function resetQueryParts($queryPartNames = null) { + #[Override] + public function resetQueryParts(?array $queryPartNames = null): self { $this->logger->debug(IQueryBuilder::class . '::' . __FUNCTION__ . ' is deprecated and will be removed soon.', ['exception' => new \Exception('Deprecated call to ' . __METHOD__)]); $this->queryBuilder->resetQueryParts($queryPartNames); return $this; } - /** - * Resets a single SQL part. - * - * @param string $queryPartName - * - * @return $this This QueryBuilder instance. - * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update - * and we can not fix this in our wrapper. Please create a new IQueryBuilder instead. - */ - public function resetQueryPart($queryPartName) { + #[Override] + public function resetQueryPart(string $queryPartName): self { $this->logger->debug(IQueryBuilder::class . '::' . __FUNCTION__ . ' is deprecated and will be removed soon.', ['exception' => new \Exception('Deprecated call to ' . __METHOD__)]); $this->queryBuilder->resetQueryPart($queryPartName); return $this; } - /** - * Creates a new named parameter and bind the value $value to it. - * - * This method provides a shortcut for PDOStatement::bindValue - * when using prepared statements. - * - * The parameter $value specifies the value that you want to bind. If - * $placeholder is not provided bindValue() will automatically create a - * placeholder for you. An automatic placeholder will be of the name - * ':dcValue1', ':dcValue2' etc. - * - * For more information see {@link https://www.php.net/pdostatement-bindparam} - * - * Example: - * - * $value = 2; - * $q->eq( 'id', $q->bindValue( $value ) ); - * $stmt = $q->executeQuery(); // executed with 'id = 2' - * - * - * @license New BSD License - * @link http://www.zetacomponents.org - * - * @param mixed $value - * @param IQueryBuilder::PARAM_* $type - * @param string $placeHolder The name to bind with. The string must start with a colon ':'. - * - * @return IParameter the placeholder name used. - */ - public function createNamedParameter($value, $type = IQueryBuilder::PARAM_STR, $placeHolder = null) { + #[Override] + public function createNamedParameter(mixed $value, mixed $type = IQueryBuilder::PARAM_STR, ?string $placeHolder = null): IParameter { return new Parameter($this->queryBuilder->createNamedParameter($value, $type, $placeHolder)); } - /** - * Creates a new positional parameter and bind the given value to it. - * - * Attention: If you are using positional parameters with the query builder you have - * to be very careful to bind all parameters in the order they appear in the SQL - * statement , otherwise they get bound in the wrong order which can lead to serious - * bugs in your code. - * - * Example: - * - * $qb = $conn->getQueryBuilder(); - * $qb->select('u.*') - * ->from('users', 'u') - * ->where('u.username = ' . $qb->createPositionalParameter('Foo', IQueryBuilder::PARAM_STR)) - * ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', IQueryBuilder::PARAM_STR)) - * - * - * @param mixed $value - * @param IQueryBuilder::PARAM_* $type - * - * @return IParameter - */ - public function createPositionalParameter($value, $type = IQueryBuilder::PARAM_STR) { + #[Override] + public function createPositionalParameter(mixed $value, mixed $type = IQueryBuilder::PARAM_STR): IParameter { return new Parameter($this->queryBuilder->createPositionalParameter($value, $type)); } - /** - * Creates a new parameter - * - * Example: - * - * $qb = $conn->getQueryBuilder(); - * $qb->select('u.*') - * ->from('users', 'u') - * ->where('u.username = ' . $qb->createParameter('name')) - * ->setParameter('name', 'Bar', IQueryBuilder::PARAM_STR)) - * - * - * @param string $name - * - * @return IParameter - */ - public function createParameter($name) { + #[Override] + public function createParameter(string $name): IParameter { return new Parameter(':' . $name); } - /** - * Creates a new function - * - * Attention: Column names inside the call have to be quoted before hand - * - * Example: - * - * $qb = $conn->getQueryBuilder(); - * $qb->select($qb->createFunction('COUNT(*)')) - * ->from('users', 'u') - * echo $qb->getSQL(); // SELECT COUNT(*) FROM `users` u - * - * - * $qb = $conn->getQueryBuilder(); - * $qb->select($qb->createFunction('COUNT(`column`)')) - * ->from('users', 'u') - * echo $qb->getSQL(); // SELECT COUNT(`column`) FROM `users` u - * - * - * @param string $call - * - * @return IQueryFunction - */ - public function createFunction($call) { + #[Override] + public function createFunction(string $call): IQueryFunction { return new QueryFunction($call); } - /** - * Used to get the id of the last inserted element - * @return int - * @throws \BadMethodCallException When being called before an insert query has been run. - */ + #[Override] public function getLastInsertId(): int { - if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && $this->lastInsertedTable) { + if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && $this->lastInsertedTable !== null) { // lastInsertId() needs the prefix but no quotes $table = $this->prefixTableName($this->lastInsertedTable); return $this->connection->lastInsertId($table); @@ -1306,13 +680,8 @@ public function getLastInsertId(): int { throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.'); } - /** - * Returns the table name quoted and with database prefix as needed by the implementation - * - * @param string|IQueryFunction $table - * @return string - */ - public function getTableName($table) { + #[Override] + public function getTableName(string|IQueryFunction $table): string { if ($table instanceof IQueryFunction) { return (string)$table; } @@ -1321,14 +690,7 @@ public function getTableName($table) { return $this->helper->quoteColumnName($table); } - /** - * Returns the table name with database prefix as needed by the implementation - * - * Was protected until version 30. - * - * @param string $table - * @return string - */ + #[Override] public function prefixTableName(string $table): string { if ($this->automaticTablePrefix === false || str_starts_with($table, '*PREFIX*')) { return $table; @@ -1337,14 +699,8 @@ public function prefixTableName(string $table): string { return '*PREFIX*' . $table; } - /** - * Returns the column name quoted and with table alias prefix as needed by the implementation - * - * @param string $column - * @param string $tableAlias - * @return string - */ - public function getColumnName($column, $tableAlias = '') { + #[Override] + public function getColumnName(string $column, string $tableAlias = ''): string { if ($tableAlias !== '') { $tableAlias .= '.'; } @@ -1352,14 +708,8 @@ public function getColumnName($column, $tableAlias = '') { return $this->helper->quoteColumnName($tableAlias . $column); } - /** - * Returns the column name quoted and with table alias prefix as needed by the implementation - * - * @param string $alias - * @return string - */ - public function quoteAlias($alias) { - if ($alias === '' || $alias === null) { + public function quoteAlias(string $alias): string { + if ($alias === '') { return $alias; } @@ -1370,10 +720,12 @@ public function escapeLikeParameter(string $parameter): string { return $this->connection->escapeLikeParameter($parameter); } + #[Override] public function hintShardKey(string $column, mixed $value, bool $overwrite = false): self { return $this; } + #[Override] public function runAcrossAllShards(): self { // noop return $this; diff --git a/lib/private/DB/QueryBuilder/QuoteHelper.php b/lib/private/DB/QueryBuilder/QuoteHelper.php index 7ce4b359638d4..168fb49d89f7d 100644 --- a/lib/private/DB/QueryBuilder/QuoteHelper.php +++ b/lib/private/DB/QueryBuilder/QuoteHelper.php @@ -12,11 +12,7 @@ use OCP\DB\QueryBuilder\IQueryFunction; class QuoteHelper { - /** - * @param array|string|ILiteral|IParameter|IQueryFunction $strings string, Literal or Parameter - * @return array|string - */ - public function quoteColumnNames($strings) { + public function quoteColumnNames(array|string|ILiteral|IParameter|IQueryFunction $strings): array|string { if (!is_array($strings)) { return $this->quoteColumnName($strings); } @@ -29,26 +25,18 @@ public function quoteColumnNames($strings) { return $return; } - /** - * @param string|ILiteral|IParameter|IQueryFunction $string string, Literal or Parameter - * @return string - */ - public function quoteColumnName($string) { + public function quoteColumnName(string|ILiteral|IParameter|IQueryFunction $string): string { if ($string instanceof IParameter || $string instanceof ILiteral || $string instanceof IQueryFunction) { return (string)$string; } - if ($string === null || $string === 'null' || $string === '*') { + if ($string === 'null' || $string === '*') { return $string; } - if (!is_string($string)) { - throw new \InvalidArgumentException('Only strings, Literals and Parameters are allowed'); - } - $string = str_replace(' AS ', ' as ', $string); if (substr_count($string, ' as ')) { - return implode(' as ', array_map([$this, 'quoteColumnName'], explode(' as ', $string, 2))); + return implode(' as ', array_map($this->quoteColumnName(...), explode(' as ', $string, 2))); } if (substr_count($string, '.')) { diff --git a/lib/private/DB/QueryBuilder/Sharded/ShardedQueryBuilder.php b/lib/private/DB/QueryBuilder/Sharded/ShardedQueryBuilder.php index 2694a116af43f..dd558885f33e6 100644 --- a/lib/private/DB/QueryBuilder/Sharded/ShardedQueryBuilder.php +++ b/lib/private/DB/QueryBuilder/Sharded/ShardedQueryBuilder.php @@ -12,8 +12,13 @@ use OC\DB\QueryBuilder\ExtendedQueryBuilder; use OC\DB\QueryBuilder\Parameter; use OCP\DB\IResult; +use OCP\DB\QueryBuilder\ICompositeExpression; +use OCP\DB\QueryBuilder\ILiteral; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\QueryBuilder\IQueryFunction; use OCP\IDBConnection; +use Override; /** * A special query builder that automatically distributes queries over multiple database shards. @@ -83,11 +88,13 @@ private function getKeyValue($value): array { } } - public function where(...$predicates) { + #[Override] + public function where(...$predicates): self { return $this->andWhere(...$predicates); } - public function andWhere(...$where) { + #[Override] + public function andWhere(...$where): self { if ($where) { foreach ($where as $predicate) { $this->tryLoadShardKey($predicate); @@ -158,14 +165,18 @@ private function tryExtractShardKeys($predicate, string $column): array { return []; } - public function set($key, $value) { + #[Override] + public function set($key, $value): self { if ($this->shardDefinition && $key === $this->shardDefinition->shardKey) { + // TODO dead code? $updateShardKey = $value; } - return parent::set($key, $value); + parent::set($key, $value); + return $this; } - public function setValue($column, $value) { + #[Override] + public function setValue(string $column, ILiteral|IParameter|IQueryFunction|string $value): self { if ($this->shardDefinition) { if ($this->shardDefinition->isKey($column)) { $this->primaryKeys[] = $value; @@ -174,10 +185,12 @@ public function setValue($column, $value) { $this->shardKeys[] = $value; } } - return parent::setValue($column, $value); + parent::setValue($column, $value); + return $this; } - public function values(array $values) { + #[Override] + public function values(array $values): self { foreach ($values as $column => $value) { $this->setValue($column, $value); } @@ -193,33 +206,35 @@ private function actOnTable(string $table): void { } } - public function from($from, $alias = null) { - if (is_string($from) && $from) { + #[Override] + public function from(string|IQueryFunction $from, ?string $alias = null): self { + if (is_string($from)) { $this->actOnTable($from); } - return parent::from($from, $alias); + parent::from($from, $alias); + return $this; } - public function update($update = null, $alias = null) { - if (is_string($update) && $update) { - $this->actOnTable($update); - } - return parent::update($update, $alias); + #[Override] + public function update(string $update, ?string $alias = null): self { + $this->actOnTable($update); + parent::update($update, $alias); + return $this; } - public function insert($insert = null) { - if (is_string($insert) && $insert) { - $this->insertTable = $insert; - $this->actOnTable($insert); - } - return parent::insert($insert); + #[Override] + public function insert(string $insert): self { + $this->insertTable = $insert; + $this->actOnTable($insert); + parent::insert($insert); + return $this; } - public function delete($delete = null, $alias = null) { - if (is_string($delete) && $delete) { - $this->actOnTable($delete); - } - return parent::delete($delete, $alias); + #[Override] + public function delete(string $delete, ?string $alias = null): self { + $this->actOnTable($delete); + parent::delete($delete, $alias); + return $this; } private function checkJoin(string $table): void { @@ -235,67 +250,82 @@ private function checkJoin(string $table): void { } } - public function innerJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function innerJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { if (is_string($join)) { $this->checkJoin($join); } - return parent::innerJoin($fromAlias, $join, $alias, $condition); + parent::innerJoin($fromAlias, $join, $alias, $condition); + return $this; } - public function leftJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function leftJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { if (is_string($join)) { $this->checkJoin($join); } - return parent::leftJoin($fromAlias, $join, $alias, $condition); + parent::leftJoin($fromAlias, $join, $alias, $condition); + return $this; } - public function rightJoin($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function rightJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { if ($this->shardDefinition) { throw new InvalidShardedQueryException("Sharded query on {$this->shardDefinition->table} isn't allowed to right join"); } - return parent::rightJoin($fromAlias, $join, $alias, $condition); + parent::rightJoin($fromAlias, $join, $alias, $condition); + return $this; } - public function join($fromAlias, $join, $alias, $condition = null) { + #[Override] + public function join(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self { return $this->innerJoin($fromAlias, $join, $alias, $condition); } - public function setMaxResults($maxResults) { - if ($maxResults > 0) { - $this->limit = (int)$maxResults; + #[Override] + public function setMaxResults(?int $maxResults): self { + if ($maxResults !== null && $maxResults > 0) { + $this->limit = $maxResults; } - return parent::setMaxResults($maxResults); + parent::setMaxResults($maxResults); + return $this; } - public function setFirstResult($firstResult) { + #[Override] + public function setFirstResult(int $firstResult): self { if ($firstResult > 0) { - $this->offset = (int)$firstResult; + $this->offset = $firstResult; } if ($this->shardDefinition && count($this->shardDefinition->shards) > 1) { // we have to emulate offset return $this; } else { - return parent::setFirstResult($firstResult); + parent::setFirstResult($firstResult); + return $this; } } - public function addOrderBy($sort, $order = null) { + #[Override] + public function addOrderBy($sort, $order = null): self { if ($order !== null && !in_array(strtoupper((string)$order), ['ASC', 'DESC'], true)) { $order = null; } $this->registerOrder((string)$sort, (string)($order ?? 'ASC')); - return parent::addOrderBy($sort, $order); + parent::addOrderBy($sort, $order); + return $this; } - public function orderBy($sort, $order = null) { + #[Override] + public function orderBy($sort, $order = null): self { if ($order !== null && !in_array(strtoupper((string)$order), ['ASC', 'DESC'], true)) { $order = null; } $this->sortList = []; $this->registerOrder((string)$sort, (string)($order ?? 'ASC')); - return parent::orderBy($sort, $order); + parent::orderBy($sort, $order); + return $this; } private function registerOrder(string $column, string $order): void { @@ -308,6 +338,7 @@ private function registerOrder(string $column, string $order): void { ]; } + #[Override] public function hintShardKey(string $column, mixed $value, bool $overwrite = false): self { if ($overwrite) { $this->primaryKeys = []; @@ -322,6 +353,7 @@ public function hintShardKey(string $column, mixed $value, bool $overwrite = fal return $this; } + #[Override] public function runAcrossAllShards(): self { $this->allShards = true; return $this; @@ -364,6 +396,7 @@ public function validate(): void { } } + #[Override] public function executeQuery(?IDBConnection $connection = null): IResult { $this->validate(); if ($this->shardDefinition) { @@ -373,6 +406,7 @@ public function executeQuery(?IDBConnection $connection = null): IResult { return parent::executeQuery($connection); } + #[Override] public function executeStatement(?IDBConnection $connection = null): int { $this->validate(); if ($this->shardDefinition) { @@ -403,6 +437,7 @@ public function executeStatement(?IDBConnection $connection = null): int { return parent::executeStatement($connection); } + #[Override] public function getLastInsertId(): int { if ($this->lastInsertId) { return $this->lastInsertId; @@ -414,6 +449,4 @@ public function getLastInsertId(): int { return parent::getLastInsertId(); } } - - } diff --git a/lib/private/Files/Cache/CacheQueryBuilder.php b/lib/private/Files/Cache/CacheQueryBuilder.php index 5492452273bba..03474261048cc 100644 --- a/lib/private/Files/Cache/CacheQueryBuilder.php +++ b/lib/private/Files/Cache/CacheQueryBuilder.php @@ -45,7 +45,7 @@ public function selectTagUsage(): self { return $this; } - public function selectFileCache(?string $alias = null, bool $joinExtendedCache = true) { + public function selectFileCache(?string $alias = null, bool $joinExtendedCache = true): self { $name = $alias ?: 'filecache'; $this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", "$name.name", 'mimetype', 'mimepart', 'size', 'mtime', 'storage_mtime', 'encrypted', "$name.etag", "$name.permissions", 'checksum', 'unencrypted_size') @@ -61,13 +61,13 @@ public function selectFileCache(?string $alias = null, bool $joinExtendedCache = return $this; } - public function whereStorageId(int $storageId) { + public function whereStorageId(int $storageId): self { $this->andWhere($this->expr()->eq('storage', $this->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); return $this; } - public function whereFileId(int $fileId) { + public function whereFileId(int $fileId): self { $alias = $this->alias; if ($alias) { $alias .= '.'; @@ -86,7 +86,7 @@ public function wherePath(string $path) { return $this; } - public function whereParent(int $parent) { + public function whereParent(int $parent): self { $alias = $this->alias; if ($alias) { $alias .= '.'; @@ -99,7 +99,7 @@ public function whereParent(int $parent) { return $this; } - public function whereParentInParameter(string $parameter) { + public function whereParentInParameter(string $parameter): self { $alias = $this->alias; if ($alias) { $alias .= '.'; diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php index 314882479399a..5ea9b2f2349dd 100644 --- a/lib/private/User/Database.php +++ b/lib/private/User/Database.php @@ -289,7 +289,7 @@ public function getDisplayNames($search = '', $limit = null, $offset = null) { ->orderBy($query->func()->lower('displayname'), 'ASC') ->addOrderBy('uid_lower', 'ASC') ->setMaxResults($limit) - ->setFirstResult($offset); + ->setFirstResult($offset ?? 0); $result = $query->executeQuery(); $displayNames = []; diff --git a/lib/public/DB/QueryBuilder/IExpressionBuilder.php b/lib/public/DB/QueryBuilder/IExpressionBuilder.php index 12e30a45071b7..f8f11ea87d88b 100644 --- a/lib/public/DB/QueryBuilder/IExpressionBuilder.php +++ b/lib/public/DB/QueryBuilder/IExpressionBuilder.php @@ -8,6 +8,7 @@ namespace OCP\DB\QueryBuilder; use Doctrine\DBAL\Query\Expression\ExpressionBuilder; +use OCP\AppFramework\Attribute\Consumable; /** * This class provides a wrapper around Doctrine's ExpressionBuilder @@ -15,6 +16,7 @@ * * @psalm-taint-specialize */ +#[Consumable(since: '8.2.0')] interface IExpressionBuilder { /** * @since 9.0.0 @@ -84,9 +86,9 @@ public function orX(...$x): ICompositeExpression; /** * Creates a comparison expression. * - * @param mixed $x The left expression. + * @param string|ILiteral|IQueryFunction|IParameter $x The left expression. * @param string $operator One of the IExpressionBuilder::* constants. - * @param mixed $y The right expression. + * @param string|ILiteral|IQueryFunction|IParameter $y The right expression. * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants * required when comparing text fields for oci compatibility * @@ -98,7 +100,7 @@ public function orX(...$x): ICompositeExpression; * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function comparison($x, string $operator, $y, $type = null): string; + public function comparison(string|ILiteral|IQueryFunction|IParameter $x, string $operator, string|ILiteral|IQueryFunction|IParameter $y, string|int|null $type = null): string; /** * Creates an equality comparison expression with the given arguments. @@ -110,33 +112,32 @@ public function comparison($x, string $operator, $y, $type = null): string; * // u.id = ? * $expr->eq('u.id', '?'); * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param string|ILiteral|IQueryFunction|IParameter $x The left expression. + * @param string|ILiteral|IQueryFunction|IParameter $y The right expression. + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * - * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 * * @psalm-taint-sink sql $x * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function eq($x, $y, $type = null): string; + public function eq(string|ILiteral|IQueryFunction|IParameter $x, string|ILiteral|IQueryFunction|IParameter $y, string|int|null $type = null): string; /** * Creates a non equality comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a <> . Example: + * When converted to string, it will generate a <> . Example: * * [php] * // u.id <> 1 * $q->where($q->expr()->neq('u.id', '1')); * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param string|ILiteral|IQueryFunction|IParameter $x The left expression. + * @param string|ILiteral|IQueryFunction|IParameter $y The right expression. + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 @@ -145,21 +146,21 @@ public function eq($x, $y, $type = null): string; * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function neq($x, $y, $type = null): string; + public function neq(string|ILiteral|IQueryFunction|IParameter $x, string|ILiteral|IQueryFunction|IParameter $y, string|int|null $type = null): string; /** * Creates a lower-than comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a < . Example: + * When converted to string, it will generate a < . Example: * * [php] * // u.id < ? * $q->where($q->expr()->lt('u.id', '?')); * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param string|ILiteral|IQueryFunction|IParameter $x The left expression. + * @param string|ILiteral|IQueryFunction|IParameter $y The right expression. + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 @@ -168,35 +169,34 @@ public function neq($x, $y, $type = null): string; * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function lt($x, $y, $type = null): string; + public function lt(string|ILiteral|IQueryFunction|IParameter $x, string|ILiteral|IQueryFunction|IParameter $y, string|int|null $type = null): string; /** * Creates a lower-than-equal comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a <= . Example: + * When converted to string, it will generate a <= . Example: * * [php] * // u.id <= ? * $q->where($q->expr()->lte('u.id', '?')); * - * @param mixed $x The left expression. - * @param mixed $y The right expression. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param string|ILiteral|IQueryFunction|IParameter $x The left expression. + * @param string|ILiteral|IQueryFunction|IParameter $y The right expression. + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * - * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 * * @psalm-taint-sink sql $x * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function lte($x, $y, $type = null): string; + public function lte(string|ILiteral|IQueryFunction|IParameter $x, string|ILiteral|IQueryFunction|IParameter $y, string|int|null $type = null): string; /** * Creates a greater-than comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a > . Example: + * When converted to string, it will generate a > . Example: * * [php] * // u.id > ? @@ -219,7 +219,7 @@ public function gt($x, $y, $type = null): string; /** * Creates a greater-than-equal comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. - * When converted to string, it will generated a >= . Example: + * When converted to string, it will generate a >= . Example: * * [php] * // u.id >= ? @@ -237,7 +237,7 @@ public function gt($x, $y, $type = null): string; * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function gte($x, $y, $type = null): string; + public function gte(string|ILiteral|IParameter|IQueryFunction $x, string|ILiteral|IParameter|IQueryFunction $y, mixed $type = null): string; /** * Creates an IS NULL expression with the given arguments. @@ -249,44 +249,42 @@ public function gte($x, $y, $type = null): string; * * @psalm-taint-sink sql $x */ - public function isNull($x): string; + public function isNull(string|ILiteral|IParameter|IQueryFunction $x): string; /** * Creates an IS NOT NULL expression with the given arguments. * * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be restricted by IS NOT NULL. * - * @return string * @since 8.2.0 * * @psalm-taint-sink sql $x */ - public function isNotNull($x): string; + public function isNotNull(string|ILiteral|IParameter|IQueryFunction $x): string; /** * Creates a LIKE() comparison expression with the given arguments. * * @param ILiteral|IParameter|IQueryFunction|string $x Field in string format to be inspected by LIKE() comparison. * @param mixed $y Argument to be used in LIKE() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * - * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 * * @psalm-taint-sink sql $x * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function like($x, $y, $type = null): string; + public function like(ILiteral|IParameter|IQueryFunction|string $x, mixed $y, mixed $type = null): string; /** * Creates a NOT LIKE() comparison expression with the given arguments. * * @param ILiteral|IParameter|IQueryFunction|string $x Field in string format to be inspected by NOT LIKE() comparison. * @param mixed $y Argument to be used in NOT LIKE() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 @@ -295,15 +293,15 @@ public function like($x, $y, $type = null): string; * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function notLike($x, $y, $type = null): string; + public function notLike(ILiteral|IParameter|IQueryFunction|string $x, mixed $y, mixed $type = null): string; /** * Creates a ILIKE() comparison expression with the given arguments. * - * @param string $x Field in string format to be inspected by ILIKE() comparison. + * @param string|IParameter|ILiteral|IQueryFunction $x Field in string format to be inspected by ILIKE() comparison. * @param mixed $y Argument to be used in ILIKE() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * * @return string * @since 9.0.0 @@ -312,32 +310,31 @@ public function notLike($x, $y, $type = null): string; * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function iLike($x, $y, $type = null): string; + public function iLike(string|IParameter|ILiteral|IQueryFunction $x, mixed $y, mixed $type = null): string; /** * Creates a IN () comparison expression with the given arguments. * * @param ILiteral|IParameter|IQueryFunction|string $x The field in string format to be inspected by IN() comparison. * @param ILiteral|IParameter|IQueryFunction|string|array $y The placeholder or the array of values to be used by IN() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * - * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 * * @psalm-taint-sink sql $x * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function in($x, $y, $type = null): string; + public function in(ILiteral|IParameter|IQueryFunction|string $x, ILiteral|IParameter|IQueryFunction|string|array $y, $type = null): string; /** * Creates a NOT IN () comparison expression with the given arguments. * * @param ILiteral|IParameter|IQueryFunction|string $x The field in string format to be inspected by NOT IN() comparison. * @param ILiteral|IParameter|IQueryFunction|string|array $y The placeholder or the array of values to be used by NOT IN() comparison. - * @param mixed|null $type one of the IQueryBuilder::PARAM_* constants - * required when comparing text fields for oci compatibility + * @param IQueryBuilder::PARAM_*|null $type one of the IQueryBuilder::PARAM_* constants + * required when comparing text fields for oci compatibility * * @return string * @since 8.2.0 - Parameter $type was added in 9.0.0 @@ -346,29 +343,27 @@ public function in($x, $y, $type = null): string; * @psalm-taint-sink sql $y * @psalm-taint-sink sql $type */ - public function notIn($x, $y, $type = null): string; + public function notIn(ILiteral|IParameter|IQueryFunction|string $x, ILiteral|IParameter|IQueryFunction|string|array $y, mixed $type = null): string; /** - * Creates a $x = '' statement, because Oracle needs a different check + * Creates a `$x = ''` statement, because Oracle needs a different check * * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be inspected by the comparison. - * @return string * @since 13.0.0 * * @psalm-taint-sink sql $x */ - public function emptyString($x): string; + public function emptyString(string|ILiteral|IParameter|IQueryFunction $x): string; /** * Creates a `$x <> ''` statement, because Oracle needs a different check * * @param string|ILiteral|IParameter|IQueryFunction $x The field in string format to be inspected by the comparison. - * @return string * @since 13.0.0 * * @psalm-taint-sink sql $x */ - public function nonEmptyString($x): string; + public function nonEmptyString(string|ILiteral|IParameter|IQueryFunction $x): string; /** @@ -382,46 +377,41 @@ public function nonEmptyString($x): string; * @psalm-taint-sink sql $x * @psalm-taint-sink sql $y */ - public function bitwiseAnd($x, int $y): IQueryFunction; + public function bitwiseAnd(string|ILiteral $x, int $y): IQueryFunction; /** * Creates a bitwise OR comparison * * @param string|ILiteral $x The field or value to check * @param int $y Bitmap that must be set - * @return IQueryFunction * @since 12.0.0 * * @psalm-taint-sink sql $x * @psalm-taint-sink sql $y */ - public function bitwiseOr($x, int $y): IQueryFunction; + public function bitwiseOr(string|ILiteral $x, int $y): IQueryFunction; /** * Quotes a given input parameter. * * @param mixed $input The parameter to be quoted. - * @param int $type One of the IQueryBuilder::PARAM_* constants + * @param IQueryBuilder::PARAM_* $type One of the IQueryBuilder::PARAM_* constants * - * @return ILiteral * @since 8.2.0 * * @psalm-taint-sink sql $input * @psalm-taint-sink sql $type */ - public function literal($input, $type = IQueryBuilder::PARAM_STR): ILiteral; + public function literal(mixed $input, int|string $type = IQueryBuilder::PARAM_STR): ILiteral; /** * Returns a IQueryFunction that casts the column to the given type * - * @param string|IQueryFunction $column - * @param mixed $type One of IQueryBuilder::PARAM_* - * @psalm-param IQueryBuilder::PARAM_* $type - * @return IQueryFunction + * @param IQueryBuilder::PARAM_* $type * @since 9.0.0 * * @psalm-taint-sink sql $column * @psalm-taint-sink sql $type */ - public function castColumn($column, $type): IQueryFunction; + public function castColumn(string|IQueryFunction|ILiteral|IParameter $column, int|string $type): IQueryFunction; } diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php index 480ec1cb1ac8c..e178a59170da9 100644 --- a/lib/public/DB/QueryBuilder/IFunctionBuilder.php +++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php @@ -6,11 +6,14 @@ */ namespace OCP\DB\QueryBuilder; +use OCP\AppFramework\Attribute\Consumable; + /** * This class provides a builder for sql some functions * * @since 12.0.0 */ +#[Consumable(since: '12.0.0')] interface IFunctionBuilder { /** * Calculates the MD5 hash of a given input @@ -31,7 +34,7 @@ public function md5($input): IQueryFunction; * @return IQueryFunction * @since 12.0.0 */ - public function concat($x, ...$expr): IQueryFunction; + public function concat(string|ILiteral|IParameter|IQueryFunction $x, ...$expr): IQueryFunction; /** * Returns a string which is the concatenation of all non-NULL values of X @@ -56,29 +59,25 @@ public function groupConcat($expr, ?string $separator = ','): IQueryFunction; * @param string|ILiteral|IParameter|IQueryFunction $start The start of the substring, note that counting starts at 1 * @param null|ILiteral|IParameter|IQueryFunction $length The length of the substring * - * @return IQueryFunction * @since 12.0.0 */ - public function substring($input, $start, $length = null): IQueryFunction; + public function substring(string|ILiteral|IParameter|IQueryFunction $input, string|ILiteral|IParameter|IQueryFunction $start, null|ILiteral|IParameter|IQueryFunction $length = null): IQueryFunction; /** * Takes the sum of all rows in a column * * @param string|ILiteral|IParameter|IQueryFunction $field the column to sum * - * @return IQueryFunction * @since 12.0.0 */ - public function sum($field): IQueryFunction; + public function sum(string|ILiteral|IParameter|IQueryFunction $field): IQueryFunction; /** * Transforms a string field or value to lower case * - * @param string|ILiteral|IParameter|IQueryFunction $field - * @return IQueryFunction * @since 14.0.0 */ - public function lower($field): IQueryFunction; + public function lower(string|ILiteral|IParameter|IQueryFunction $field): IQueryFunction; /** * @param string|ILiteral|IParameter|IQueryFunction $x The first input field or number diff --git a/lib/public/DB/QueryBuilder/IQueryBuilder.php b/lib/public/DB/QueryBuilder/IQueryBuilder.php index b1c483522ee44..7f711b938663c 100644 --- a/lib/public/DB/QueryBuilder/IQueryBuilder.php +++ b/lib/public/DB/QueryBuilder/IQueryBuilder.php @@ -11,6 +11,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Types\Types; +use OCP\AppFramework\Attribute\Consumable; use OCP\DB\Exception; use OCP\DB\IResult; use OCP\IDBConnection; @@ -21,6 +22,7 @@ * * @psalm-taint-specialize */ +#[Consumable(since: '8.2.0')] interface IQueryBuilder { /** * @since 9.0.0 @@ -126,7 +128,7 @@ interface IQueryBuilder { * owncloud database prefix automatically. * @since 8.2.0 */ - public function automaticTablePrefix($enabled); + public function automaticTablePrefix(bool $enabled): void; /** * Gets an ExpressionBuilder used for object-oriented construction of query expressions. @@ -142,10 +144,9 @@ public function automaticTablePrefix($enabled); * For more complex expression construction, consider storing the expression * builder object in a local variable. * - * @return \OCP\DB\QueryBuilder\IExpressionBuilder * @since 8.2.0 */ - public function expr(); + public function expr(): IExpressionBuilder; /** * Gets an FunctionBuilder used for object-oriented construction of query functions. @@ -161,26 +162,24 @@ public function expr(); * For more complex function construction, consider storing the function * builder object in a local variable. * - * @return \OCP\DB\QueryBuilder\IFunctionBuilder * @since 12.0.0 */ - public function func(); + public function func(): IFunctionBuilder; /** * Gets the type of the currently built query. * - * @return integer + * @deprecated Since 34.0.0, if necessary, track the type of the query being built outside of the builder. * @since 8.2.0 */ - public function getType(); + public function getType(): int; /** * Gets the associated DBAL Connection for this query builder. * - * @return \OCP\IDBConnection * @since 8.2.0 */ - public function getConnection(); + public function getConnection(): IDBConnection; /** * Gets the state of this query builder instance. @@ -190,7 +189,7 @@ public function getConnection(); * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update * and we can not fix this in our wrapper. */ - public function getState(); + public function getState(): int; /** * Execute for select statements @@ -229,7 +228,7 @@ public function executeStatement(?IDBConnection $connection = null): int; * @return string The SQL query string. * @since 8.2.0 */ - public function getSQL(); + public function getSQL(): string; /** * Sets a query parameter for the query being constructed. @@ -246,10 +245,9 @@ public function getSQL(); * @param mixed $value The parameter value. * @param string|null|int $type One of the IQueryBuilder::PARAM_* constants. * - * @return $this This QueryBuilder instance. * @since 8.2.0 */ - public function setParameter($key, $value, $type = null); + public function setParameter(string|int $key, mixed $value, string|null|int $type = null): self; /** * Sets a collection of query parameters for the query being constructed. @@ -268,10 +266,9 @@ public function setParameter($key, $value, $type = null); * @param array $params The query parameters to set. * @param array $types The query parameters types to set. * - * @return $this This QueryBuilder instance. * @since 8.2.0 */ - public function setParameters(array $params, array $types = []); + public function setParameters(array $params, array $types = []): self; /** * Gets all defined query parameters for the query being constructed indexed by parameter index or name. @@ -279,17 +276,17 @@ public function setParameters(array $params, array $types = []); * @return array The currently defined query parameters indexed by parameter index or name. * @since 8.2.0 */ - public function getParameters(); + public function getParameters(): array; /** * Gets a (previously set) query parameter of the query being constructed. * - * @param mixed $key The key (index or name) of the bound parameter. + * @param int|string $key The key (index or name) of the bound parameter. * * @return mixed The value of the bound parameter. * @since 8.2.0 */ - public function getParameter($key); + public function getParameter(int|string $key): mixed; /** * Gets all defined query parameter types for the query being constructed indexed by parameter index or name. @@ -297,17 +294,17 @@ public function getParameter($key); * @return array The currently defined query parameter types indexed by parameter index or name. * @since 8.2.0 */ - public function getParameterTypes(); + public function getParameterTypes(): array; /** * Gets a (previously set) query parameter type of the query being constructed. * - * @param mixed $key The key (index or name) of the bound parameter type. + * @param int|string $key The key (index or name) of the bound parameter type. * * @return mixed The value of the bound parameter type. * @since 8.2.0 */ - public function getParameterType($key); + public function getParameterType(int|string $key): mixed; /** * Sets the position of the first result to retrieve (the "offset"). @@ -317,7 +314,7 @@ public function getParameterType($key); * @return $this This QueryBuilder instance. * @since 8.2.0 */ - public function setFirstResult($firstResult); + public function setFirstResult(int $firstResult): self; /** * Gets the position of the first result the query object was set to retrieve (the "offset"). @@ -326,17 +323,16 @@ public function setFirstResult($firstResult); * @return int The position of the first result. * @since 8.2.0 */ - public function getFirstResult(); + public function getFirstResult(): int; /** * Sets the maximum number of results to retrieve (the "limit"). * * @param int|null $maxResults The maximum number of results to retrieve. * - * @return $this This QueryBuilder instance. * @since 8.2.0 */ - public function setMaxResults($maxResults); + public function setMaxResults(?int $maxResults): self; /** * Gets the maximum number of results the query object was set to retrieve (the "limit"). @@ -345,7 +341,7 @@ public function setMaxResults($maxResults); * @return int|null The maximum number of results. * @since 8.2.0 */ - public function getMaxResults(); + public function getMaxResults(): ?int; /** * Specifies an item that is to be returned in the query result. @@ -360,12 +356,11 @@ public function getMaxResults(); * * @param mixed ...$selects The selection expressions. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $selects */ - public function select(...$selects); + public function select(...$selects): self; /** * Specifies an item that is to be returned with a different name in the query result. @@ -377,16 +372,15 @@ public function select(...$selects); * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id'); * * - * @param mixed $select The selection expressions. + * @param string|IParameter|IQueryFunction $select The selection expressions. * @param string $alias The column alias used in the constructed query. * - * @return $this This QueryBuilder instance. * @since 8.2.1 * * @psalm-taint-sink sql $select * @psalm-taint-sink sql $alias */ - public function selectAlias($select, $alias); + public function selectAlias(string|IParameter|IQueryFunction|ILiteral $select, string $alias): self; /** * Specifies an item that is to be returned uniquely in the query result. @@ -397,14 +391,13 @@ public function selectAlias($select, $alias); * ->from('users'); * * - * @param mixed $select The selection expressions. + * @param string|string[] $select The selection expressions. * - * @return $this This QueryBuilder instance. * @since 9.0.0 * * @psalm-taint-sink sql $select */ - public function selectDistinct($select); + public function selectDistinct(string|array $select): self; /** * Adds an item that is to be returned in the query result. @@ -419,12 +412,11 @@ public function selectDistinct($select); * * @param mixed ...$select The selection expression. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $select */ - public function addSelect(...$select); + public function addSelect(...$selects): self; /** * Turns the query being built into a bulk delete query that ranges over @@ -438,15 +430,14 @@ public function addSelect(...$select); * * * @param string $delete The table whose rows are subject to the deletion. - * @param string $alias The table alias used in the constructed query. + * @param ?string $alias The table alias used in the constructed query. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * @since 30.0.0 Alias is deprecated and will no longer be used with the next Doctrine/DBAL update * * @psalm-taint-sink sql $delete */ - public function delete($delete = null, $alias = null); + public function delete(string $delete, ?string $alias = null): self; /** * Turns the query being built into a bulk update query that ranges over @@ -461,15 +452,14 @@ public function delete($delete = null, $alias = null); * * * @param string $update The table whose rows are subject to the update. - * @param string $alias The table alias used in the constructed query. + * @param ?string $alias The table alias used in the constructed query. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * @since 30.0.0 Alias is deprecated and will no longer be used with the next Doctrine/DBAL update * * @psalm-taint-sink sql $update */ - public function update($update = null, $alias = null); + public function update(string $update, ?string $alias = null): self; /** * Turns the query being built into an insert query that inserts into @@ -488,12 +478,11 @@ public function update($update = null, $alias = null); * * @param string $insert The table into which the rows should be inserted. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $insert */ - public function insert($insert = null); + public function insert(string $insert): self; /** * Creates and adds a query root corresponding to the table identified by the @@ -508,12 +497,11 @@ public function insert($insert = null); * @param string|IQueryFunction $from The table. * @param string|null $alias The alias of the table. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $from */ - public function from($from, $alias = null); + public function from(string|IQueryFunction $from, ?string $alias = null): self; /** * Creates and adds a join to the query. @@ -527,10 +515,9 @@ public function from($from, $alias = null); * * @param string $fromAlias The alias that points to a from clause. * @param string|IQueryFunction $join The table name to join. - * @param string $alias The alias of the join table. + * @param ?string $alias The alias of the join table. * @param string|ICompositeExpression|null $condition The condition for the join. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $fromAlias @@ -538,7 +525,7 @@ public function from($from, $alias = null); * @psalm-taint-sink sql $alias * @psalm-taint-sink sql $condition */ - public function join($fromAlias, $join, $alias, $condition = null); + public function join(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self; /** * Creates and adds a join to the query. @@ -552,10 +539,9 @@ public function join($fromAlias, $join, $alias, $condition = null); * * @param string $fromAlias The alias that points to a from clause. * @param string|IQueryFunction $join The table name to join. - * @param string $alias The alias of the join table. + * @param ?string $alias The alias of the join table. * @param string|ICompositeExpression|null $condition The condition for the join. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $fromAlias @@ -563,7 +549,7 @@ public function join($fromAlias, $join, $alias, $condition = null); * @psalm-taint-sink sql $alias * @psalm-taint-sink sql $condition */ - public function innerJoin($fromAlias, $join, $alias, $condition = null); + public function innerJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self; /** * Creates and adds a left join to the query. @@ -577,10 +563,9 @@ public function innerJoin($fromAlias, $join, $alias, $condition = null); * * @param string $fromAlias The alias that points to a from clause. * @param string|IQueryFunction $join The table name to join. - * @param string $alias The alias of the join table. + * @param ?string $alias The alias of the join table. * @param string|ICompositeExpression|null $condition The condition for the join. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * @since 30.0.0 Allow passing IQueryFunction as parameter for `$join` to allow join with a sub-query. * @@ -589,7 +574,7 @@ public function innerJoin($fromAlias, $join, $alias, $condition = null); * @psalm-taint-sink sql $alias * @psalm-taint-sink sql $condition */ - public function leftJoin($fromAlias, $join, $alias, $condition = null); + public function leftJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self; /** * Creates and adds a right join to the query. @@ -603,10 +588,9 @@ public function leftJoin($fromAlias, $join, $alias, $condition = null); * * @param string $fromAlias The alias that points to a from clause. * @param string|IQueryFunction $join The table name to join. - * @param string $alias The alias of the join table. + * @param ?string $alias The alias of the join table. * @param string|ICompositeExpression|null $condition The condition for the join. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $fromAlias @@ -614,7 +598,7 @@ public function leftJoin($fromAlias, $join, $alias, $condition = null); * @psalm-taint-sink sql $alias * @psalm-taint-sink sql $condition */ - public function rightJoin($fromAlias, $join, $alias, $condition = null); + public function rightJoin(string $fromAlias, string|IQueryFunction $join, ?string $alias, string|ICompositeExpression|null $condition = null): self; /** * Sets a new value for a column in a bulk update query. @@ -629,13 +613,12 @@ public function rightJoin($fromAlias, $join, $alias, $condition = null); * @param string $key The column to set. * @param ILiteral|IParameter|IQueryFunction|string $value The value, expression, placeholder, etc. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $key * @psalm-taint-sink sql $value */ - public function set($key, $value); + public function set(string $key, ILiteral|IParameter|IQueryFunction|string $value): self; /** * Specifies one or more restrictions to the query result. @@ -662,12 +645,11 @@ public function set($key, $value); * * @param mixed $predicates The restriction predicates. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $predicates */ - public function where(...$predicates); + public function where(...$predicates): self; /** * Adds one or more restrictions to the query results, forming a logical @@ -683,14 +665,12 @@ public function where(...$predicates); * * @param mixed ...$where The query restrictions. * - * @return $this This QueryBuilder instance. - * * @see where() * @since 8.2.0 * * @psalm-taint-sink sql $where */ - public function andWhere(...$where); + public function andWhere(...$where): self; /** * Adds one or more restrictions to the query results, forming a logical @@ -706,14 +686,12 @@ public function andWhere(...$where); * * @param mixed ...$where The WHERE statement. * - * @return $this This QueryBuilder instance. - * * @see where() * @since 8.2.0 * * @psalm-taint-sink sql $where */ - public function orWhere(...$where); + public function orWhere(...$where): self; /** * Specifies a grouping over the results of the query. @@ -728,12 +706,11 @@ public function orWhere(...$where); * * @param mixed ...$groupBys The grouping expression. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $groupBys */ - public function groupBy(...$groupBys); + public function groupBy(...$groupBys): self; /** * Adds a grouping expression to the query. @@ -748,12 +725,11 @@ public function groupBy(...$groupBys); * * @param mixed ...$groupBy The grouping expression. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $groupby */ - public function addGroupBy(...$groupBy); + public function addGroupBy(...$groupBy): self; /** * Sets a value for a column in an insert query. @@ -770,15 +746,14 @@ public function addGroupBy(...$groupBy); * * * @param string $column The column into which the value should be inserted. - * @param IParameter|string $value The value that should be inserted into the column. + * @param IParameter|IQueryFunction|string $value The value that should be inserted into the column. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $column * @psalm-taint-sink sql $value */ - public function setValue($column, $value); + public function setValue(string $column, ILiteral|IParameter|IQueryFunction|string $value): self; /** * Specifies values for an insert query indexed by column names. @@ -795,14 +770,13 @@ public function setValue($column, $value); * ); * * - * @param array $values The values to specify for the insert query indexed by column names. + * @param array $values The values to specify for the insert query indexed by column names. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $values */ - public function values(array $values); + public function values(array $values): self; /** * Specifies a restriction over the groups of the query. @@ -810,12 +784,11 @@ public function values(array $values); * * @param mixed ...$having The restriction over the groups. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $having */ - public function having(...$having); + public function having(...$having): self; /** * Adds a restriction over the groups of the query, forming a logical @@ -823,12 +796,11 @@ public function having(...$having); * * @param mixed ...$having The restriction to append. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $andHaving */ - public function andHaving(...$having); + public function andHaving(...$having): self; /** * Adds a restriction over the groups of the query, forming a logical @@ -836,19 +808,18 @@ public function andHaving(...$having); * * @param mixed ...$having The restriction to add. * - * @return $this This QueryBuilder instance. * @since 8.2.0 * * @psalm-taint-sink sql $having */ - public function orHaving(...$having); + public function orHaving(...$having): self; /** * Specifies an ordering for the query results. * Replaces any previously specified orderings, if any. * * @param string|IQueryFunction|ILiteral|IParameter $sort The ordering expression. - * @param string $order The ordering direction. + * @param 'ASC'|'DESC'|'asc'|'desc'|null $order The ordering direction. * * @return $this This QueryBuilder instance. * @since 8.2.0 @@ -856,13 +827,13 @@ public function orHaving(...$having); * @psalm-taint-sink sql $sort * @psalm-taint-sink sql $order */ - public function orderBy($sort, $order = null); + public function orderBy(string|IQueryFunction|ILiteral|IParameter $sort, ?string $order = null): self; /** * Adds an ordering to the query results. * * @param string|ILiteral|IParameter|IQueryFunction $sort The ordering expression. - * @param string $order The ordering direction. + * @param 'ASC'|'DESC'|'asc'|'desc'|null $order The ordering direction. * * @return $this This QueryBuilder instance. * @since 8.2.0 @@ -870,29 +841,25 @@ public function orderBy($sort, $order = null); * @psalm-taint-sink sql $sort * @psalm-taint-sink sql $order */ - public function addOrderBy($sort, $order = null); + public function addOrderBy(string|ILiteral|IParameter|IQueryFunction $sort, ?string $order = null): self; /** * Gets a query part by its name. * - * @param string $queryPartName - * - * @return mixed * @since 8.2.0 * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update * and we can not fix this in our wrapper. Please track the details you need, outside the object. */ - public function getQueryPart($queryPartName); + public function getQueryPart(string $queryPartName): mixed; /** * Gets all query parts. * - * @return array * @since 8.2.0 * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update * and we can not fix this in our wrapper. Please track the details you need, outside the object. */ - public function getQueryParts(); + public function getQueryParts(): array; /** * Resets SQL parts. @@ -904,7 +871,7 @@ public function getQueryParts(); * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update * and we can not fix this in our wrapper. Please create a new IQueryBuilder instead. */ - public function resetQueryParts($queryPartNames = null); + public function resetQueryParts(?array $queryPartNames = null): self; /** * Resets a single SQL part. @@ -916,7 +883,7 @@ public function resetQueryParts($queryPartNames = null); * @deprecated 30.0.0 This function is going to be removed with the next Doctrine/DBAL update * and we can not fix this in our wrapper. Please create a new IQueryBuilder instead. */ - public function resetQueryPart($queryPartName); + public function resetQueryPart(string $queryPartName): self; /** * Creates a new named parameter and bind the value $value to it. @@ -950,7 +917,7 @@ public function resetQueryPart($queryPartName); * * @psalm-taint-escape sql */ - public function createNamedParameter($value, $type = self::PARAM_STR, $placeHolder = null); + public function createNamedParameter(mixed $value, $type = self::PARAM_STR, ?string $placeHolder = null): IParameter; /** * Creates a new positional parameter and bind the given value to it. @@ -977,7 +944,7 @@ public function createNamedParameter($value, $type = self::PARAM_STR, $placeHold * * @psalm-taint-escape sql */ - public function createPositionalParameter($value, $type = self::PARAM_STR); + public function createPositionalParameter(mixed $value, $type = self::PARAM_STR): IParameter; /** * Creates a new parameter @@ -998,7 +965,7 @@ public function createPositionalParameter($value, $type = self::PARAM_STR); * * @psalm-taint-escape sql */ - public function createParameter($name); + public function createParameter(string $name): IParameter; /** * Creates a new function @@ -1026,7 +993,7 @@ public function createParameter($name); * * @psalm-taint-sink sql $call */ - public function createFunction($call); + public function createFunction(string $call): IQueryFunction; /** * Used to get the id of the last inserted element @@ -1046,13 +1013,11 @@ public function getLastInsertId(): int; * @since 9.0.0 * @since 24.0.0 accepts IQueryFunction as parameter */ - public function getTableName($table); + public function getTableName(string|IQueryFunction $table): string; /** * Returns the table name with database prefix as needed by the implementation * - * @param string $table - * @return string * @since 30.0.0 */ public function prefixTableName(string $table): string; @@ -1060,19 +1025,13 @@ public function prefixTableName(string $table): string; /** * Returns the column name quoted and with table alias prefix as needed by the implementation * - * @param string $column - * @param string $tableAlias - * @return string * @since 9.0.0 */ - public function getColumnName($column, $tableAlias = ''); + public function getColumnName(string $column, string $tableAlias = ''): string; /** * Provide a hint for the shard key for queries where this can't be detected otherwise * - * @param string $column - * @param mixed $value - * @return $this * @since 30.0.0 */ public function hintShardKey(string $column, mixed $value, bool $overwrite = false): self; @@ -1080,7 +1039,6 @@ public function hintShardKey(string $column, mixed $value, bool $overwrite = fal /** * Set the query to run across all shards if sharding is enabled. * - * @return $this * @since 30.0.0 */ public function runAcrossAllShards(): self; @@ -1088,7 +1046,7 @@ public function runAcrossAllShards(): self; /** * Get a list of column names that are expected in the query output * - * @return array + * @return string[] * @since 30.0.0 */ public function getOutputColumns(): array; diff --git a/psalm.xml b/psalm.xml index 576c482532cd5..c13ba139b28ee 100644 --- a/psalm.xml +++ b/psalm.xml @@ -55,6 +55,7 @@ + @@ -171,52 +172,61 @@ + + + + + + + + + diff --git a/tests/lib/AppFramework/Db/QBMapperTest.php b/tests/lib/AppFramework/Db/QBMapperTest.php index 0f18ef3f204e7..8e61c76bcc38a 100644 --- a/tests/lib/AppFramework/Db/QBMapperTest.php +++ b/tests/lib/AppFramework/Db/QBMapperTest.php @@ -10,6 +10,7 @@ use OCP\AppFramework\Db\Entity; use OCP\AppFramework\Db\QBMapper; use OCP\DB\QueryBuilder\IExpressionBuilder; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\Types; use OCP\IDBConnection; @@ -128,9 +129,10 @@ public function testInsertEntityParameterTypeMapping(): void { ]; $this->qb->expects($this->exactly(6)) ->method('createNamedParameter') - ->willReturnCallback(function () use (&$createNamedParameterCalls): void { + ->willReturnCallback(function () use (&$createNamedParameterCalls): IParameter { $expected = array_shift($createNamedParameterCalls); $this->assertEquals($expected, func_get_args()); + return $this->createMock(IParameter::class); }); $setValueCalls = [ @@ -185,9 +187,10 @@ public function testUpdateEntityParameterTypeMapping(): void { ]; $this->qb->expects($this->exactly(8)) ->method('createNamedParameter') - ->willReturnCallback(function () use (&$createNamedParameterCalls): void { + ->willReturnCallback(function () use (&$createNamedParameterCalls): IParameter { $expected = array_shift($createNamedParameterCalls); $this->assertEquals($expected, func_get_args()); + return $this->createMock(IParameter::class); }); $setCalls = [ diff --git a/tests/lib/Comments/ManagerTest.php b/tests/lib/Comments/ManagerTest.php index d0cb1e00fe891..4bd41c8801c35 100644 --- a/tests/lib/Comments/ManagerTest.php +++ b/tests/lib/Comments/ManagerTest.php @@ -54,7 +54,12 @@ protected function setUp(): void { $this->connection->prepare($sql)->execute(); } - protected function addDatabaseEntry(?string $parentId, ?string $topmostParentId, ?\DateTimeInterface $creationDT = null, ?\DateTimeInterface $latestChildDT = null, $objectId = null, ?\DateTimeInterface $expireDate = null): string { + /** + * @param int|null|string $objectId + * + * @psalm-param 'file1'|'file2'|'file3'|int|null $objectId + */ + protected function addDatabaseEntry(?string $parentId, ?string $topmostParentId, ?\DateTimeInterface $creationDT = null, ?\DateTimeInterface $latestChildDT = null, string|int|null $objectId = null, ?\DateTimeInterface $expireDate = null): string { $creationDT ??= new \DateTime(); $latestChildDT ??= new \DateTime('yesterday'); $objectId ??= 'file64'; diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php index 7bfa6ed5f41bf..3fd9c9e5c8d8d 100644 --- a/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php +++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php @@ -14,13 +14,14 @@ use OCP\IConfig; use OCP\IDBConnection; use OCP\Server; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use Test\TestCase; -#[\PHPUnit\Framework\Attributes\Group('DB')] +#[Group(name: 'DB')] class ExpressionBuilderDBTest extends TestCase { - /** @var \Doctrine\DBAL\Connection|IDBConnection */ - protected $connection; - protected $schemaSetup = false; + protected IDBConnection $connection; + protected bool $schemaSetup = false; protected function setUp(): void { parent::setUp(); @@ -45,14 +46,8 @@ public static function likeProvider(): array { ]; } - /** - * - * @param string $param1 - * @param string $param2 - * @param boolean $match - */ - #[\PHPUnit\Framework\Attributes\DataProvider('likeProvider')] - public function testLike($param1, $param2, $match): void { + #[DataProvider(methodName: 'likeProvider')] + public function testLike(string $param1, string $param2, bool $match): void { $query = $this->connection->getQueryBuilder(); $query->select(new Literal('1')) @@ -82,14 +77,8 @@ public static function ilikeProvider(): array { ]; } - /** - * - * @param string $param1 - * @param string $param2 - * @param boolean $match - */ - #[\PHPUnit\Framework\Attributes\DataProvider('ilikeProvider')] - public function testILike($param1, $param2, $match): void { + #[DataProvider(methodName: 'ilikeProvider')] + public function testILike(string $param1, string $param2, bool $match): void { $query = $this->connection->getQueryBuilder(); $query->select(new Literal('1')) @@ -233,7 +222,11 @@ public function testDateTimeGreater(): void { self::assertCount(1, $entries); } - protected function createConfig($appId, $key, $value) { + /** + * @psalm-param '1'|'mykey' $key + * @psalm-param '4'|'myvalue' $value + */ + protected function createConfig(string $appId, string $key, string $value) { $query = $this->connection->getQueryBuilder(); $query->insert('appconfig') ->values([ diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php index 5effc2f14692f..7d04d2a5d8700 100644 --- a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php @@ -1,5 +1,7 @@ helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -94,15 +76,8 @@ public static function dataComparisons(): array { ]; } - /** - * - * @param mixed $input1 - * @param bool $isInput1Literal - * @param mixed $input2 - * @param bool $isInput2Literal - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] - public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { + #[DataProvider(methodName: 'dataComparisons')] + public function testEquals(string $input1, bool $isInput1Literal, string $input2, bool $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -112,15 +87,8 @@ public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal) ); } - /** - * - * @param mixed $input1 - * @param bool $isInput1Literal - * @param mixed $input2 - * @param bool $isInput2Literal - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] - public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { + #[DataProvider(methodName: 'dataComparisons')] + public function testNotEquals(string $input1, bool $isInput1Literal, string $input2, bool $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -130,15 +98,8 @@ public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Liter ); } - /** - * - * @param mixed $input1 - * @param bool $isInput1Literal - * @param mixed $input2 - * @param bool $isInput2Literal - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] - public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Literal): void { + #[DataProvider(methodName: 'dataComparisons')] + public function testLowerThan(string $input1, bool $isInput1Literal, string $input2, bool $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -148,15 +109,8 @@ public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Liter ); } - /** - * - * @param mixed $input1 - * @param bool $isInput1Literal - * @param mixed $input2 - * @param bool $isInput2Literal - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] - public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { + #[DataProvider(methodName: 'dataComparisons')] + public function testLowerThanEquals(string $input1, bool $isInput1Literal, string $input2, bool $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -166,15 +120,8 @@ public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput ); } - /** - * - * @param mixed $input1 - * @param bool $isInput1Literal - * @param mixed $input2 - * @param bool $isInput2Literal - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] - public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Literal): void { + #[DataProvider(methodName: 'dataComparisons')] + public function testGreaterThan(string $input1, bool $isInput1Literal, string $input2, bool $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -184,15 +131,8 @@ public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Lit ); } - /** - * - * @param mixed $input1 - * @param bool $isInput1Literal - * @param mixed $input2 - * @param bool $isInput2Literal - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] - public function testGreaterThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { + #[DataProvider(methodName: 'dataComparisons')] + public function testGreaterThanEquals(string $input1, bool $isInput1Literal, string $input2, bool $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -223,13 +163,8 @@ public static function dataLike(): array { ]; } - /** - * - * @param mixed $input - * @param bool $isLiteral - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')] - public function testLike($input, $isLiteral): void { + #[DataProvider(methodName: 'dataLike')] + public function testLike(string $input, bool $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -238,13 +173,8 @@ public function testLike($input, $isLiteral): void { ); } - /** - * - * @param mixed $input - * @param bool $isLiteral - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')] - public function testNotLike($input, $isLiteral): void { + #[DataProvider(methodName: 'dataLike')] + public function testNotLike(string $input, bool $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -262,13 +192,8 @@ public static function dataIn(): array { ]; } - /** - * - * @param mixed $input - * @param bool $isLiteral - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')] - public function testIn($input, $isLiteral): void { + #[DataProvider(methodName: 'dataIn')] + public function testIn(string|array $input, bool $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -277,13 +202,8 @@ public function testIn($input, $isLiteral): void { ); } - /** - * - * @param mixed $input - * @param bool $isLiteral - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')] - public function testNotIn($input, $isLiteral): void { + #[DataProvider(methodName: 'dataIn')] + public function testNotIn(string|array $input, bool $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -292,7 +212,7 @@ public function testNotIn($input, $isLiteral): void { ); } - protected function helpWithLiteral($input, $isLiteral) { + protected function helpWithLiteral(mixed $input, bool $isLiteral): array { if ($isLiteral) { if (is_array($input)) { $doctrineInput = array_map(function ($ident) { @@ -331,17 +251,14 @@ public static function dataLiteral(): array { ]; } - /** - * - * @param mixed $input - * @param string|null $type - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataLiteral')] - public function testLiteral($input, $type): void { - /** @var \OC\DB\QueryBuilder\Literal $actual */ - $actual = $this->expressionBuilder->literal($input, $type); + #[DataProvider(methodName: 'dataLiteral')] + public function testLiteral(string|int $input, string|int|null $type): void { + if ($type === null) { + $actual = $this->expressionBuilder->literal($input); + } else { + $actual = $this->expressionBuilder->literal($input, $type); + } - $this->assertInstanceOf('\OC\DB\QueryBuilder\Literal', $actual); $this->assertEquals( $this->doctrineExpressionBuilder->literal($input, $type), $actual->__toString() @@ -376,14 +293,10 @@ public static function dataClobComparisons(): array { } /** - * @param string $function - * @param mixed $value - * @param mixed $type - * @param bool $compareKeyToValue - * @param int $expected + * @param IQueryBuilder::PARAM_* $type */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataClobComparisons')] - public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected): void { + #[DataProvider(methodName: 'dataClobComparisons')] + public function testClobComparisons(string $function, string|array $value, mixed $type, bool $compareKeyToValue, int $expected): void { $appId = $this->getUniqueID('testing'); $this->createConfig($appId, 1, 4); $this->createConfig($appId, 2, 5); @@ -418,7 +331,7 @@ public function testClobComparisons($function, $value, $type, $compareKeyToValue ->executeStatement(); } - protected function createConfig($appId, $key, $value) { + protected function createConfig(string $appId, int $key, string|int $value): void { $query = $this->connection->getQueryBuilder(); $query->insert('appconfig') ->values([ diff --git a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php index 2202e6879f331..93652af20c930 100644 --- a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php @@ -11,18 +11,13 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\Server; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use Test\TestCase; -/** - * Class FunctionBuilderTest - * - * - * @package Test\DB\QueryBuilder - */ -#[\PHPUnit\Framework\Attributes\Group('DB')] +#[Group(name: 'DB')] class FunctionBuilderTest extends TestCase { - /** @var \Doctrine\DBAL\Connection|IDBConnection */ - protected $connection; + protected IDBConnection $connection; protected function setUp(): void { parent::setUp(); @@ -30,8 +25,8 @@ protected function setUp(): void { $this->connection = Server::get(IDBConnection::class); } - #[\PHPUnit\Framework\Attributes\DataProvider('providerTestConcatString')] - public function testConcatString($closure): void { + #[DataProvider(methodName: 'providerTestConcatString')] + public function testConcatString(callable $closure): void { $query = $this->connection->getQueryBuilder(); [$real, $arguments, $return] = $closure($query); if ($real) { @@ -53,35 +48,35 @@ public function testConcatString($closure): void { public static function providerTestConcatString(): array { return [ '1 column: string param unicode' - => [function ($q) { + => [function (IQueryBuilder $q) { return [false, [$q->createNamedParameter('👍')], '👍']; }], '2 columns: string param and string param' - => [function ($q) { + => [function (IQueryBuilder $q) { return [false, [$q->createNamedParameter('foo'), $q->createNamedParameter('bar')], 'foobar']; }], '2 columns: string param and int literal' - => [function ($q) { + => [function (IQueryBuilder $q) { return [false, [$q->createNamedParameter('foo'), $q->expr()->literal(1)], 'foo1']; }], '2 columns: string param and string literal' - => [function ($q) { + => [function (IQueryBuilder $q) { return [false, [$q->createNamedParameter('foo'), $q->expr()->literal('bar')], 'foobar']; }], '2 columns: string real and int literal' - => [function ($q) { + => [function (IQueryBuilder $q) { return [true, ['configkey', $q->expr()->literal(2)], '12']; }], '4 columns: string literal' - => [function ($q) { + => [function (IQueryBuilder $q) { return [false, [$q->expr()->literal('foo'), $q->expr()->literal('bar'), $q->expr()->literal('foo'), $q->expr()->literal('bar')], 'foobarfoobar']; }], '4 columns: int literal' - => [function ($q) { + => [function (IQueryBuilder $q) { return [false, [$q->expr()->literal(1), $q->expr()->literal(2), $q->expr()->literal(3), $q->expr()->literal(4)], '1234']; }], '5 columns: string param with special chars used in the function' - => [function ($q) { + => [function (IQueryBuilder $q) { return [false, [$q->createNamedParameter('b'), $q->createNamedParameter("'"), $q->createNamedParameter('||'), $q->createNamedParameter(','), $q->createNamedParameter('a')], "b'||,a"]; }], ]; @@ -333,7 +328,7 @@ public static function octetLengthProvider(): array { ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('octetLengthProvider')] + #[DataProvider(methodName: 'octetLengthProvider')] public function testOctetLength(string $str, int $bytes): void { $query = $this->connection->getQueryBuilder(); @@ -356,7 +351,7 @@ public static function charLengthProvider(): array { ]; } - #[\PHPUnit\Framework\Attributes\DataProvider('charLengthProvider')] + #[DataProvider(methodName: 'charLengthProvider')] public function testCharLength(string $str, int $bytes): void { $query = $this->connection->getQueryBuilder(); @@ -371,7 +366,10 @@ public function testCharLength(string $str, int $bytes): void { $this->assertEquals($bytes, $column); } - private function setUpMinMax($value) { + /** + * @psalm-param 10|11|20 $value + */ + private function setUpMinMax(int $value) { $query = $this->connection->getQueryBuilder(); $query->insert('appconfig') diff --git a/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php b/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php index 8f84d6a0d2cc5..59cc0f983fc2b 100644 --- a/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php +++ b/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php @@ -14,6 +14,7 @@ use OC\SystemConfig; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; +use PHPUnit\Framework\Attributes\DataProvider; use Psr\Log\LoggerInterface; use Test\TestCase; @@ -41,7 +42,7 @@ private function getBuilder(string $platform): IQueryBuilder { ); } - #[\PHPUnit\Framework\Attributes\DataProvider('platformProvider')] + #[DataProvider(methodName: 'platformProvider')] public function testParseCondition(string $platform): void { $query = $this->getBuilder($platform); $param1 = $query->createNamedParameter('files'); @@ -61,7 +62,7 @@ public function testParseCondition(string $platform): void { ], $parsed->toConditions); } - #[\PHPUnit\Framework\Attributes\DataProvider('platformProvider')] + #[DataProvider(methodName: 'platformProvider')] public function testParseCastCondition(string $platform): void { $query = $this->getBuilder($platform); diff --git a/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php b/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php index 8d58ed9779b82..ba08d5c8cf233 100644 --- a/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php @@ -16,9 +16,10 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\Server; +use PHPUnit\Framework\Attributes\Group; use Test\TestCase; -#[\PHPUnit\Framework\Attributes\Group('DB')] +#[Group(name: 'DB')] class PartitionedQueryBuilderTest extends TestCase { private IDBConnection $connection; private ShardConnectionManager $shardConnectionManager; @@ -27,7 +28,6 @@ class PartitionedQueryBuilderTest extends TestCase { protected function setUp(): void { if (PHP_INT_SIZE < 8) { $this->markTestSkipped('Test requires 64bit'); - return; } $this->connection = Server::get(IDBConnection::class); $this->shardConnectionManager = Server::get(ShardConnectionManager::class); diff --git a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php index 9c4379e6f28f3..8e4647387f4d6 100644 --- a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php @@ -10,27 +10,27 @@ namespace Test\DB\QueryBuilder; +use BadMethodCallException; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Doctrine\DBAL\Query\QueryException; +use OC\DB\ConnectionAdapter; use OC\DB\QueryBuilder\Literal; use OC\DB\QueryBuilder\Parameter; use OC\DB\QueryBuilder\QueryBuilder; use OC\SystemConfig; use OCP\DB\IResult; +use OCP\DB\QueryBuilder\ILiteral; +use OCP\DB\QueryBuilder\IParameter; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\Server; use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; +use function str_starts_with; -/** - * Class QueryBuilderTest - * - * - * @package Test\DB\QueryBuilder - */ -#[\PHPUnit\Framework\Attributes\Group('DB')] +#[Group(name: 'DB')] class QueryBuilderTest extends \Test\TestCase { private SystemConfig&MockObject $config; private LoggerInterface&MockObject $logger; @@ -47,7 +47,10 @@ protected function setUp(): void { $this->queryBuilder = new QueryBuilder($this->connection, $this->config, $this->logger); } - protected function createTestingRows($appId = 'testFirstResult') { + /** + * @psalm-param 'testFirstResult'|'testFirstResult1'|'testFirstResult2' $appId + */ + protected function createTestingRows(string $appId = 'testFirstResult'): void { $qB = $this->connection->getQueryBuilder(); for ($i = 1; $i < 10; $i++) { $qB->insert('*PREFIX*appconfig') @@ -60,7 +63,7 @@ protected function createTestingRows($appId = 'testFirstResult') { } } - protected function getTestingRows(QueryBuilder $queryBuilder) { + protected function getTestingRows(QueryBuilder $queryBuilder): array { $queryBuilder->select('configvalue') ->from('*PREFIX*appconfig') ->where($queryBuilder->expr()->eq( @@ -79,7 +82,10 @@ protected function getTestingRows(QueryBuilder $queryBuilder) { return $rows; } - protected function deleteTestingRows($appId = 'testFirstResult') { + /** + * @psalm-param 'testFirstResult'|'testFirstResult1'|'testFirstResult2' $appId + */ + protected function deleteTestingRows(string $appId = 'testFirstResult'): void { $qB = $this->connection->getQueryBuilder(); $qB->delete('*PREFIX*appconfig') @@ -96,13 +102,8 @@ public static function dataFirstResult(): array { ]; } - /** - * - * @param int|null $firstResult - * @param array $expectedSet - */ - #[DataProvider('dataFirstResult')] - public function testFirstResult($firstResult, $expectedSet): void { + #[DataProvider(methodName: 'dataFirstResult')] + public function testFirstResult(?int $firstResult, array $expectedSet): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -133,13 +134,8 @@ public static function dataMaxResults(): array { ]; } - /** - * - * @param int $maxResult - * @param array $expectedSet - */ - #[DataProvider('dataMaxResults')] - public function testMaxResults($maxResult, $expectedSet): void { + #[DataProvider(methodName: 'dataMaxResults')] + public function testMaxResults(?int $maxResult, array $expectedSet): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -182,7 +178,7 @@ public static function dataSelect(): array { ]; } - #[DataProvider('dataSelect')] + #[DataProvider(methodName: 'dataSelect')] public function testSelect(array $selectArguments, array $expected, string $expectedLiteral = ''): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -190,7 +186,7 @@ public function testSelect(array $selectArguments, array $expected, string $expe array_walk_recursive( $selectArguments, function (string &$arg): void { - if (\str_starts_with($arg, 'l::')) { + if (str_starts_with($arg, 'l::')) { $arg = $this->queryBuilder->expr()->literal(substr($arg, 3)); } }, @@ -231,7 +227,7 @@ public static function dataSelectAlias(): array { ]; } - #[DataProvider('dataSelectAlias')] + #[DataProvider(methodName: 'dataSelectAlias')] public function testSelectAlias(string $select, string $alias, array $expected): void { if (str_starts_with($select, 'l::')) { $select = $this->queryBuilder->expr()->literal(substr($select, 3)); @@ -242,7 +238,7 @@ public function testSelectAlias(string $select, string $alias, array $expected): $this->queryBuilder->selectAlias($select, $alias); - $this->queryBuilder->from('*PREFIX*appconfig') + $this->queryBuilder->from('appconfig') ->where($this->queryBuilder->expr()->eq( 'appid', $this->queryBuilder->expr()->literal('testFirstResult') @@ -350,7 +346,7 @@ public static function dataAddSelect(): array { ]; } - #[DataProvider('dataAddSelect')] + #[DataProvider(methodName: 'dataAddSelect')] public function testAddSelect(array $selectArguments, array $expected, string $expectedLiteral = ''): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -358,7 +354,7 @@ public function testAddSelect(array $selectArguments, array $expected, string $e array_walk_recursive( $selectArguments, function (string &$arg): void { - if (\str_starts_with($arg, 'l::')) { + if (str_starts_with($arg, 'l::')) { $arg = $this->queryBuilder->expr()->literal(substr($arg, 3)); } }, @@ -405,15 +401,8 @@ public static function dataDelete(): array { ]; } - /** - * - * @param string $tableName - * @param string $tableAlias - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataDelete')] - public function testDelete($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataDelete')] + public function testDelete(string $tableName, ?string $tableAlias, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->delete($tableName, $tableAlias); $this->assertSame( @@ -434,15 +423,8 @@ public static function dataUpdate(): array { ]; } - /** - * - * @param string $tableName - * @param string $tableAlias - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataUpdate')] - public function testUpdate($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataUpdate')] + public function testUpdate(string $tableName, ?string $tableAlias, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->update($tableName, $tableAlias); $this->assertSame( @@ -462,14 +444,8 @@ public static function dataInsert(): array { ]; } - /** - * - * @param string $tableName - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataInsert')] - public function testInsert($tableName, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataInsert')] + public function testInsert(string $tableName, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->insert($tableName); $this->assertSame( @@ -501,7 +477,7 @@ public static function dataFrom(): array { ]; } - #[DataProvider('dataFrom')] + #[DataProvider(methodName: 'dataFrom')] public function testFrom(string $table1Name, ?string $table1Alias, ?string $table2Name, ?string $table2Alias, array $expectedQueryPart, string $expectedQuery): void { $config = $this->createMock(SystemConfig::class); $logger = $this->createMock(LoggerInterface::class); @@ -547,17 +523,8 @@ public static function dataJoin(): array { ]; } - /** - * - * @param string $fromAlias - * @param string $tableName - * @param string $tableAlias - * @param string $condition - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataJoin')] - public function testJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataJoin')] + public function testJoin(string $fromAlias, string $tableName, ?string $tableAlias, ?string $condition, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->join( $fromAlias, @@ -577,17 +544,8 @@ public function testJoin($fromAlias, $tableName, $tableAlias, $condition, $expec ); } - /** - * - * @param string $fromAlias - * @param string $tableName - * @param string $tableAlias - * @param string $condition - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataJoin')] - public function testInnerJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataJoin')] + public function testInnerJoin(string $fromAlias, string $tableName, ?string $tableAlias, ?string $condition, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->innerJoin( $fromAlias, @@ -627,17 +585,8 @@ public static function dataLeftJoin(): array { ]; } - /** - * - * @param string $fromAlias - * @param string $tableName - * @param string $tableAlias - * @param string $condition - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataLeftJoin')] - public function testLeftJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataLeftJoin')] + public function testLeftJoin(string $fromAlias, string $tableName, ?string $tableAlias, ?string $condition, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->leftJoin( $fromAlias, @@ -677,17 +626,8 @@ public static function dataRightJoin(): array { ]; } - /** - * - * @param string $fromAlias - * @param string $tableName - * @param string $tableAlias - * @param string $condition - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataRightJoin')] - public function testRightJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataRightJoin')] + public function testRightJoin(string $fromAlias, string $tableName, ?string $tableAlias, ?string $condition, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->rightJoin( $fromAlias, @@ -716,17 +656,8 @@ public static function dataSet(): array { ]; } - /** - * - * @param string $partOne1 - * @param string $partOne2 - * @param string $partTwo1 - * @param string $partTwo2 - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataSet')] - public function testSet($partOne1, $partOne2, $partTwo1, $partTwo2, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataSet')] + public function testSet(string $partOne1, string|ILiteral|IParameter $partOne2, ?string $partTwo1, ?ILiteral $partTwo2, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->update('data'); $this->queryBuilder->set($partOne1, $partOne2); if ($partTwo1 !== null) { @@ -751,14 +682,8 @@ public static function dataWhere(): array { ]; } - /** - * - * @param array $whereArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataWhere')] - public function testWhere($whereArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataWhere')] + public function testWhere(array $whereArguments, CompositeExpression $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'where'], @@ -776,14 +701,8 @@ public function testWhere($whereArguments, $expectedQueryPart, $expectedQuery): ); } - /** - * - * @param array $whereArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataWhere')] - public function testAndWhere($whereArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataWhere')] + public function testAndWhere(array $whereArguments, CompositeExpression $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'andWhere'], @@ -808,14 +727,8 @@ public static function dataOrWhere(): array { ]; } - /** - * - * @param array $whereArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataOrWhere')] - public function testOrWhere($whereArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataOrWhere')] + public function testOrWhere(array $whereArguments, CompositeExpression $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'orWhere'], @@ -840,14 +753,8 @@ public static function dataGroupBy(): array { ]; } - /** - * - * @param array $groupByArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataGroupBy')] - public function testGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataGroupBy')] + public function testGroupBy(array $groupByArguments, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'groupBy'], @@ -872,14 +779,8 @@ public static function dataAddGroupBy(): array { ]; } - /** - * - * @param array $groupByArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataAddGroupBy')] - public function testAddGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataAddGroupBy')] + public function testAddGroupBy(array $groupByArguments, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->select('column'); $this->queryBuilder->groupBy('column1'); call_user_func_array( @@ -904,15 +805,8 @@ public static function dataSetValue(): array { ]; } - /** - * - * @param string $column - * @param string $value - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataSetValue')] - public function testSetValue($column, $value, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataSetValue')] + public function testSetValue(string $column, string $value, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->insert('data'); $this->queryBuilder->setValue($column, $value); @@ -927,15 +821,8 @@ public function testSetValue($column, $value, $expectedQueryPart, $expectedQuery ); } - /** - * - * @param string $column - * @param string $value - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataSetValue')] - public function testValues($column, $value, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataSetValue')] + public function testValues(string $column, string $value, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->insert('data'); $this->queryBuilder->values([ $column => $value, @@ -969,14 +856,8 @@ public static function dataHaving(): array { ]; } - /** - * - * @param array $havingArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataHaving')] - public function testHaving($havingArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataHaving')] + public function testHaving(array $havingArguments, CompositeExpression $expectedQueryPart, string $expectedQuery): void { call_user_func_array( [$this->queryBuilder, 'having'], $havingArguments @@ -1010,14 +891,8 @@ public static function dataAndHaving(): array { ]; } - /** - * - * @param array $havingArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataAndHaving')] - public function testAndHaving($havingArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataAndHaving')] + public function testAndHaving(array $havingArguments, CompositeExpression $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->having('condition1'); call_user_func_array( [$this->queryBuilder, 'andHaving'], @@ -1052,14 +927,8 @@ public static function dataOrHaving(): array { ]; } - /** - * - * @param array $havingArguments - * @param array $expectedQueryPart - * @param string $expectedQuery - */ - #[DataProvider('dataOrHaving')] - public function testOrHaving($havingArguments, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataOrHaving')] + public function testOrHaving(array $havingArguments, CompositeExpression $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->having('condition1'); call_user_func_array( [$this->queryBuilder, 'orHaving'], @@ -1086,14 +955,10 @@ public static function dataOrderBy(): array { } /** - * - * @param string $sort - * @param string $order - * @param array $expectedQueryPart - * @param string $expectedQuery + * @param string|'ASC'|'DESC'|null $order */ - #[DataProvider('dataOrderBy')] - public function testOrderBy($sort, $order, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataOrderBy')] + public function testOrderBy(string $sort, ?string $order, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->orderBy($sort, $order); $this->assertEquals( @@ -1122,15 +987,11 @@ public static function dataAddOrderBy(): array { } /** - * - * @param string $sort2 - * @param string $order2 - * @param string $order1 - * @param array $expectedQueryPart - * @param string $expectedQuery + * @param string|'ASC'|'DESC'|null $order2 + * @param string|'ASC'|'DESC'|null $order1 */ - #[DataProvider('dataAddOrderBy')] - public function testAddOrderBy($sort2, $order2, $order1, $expectedQueryPart, $expectedQuery): void { + #[DataProvider(methodName: 'dataAddOrderBy')] + public function testAddOrderBy(string $sort2, ?string $order2, ?string $order1, array $expectedQueryPart, string $expectedQuery): void { $this->queryBuilder->orderBy('column1', $order1); $this->queryBuilder->addOrderBy($sort2, $order2); @@ -1151,7 +1012,7 @@ public function testGetLastInsertId(): void { try { $qB->getLastInsertId(); $this->fail('getLastInsertId() should throw an exception, when being called before insert()'); - } catch (\BadMethodCallException $e) { + } catch (BadMethodCallException) { $this->addToAssertionCount(1); } @@ -1166,8 +1027,6 @@ public function testGetLastInsertId(): void { $actual = $qB->getLastInsertId(); - $this->assertNotNull($actual); - $this->assertIsInt($actual); $this->assertEquals($this->connection->lastInsertId('*PREFIX*properties'), $actual); $qB->delete('properties') @@ -1177,7 +1036,7 @@ public function testGetLastInsertId(): void { try { $qB->getLastInsertId(); $this->fail('getLastInsertId() should throw an exception, when being called after delete()'); - } catch (\BadMethodCallException $e) { + } catch (BadMethodCallException) { $this->addToAssertionCount(1); } } @@ -1198,7 +1057,7 @@ public static function dataGetTableName(): array { ]; } - #[DataProvider('dataGetTableName')] + #[DataProvider(methodName: 'dataGetTableName')] public function testGetTableName(string $tableName, ?bool $automatic, string $expected): void { if ($tableName === 'function') { $tableName = $this->queryBuilder->createFunction('(' . $this->queryBuilder->select('*')->from('table')->getSQL() . ')'); @@ -1221,21 +1080,16 @@ public static function dataGetColumnName(): array { ]; } - /** - * @param string $column - * @param string $prefix - * @param string $expected - */ - #[DataProvider('dataGetColumnName')] - public function testGetColumnName($column, $prefix, $expected): void { + #[DataProvider(methodName: 'dataGetColumnName')] + public function testGetColumnName(string $column, string $prefix, string $expected): void { $this->assertSame( $expected, $this->queryBuilder->getColumnName($column, $prefix) ); } - private function getConnection(): IDBConnection { - $connection = $this->createMock(IDBConnection::class); + private function getConnection(): ConnectionAdapter&MockObject { + $connection = $this->createMock(ConnectionAdapter::class); $connection->method('executeStatement') ->willReturn(3); $connection->method('executeQuery') @@ -1245,6 +1099,9 @@ private function getConnection(): IDBConnection { public function testExecuteWithoutLogger(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::INSERT); $queryBuilder ->method('getSQL') ->willReturn(''); @@ -1270,6 +1127,9 @@ public function testExecuteWithoutLogger(): void { public function testExecuteWithLoggerAndNamedArray(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::INSERT); $queryBuilder ->expects($this->any()) ->method('getParameters') @@ -1311,6 +1171,9 @@ public function testExecuteWithLoggerAndNamedArray(): void { public function testExecuteWithLoggerAndUnnamedArray(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::INSERT); $queryBuilder ->expects($this->any()) ->method('getParameters') @@ -1346,6 +1209,9 @@ public function testExecuteWithLoggerAndUnnamedArray(): void { public function testExecuteWithLoggerAndNoParams(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::INSERT); $queryBuilder ->expects($this->any()) ->method('getParameters') diff --git a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php index 6efb55708a11a..15833cb2043a4 100644 --- a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php +++ b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php @@ -13,10 +13,10 @@ use OC\DB\QueryBuilder\QuoteHelper; use OCP\DB\QueryBuilder\ILiteral; use OCP\DB\QueryBuilder\IParameter; +use PHPUnit\Framework\Attributes\DataProvider; class QuoteHelperTest extends \Test\TestCase { - /** @var QuoteHelper */ - protected $helper; + protected QuoteHelper $helper; protected function setUp(): void { parent::setUp(); @@ -37,12 +37,8 @@ public static function dataQuoteColumnName(): array { ]; } - /** - * @param mixed $input - * @param string $expected - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataQuoteColumnName')] - public function testQuoteColumnName($input, $expected): void { + #[DataProvider(methodName: 'dataQuoteColumnName')] + public function testQuoteColumnName(string|Literal|Parameter $input, string $expected): void { $this->assertSame( $expected, $this->helper->quoteColumnName($input) @@ -72,23 +68,15 @@ public static function dataQuoteColumnNames(): array { ]; } - /** - * @param mixed $input - * @param string $expected - */ - #[\PHPUnit\Framework\Attributes\DataProvider('dataQuoteColumnNames')] - public function testQuoteColumnNames($input, $expected): void { + #[DataProvider(methodName: 'dataQuoteColumnNames')] + public function testQuoteColumnNames(string|Literal|Parameter|array $input, string|array $expected): void { $this->assertSame( $expected, $this->helper->quoteColumnNames($input) ); } - /** - * @param array|string|ILiteral|IParameter $strings string, Literal or Parameter - * @return array|string - */ - public function quoteColumnNames($strings) { + public function quoteColumnNames(array|string|ILiteral|IParameter $strings): array|string { if (!is_array($strings)) { return $this->quoteColumnName($strings); } @@ -101,25 +89,9 @@ public function quoteColumnNames($strings) { return $return; } - /** - * @param string|ILiteral|IParameter $string string, Literal or Parameter - * @return string - */ - public function quoteColumnName($string) { - if ($string instanceof IParameter) { - return $string->getName(); - } - - if ($string instanceof ILiteral) { - return $string->getLiteral(); - } - - if ($string === null) { - return $string; - } - - if (!is_string($string)) { - throw new \InvalidArgumentException('Only strings, Literals and Parameters are allowed'); + public function quoteColumnName(string|ILiteral|IParameter $string): string { + if ($string instanceof ILiteral || $string instanceof IParameter) { + return (string)$string; } if (substr_count($string, '.')) { diff --git a/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php b/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php index 145a0214570b3..8cebd7557c3fc 100644 --- a/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php @@ -17,9 +17,10 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\Server; +use PHPUnit\Framework\Attributes\Group; use Test\TestCase; -#[\PHPUnit\Framework\Attributes\Group('DB')] +#[Group(name: 'DB')] class SharedQueryBuilderTest extends TestCase { private IDBConnection $connection; private AutoIncrementHandler $autoIncrementHandler;