Skip to content

Commit

Permalink
fix(db): Deprecate IExpressionBuilder::or() and `IExpressionBuilder…
Browse files Browse the repository at this point in the history
…::and()` without parameters

Signed-off-by: Joas Schilling <coding@schilljs.com>
  • Loading branch information
nickvergessen committed Jul 18, 2024
1 parent 26a091d commit b11564f
Show file tree
Hide file tree
Showing 12 changed files with 105 additions and 90 deletions.
20 changes: 12 additions & 8 deletions apps/contactsinteraction/lib/Db/CardSearchDao.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,37 @@ public function findExisting(IUser $user,
$cardQuery = $this->db->getQueryBuilder();
$propQuery = $this->db->getQueryBuilder();

$propOr = $propQuery->expr()->orX();
$additionalWheres = [];
if ($uid !== null) {
$propOr->add($propQuery->expr()->andX(
$additionalWheres[] = $propQuery->expr()->andX(
$propQuery->expr()->eq('name', $cardQuery->createNamedParameter('UID')),
$propQuery->expr()->eq('value', $cardQuery->createNamedParameter($uid))
));
);
}
if ($email !== null) {
$propOr->add($propQuery->expr()->andX(
$additionalWheres[] = $propQuery->expr()->andX(
$propQuery->expr()->eq('name', $cardQuery->createNamedParameter('EMAIL')),
$propQuery->expr()->eq('value', $cardQuery->createNamedParameter($email))
));
);
}
if ($cloudId !== null) {
$propOr->add($propQuery->expr()->andX(
$additionalWheres[] = $propQuery->expr()->andX(
$propQuery->expr()->eq('name', $cardQuery->createNamedParameter('CLOUD')),
$propQuery->expr()->eq('value', $cardQuery->createNamedParameter($cloudId))
));
);
}
$addressbooksQuery->selectDistinct('id')
->from('addressbooks')
->where($addressbooksQuery->expr()->eq('principaluri', $cardQuery->createNamedParameter("principals/users/" . $user->getUID())));
$propQuery->selectDistinct('cardid')
->from('cards_properties')
->where($propQuery->expr()->in('addressbookid', $propQuery->createFunction($addressbooksQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY))
->andWhere($propOr)
->groupBy('cardid');

if (!empty($additionalWheres)) {
$propQuery->andWhere($propQuery->expr()->orX(...$additionalWheres));
}

$cardQuery->select('carddata')
->from('cards')
->where($cardQuery->expr()->in('id', $cardQuery->createFunction($propQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY))
Expand Down
14 changes: 8 additions & 6 deletions apps/contactsinteraction/lib/Db/RecentContactMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,25 @@ public function findMatch(IUser $user,
?string $cloudId): array {
$qb = $this->db->getQueryBuilder();

$or = $qb->expr()->orX();
$additionalWheres = [];
if ($uid !== null) {
$or->add($qb->expr()->eq('uid', $qb->createNamedParameter($uid)));
$additionalWheres[] = $qb->expr()->eq('uid', $qb->createNamedParameter($uid));
}
if ($email !== null) {
$or->add($qb->expr()->eq('email', $qb->createNamedParameter($email)));
$additionalWheres[] = $qb->expr()->eq('email', $qb->createNamedParameter($email));
}
if ($cloudId !== null) {
$or->add($qb->expr()->eq('federated_cloud_id', $qb->createNamedParameter($cloudId)));
$additionalWheres[] = $qb->expr()->eq('federated_cloud_id', $qb->createNamedParameter($cloudId));
}

$select = $qb
->select('*')
->from($this->getTableName())
->where($or)
->andWhere($qb->expr()->eq('actor_uid', $qb->createNamedParameter($user->getUID())));
->where($qb->expr()->eq('actor_uid', $qb->createNamedParameter($user->getUID())));

if (!empty($additionalWheres)) {
$select->andWhere($select->expr()->orX(...$additionalWheres));
}
return $this->findEntities($select);
}

Expand Down
64 changes: 34 additions & 30 deletions apps/dav/lib/CalDAV/CalDavBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -1875,12 +1875,12 @@ public function search(
}

if (!empty($searchProperties)) {
$or = $innerQuery->expr()->orX();
$or = [];
foreach ($searchProperties as $searchProperty) {
$or->add($innerQuery->expr()->eq('op.name',
$outerQuery->createNamedParameter($searchProperty)));
$or[] = $innerQuery->expr()->eq('op.name',
$outerQuery->createNamedParameter($searchProperty));
}
$innerQuery->andWhere($or);
$innerQuery->andWhere($innerQuery->expr()->orX(...$or));
}

if ($pattern !== '') {
Expand Down Expand Up @@ -1924,12 +1924,12 @@ public function search(
}

if (!empty($options['types'])) {
$or = $outerQuery->expr()->orX();
$or = [];
foreach ($options['types'] as $type) {
$or->add($outerQuery->expr()->eq('componenttype',
$outerQuery->createNamedParameter($type)));
$or[] = $outerQuery->expr()->eq('componenttype',
$outerQuery->createNamedParameter($type));
}
$outerQuery->andWhere($or);
$outerQuery->andWhere($outerQuery->expr()->orX(...$or));
}

$outerQuery->andWhere($outerQuery->expr()->in('c.id', $outerQuery->createFunction($innerQuery->getSQL())));
Expand Down Expand Up @@ -2150,67 +2150,71 @@ public function searchPrincipalUri(string $principalUri,
$escapePattern = !\array_key_exists('escape_like_param', $options) || $options['escape_like_param'] !== false;

$calendarObjectIdQuery = $this->db->getQueryBuilder();
$calendarOr = $calendarObjectIdQuery->expr()->orX();
$searchOr = $calendarObjectIdQuery->expr()->orX();
$calendarOr = [];
$searchOr = [];

// Fetch calendars and subscription
$calendars = $this->getCalendarsForUser($principalUri);
$subscriptions = $this->getSubscriptionsForUser($principalUri);
foreach ($calendars as $calendar) {
$calendarAnd = $calendarObjectIdQuery->expr()->andX();
$calendarAnd->add($calendarObjectIdQuery->expr()->eq('cob.calendarid', $calendarObjectIdQuery->createNamedParameter((int)$calendar['id'])));
$calendarAnd->add($calendarObjectIdQuery->expr()->eq('cob.calendartype', $calendarObjectIdQuery->createNamedParameter(self::CALENDAR_TYPE_CALENDAR)));
$calendarAnd = $calendarObjectIdQuery->expr()->andX(
$calendarObjectIdQuery->expr()->eq('cob.calendarid', $calendarObjectIdQuery->createNamedParameter((int)$calendar['id'])),
$calendarObjectIdQuery->expr()->eq('cob.calendartype', $calendarObjectIdQuery->createNamedParameter(self::CALENDAR_TYPE_CALENDAR)),
);

// If it's shared, limit search to public events
if (isset($calendar['{http://owncloud.org/ns}owner-principal'])
&& $calendar['principaluri'] !== $calendar['{http://owncloud.org/ns}owner-principal']) {
$calendarAnd->add($calendarObjectIdQuery->expr()->eq('co.classification', $calendarObjectIdQuery->createNamedParameter(self::CLASSIFICATION_PUBLIC)));
}

$calendarOr->add($calendarAnd);
$calendarOr[] = $calendarAnd;
}
foreach ($subscriptions as $subscription) {
$subscriptionAnd = $calendarObjectIdQuery->expr()->andX();
$subscriptionAnd->add($calendarObjectIdQuery->expr()->eq('cob.calendarid', $calendarObjectIdQuery->createNamedParameter((int)$subscription['id'])));
$subscriptionAnd->add($calendarObjectIdQuery->expr()->eq('cob.calendartype', $calendarObjectIdQuery->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION)));
$subscriptionAnd = $calendarObjectIdQuery->expr()->andX(
$calendarObjectIdQuery->expr()->eq('cob.calendarid', $calendarObjectIdQuery->createNamedParameter((int)$subscription['id'])),
$calendarObjectIdQuery->expr()->eq('cob.calendartype', $calendarObjectIdQuery->createNamedParameter(self::CALENDAR_TYPE_SUBSCRIPTION)),
);

// If it's shared, limit search to public events
if (isset($subscription['{http://owncloud.org/ns}owner-principal'])
&& $subscription['principaluri'] !== $subscription['{http://owncloud.org/ns}owner-principal']) {
$subscriptionAnd->add($calendarObjectIdQuery->expr()->eq('co.classification', $calendarObjectIdQuery->createNamedParameter(self::CLASSIFICATION_PUBLIC)));
}

$calendarOr->add($subscriptionAnd);
$calendarOr[] = $subscriptionAnd;
}

foreach ($searchProperties as $property) {
$propertyAnd = $calendarObjectIdQuery->expr()->andX();
$propertyAnd->add($calendarObjectIdQuery->expr()->eq('cob.name', $calendarObjectIdQuery->createNamedParameter($property, IQueryBuilder::PARAM_STR)));
$propertyAnd->add($calendarObjectIdQuery->expr()->isNull('cob.parameter'));
$propertyAnd = $calendarObjectIdQuery->expr()->andX(
$calendarObjectIdQuery->expr()->eq('cob.name', $calendarObjectIdQuery->createNamedParameter($property, IQueryBuilder::PARAM_STR)),
$calendarObjectIdQuery->expr()->isNull('cob.parameter'),
);

$searchOr->add($propertyAnd);
$searchOr[] = $propertyAnd;
}
foreach ($searchParameters as $property => $parameter) {
$parameterAnd = $calendarObjectIdQuery->expr()->andX();
$parameterAnd->add($calendarObjectIdQuery->expr()->eq('cob.name', $calendarObjectIdQuery->createNamedParameter($property, IQueryBuilder::PARAM_STR)));
$parameterAnd->add($calendarObjectIdQuery->expr()->eq('cob.parameter', $calendarObjectIdQuery->createNamedParameter($parameter, IQueryBuilder::PARAM_STR_ARRAY)));
$parameterAnd = $calendarObjectIdQuery->expr()->andX(
$calendarObjectIdQuery->expr()->eq('cob.name', $calendarObjectIdQuery->createNamedParameter($property, IQueryBuilder::PARAM_STR)),
$calendarObjectIdQuery->expr()->eq('cob.parameter', $calendarObjectIdQuery->createNamedParameter($parameter, IQueryBuilder::PARAM_STR_ARRAY)),
);

$searchOr->add($parameterAnd);
$searchOr[] = $parameterAnd;
}

if ($calendarOr->count() === 0) {
if (empty($calendarOr)) {
return [];
}
if ($searchOr->count() === 0) {
if (empty($searchOr)) {
return [];
}

$calendarObjectIdQuery->selectDistinct('cob.objectid')
->from($this->dbObjectPropertiesTable, 'cob')
->leftJoin('cob', 'calendarobjects', 'co', $calendarObjectIdQuery->expr()->eq('co.id', 'cob.objectid'))
->andWhere($calendarObjectIdQuery->expr()->in('co.componenttype', $calendarObjectIdQuery->createNamedParameter($componentTypes, IQueryBuilder::PARAM_STR_ARRAY)))
->andWhere($calendarOr)
->andWhere($searchOr)
->andWhere($calendarObjectIdQuery->expr()->orX(...$calendarOr))
->andWhere($calendarObjectIdQuery->expr()->orX(...$searchOr))
->andWhere($calendarObjectIdQuery->expr()->isNull('deleted_at'));

if ($pattern !== '') {
Expand Down
12 changes: 6 additions & 6 deletions apps/dav/lib/CardDAV/CardDavBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -1148,20 +1148,20 @@ private function searchByAddressBookIds(array $addressBookIds,
/**
* FIXME Find a way to match only 4 last digits
* BDAY can be --1018 without year or 20001019 with it
* $bDayOr = $query2->expr()->orX();
* $bDayOr = [];
* if ($options['since'] instanceof DateTimeFilter) {
* $bDayOr->add(
* $bDayOr[] =
* $query2->expr()->gte('SUBSTR(cp_bday.value, -4)',
* $query2->createNamedParameter($options['since']->get()->format('md')))
* $query2->createNamedParameter($options['since']->get()->format('md'))
* );
* }
* if ($options['until'] instanceof DateTimeFilter) {
* $bDayOr->add(
* $bDayOr[] =
* $query2->expr()->lte('SUBSTR(cp_bday.value, -4)',
* $query2->createNamedParameter($options['until']->get()->format('md')))
* $query2->createNamedParameter($options['until']->get()->format('md'))
* );
* }
* $query2->andWhere($bDayOr);
* $query2->andWhere($query2->expr()->orX(...$bDayOr));
*/
}

Expand Down
8 changes: 4 additions & 4 deletions lib/private/BackgroundJob/JobList.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,12 @@ public function getNext(bool $onlyTimeSensitive = false, ?array $jobClasses = nu
$query->andWhere($query->expr()->eq('time_sensitive', $query->createNamedParameter(IJob::TIME_SENSITIVE, IQueryBuilder::PARAM_INT)));
}

if ($jobClasses !== null && count($jobClasses) > 0) {
$orClasses = $query->expr()->orx();
if (!empty($jobClasses)) {
$orClasses = [];
foreach ($jobClasses as $jobClass) {
$orClasses->add($query->expr()->eq('class', $query->createNamedParameter($jobClass, IQueryBuilder::PARAM_STR)));
$orClasses[] = $query->expr()->eq('class', $query->createNamedParameter($jobClass, IQueryBuilder::PARAM_STR));
}
$query->andWhere($orClasses);
$query->andWhere($query->expr()->orX(...$orClasses));
}

$result = $query->executeQuery();
Expand Down
12 changes: 6 additions & 6 deletions lib/private/DB/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -471,22 +471,22 @@ public function setValues(string $table, array $keys, array $values, array $upda
foreach ($values as $name => $value) {
$updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
}
$where = $updateQb->expr()->andX();
$where = [];
$whereValues = array_merge($keys, $updatePreconditionValues);
foreach ($whereValues as $name => $value) {
if ($value === '') {
$where->add($updateQb->expr()->emptyString(
$where[] = $updateQb->expr()->emptyString(
$name
));
);
} else {
$where->add($updateQb->expr()->eq(
$where[] = $updateQb->expr()->eq(
$name,
$updateQb->createNamedParameter($value, $this->getType($value)),
$this->getType($value)
));
);
}
}
$updateQb->where($where);
$updateQb->where($updateQb->expr()->andX(...$where));
$affected = $updateQb->executeStatement();

if ($affected === 0 && !empty($updatePreconditionValues)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
use OCP\IDBConnection;
use Psr\Log\LoggerInterface;

class ExpressionBuilder implements IExpressionBuilder {
/** @var \Doctrine\DBAL\Query\Expression\ExpressionBuilder */
Expand All @@ -33,16 +34,14 @@ class ExpressionBuilder implements IExpressionBuilder {
protected $connection;

/** @var FunctionBuilder */
protected $logger;

/** @var LoggerInterface */
protected $functionBuilder;

/**
* Initializes a new <tt>ExpressionBuilder</tt>.
*
* @param ConnectionAdapter $connection
* @param IQueryBuilder $queryBuilder
*/
public function __construct(ConnectionAdapter $connection, IQueryBuilder $queryBuilder) {
public function __construct(ConnectionAdapter $connection, IQueryBuilder $queryBuilder, LoggerInterface $logger) {
$this->connection = $connection;
$this->logger = $logger;

Check failure

Code scanning / Psalm

InvalidPropertyAssignmentValue Error

$this->logger with declared type 'OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder' cannot be assigned type 'Psr\Log\LoggerInterface'

Check failure on line 44 in lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidPropertyAssignmentValue

lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php:44:19: InvalidPropertyAssignmentValue: $this->logger with declared type 'OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder' cannot be assigned type 'Psr\Log\LoggerInterface' (see https://psalm.dev/145)
$this->helper = new QuoteHelper();
$this->expressionBuilder = new DoctrineExpressionBuilder($connection->getInner());
$this->functionBuilder = $queryBuilder->func();

Check failure on line 47 in lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidPropertyAssignmentValue

lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php:47:28: InvalidPropertyAssignmentValue: $this->functionBuilder with declared type 'Psr\Log\LoggerInterface' cannot be assigned type 'OCP\DB\QueryBuilder\IFunctionBuilder' (see https://psalm.dev/145)
Expand All @@ -63,6 +62,9 @@ public function __construct(ConnectionAdapter $connection, IQueryBuilder $queryB
* @return \OCP\DB\QueryBuilder\ICompositeExpression
*/
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__)]);

Check failure

Code scanning / Psalm

UndefinedMethod Error

Method OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder::debug does not exist

Check failure on line 66 in lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedMethod

lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php:66:19: UndefinedMethod: Method OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder::debug does not exist (see https://psalm.dev/022)
}
return new CompositeExpression(CompositeExpression::TYPE_AND, $x);
}

Expand All @@ -81,6 +83,9 @@ public function andX(...$x): ICompositeExpression {
* @return \OCP\DB\QueryBuilder\ICompositeExpression
*/
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__)]);

Check failure

Code scanning / Psalm

UndefinedMethod Error

Method OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder::debug does not exist

Check failure on line 87 in lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedMethod

lib/private/DB/QueryBuilder/ExpressionBuilder/ExpressionBuilder.php:87:19: UndefinedMethod: Method OC\DB\QueryBuilder\FunctionBuilder\FunctionBuilder::debug does not exist (see https://psalm.dev/022)
}
return new CompositeExpression(CompositeExpression::TYPE_OR, $x);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@
use OC\DB\QueryBuilder\QueryFunction;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
use Psr\Log\LoggerInterface;

class MySqlExpressionBuilder extends ExpressionBuilder {
/** @var string */
protected $collation;
protected string $collation;

/**
* @param ConnectionAdapter $connection
* @param IQueryBuilder $queryBuilder
*/
public function __construct(ConnectionAdapter $connection, IQueryBuilder $queryBuilder) {
parent::__construct($connection, $queryBuilder);
public function __construct(ConnectionAdapter $connection, IQueryBuilder $queryBuilder, LoggerInterface $logger) {
parent::__construct($connection, $queryBuilder, $logger);

$params = $connection->getInner()->getParams();
$this->collation = $params['collation'] ?? (($params['charset'] ?? 'utf8') . '_general_ci');
Expand Down
15 changes: 8 additions & 7 deletions lib/private/DB/QueryBuilder/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ public function automaticTablePrefix($enabled) {
*/
public function expr() {
return match($this->connection->getDatabaseProvider()) {
IDBConnection::PLATFORM_ORACLE => new OCIExpressionBuilder($this->connection, $this),
IDBConnection::PLATFORM_POSTGRES => new PgSqlExpressionBuilder($this->connection, $this),
IDBConnection::PLATFORM_MYSQL => new MySqlExpressionBuilder($this->connection, $this),
IDBConnection::PLATFORM_SQLITE => new SqliteExpressionBuilder($this->connection, $this),
IDBConnection::PLATFORM_ORACLE => new OCIExpressionBuilder($this->connection, $this, $this->logger),
IDBConnection::PLATFORM_POSTGRES => new PgSqlExpressionBuilder($this->connection, $this, $this->logger),
IDBConnection::PLATFORM_MYSQL => new MySqlExpressionBuilder($this->connection, $this, $this->logger),
IDBConnection::PLATFORM_SQLITE => new SqliteExpressionBuilder($this->connection, $this, $this->logger),
};
}

Expand Down Expand Up @@ -819,9 +819,10 @@ public function set($key, $value) {
* // You can optionally programmatically build and/or expressions
* $qb = $conn->getQueryBuilder();
*
* $or = $qb->expr()->orx();
* $or->add($qb->expr()->eq('u.id', 1));
* $or->add($qb->expr()->eq('u.id', 2));
* $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'))
Expand Down
Loading

0 comments on commit b11564f

Please sign in to comment.