mirror of
https://github.com/nextcloud/server.git
synced 2026-02-03 20:41:22 -05:00
Merge pull request #47329 from nextcloud/feat/add-datetime-qbmapper-support
feat(AppFramework): Add full support for date / time / datetime columns
This commit is contained in:
commit
2ef74b9860
29 changed files with 527 additions and 146 deletions
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
namespace OCA\ContactsInteraction\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* @method void setActorUid(string $uid)
|
||||
|
|
@ -33,11 +34,11 @@ class RecentContact extends Entity {
|
|||
protected int $lastContact = -1;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('actorUid', 'string');
|
||||
$this->addType('uid', 'string');
|
||||
$this->addType('email', 'string');
|
||||
$this->addType('federatedCloudId', 'string');
|
||||
$this->addType('card', 'blob');
|
||||
$this->addType('lastContact', 'int');
|
||||
$this->addType('actorUid', Types::STRING);
|
||||
$this->addType('uid', Types::STRING);
|
||||
$this->addType('email', Types::STRING);
|
||||
$this->addType('federatedCloudId', Types::STRING);
|
||||
$this->addType('card', Types::BLOB);
|
||||
$this->addType('lastContact', Types::INTEGER);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
namespace OCA\DAV\CalDAV\Proxy;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* @method string getOwnerId()
|
||||
|
|
@ -28,8 +29,8 @@ class Proxy extends Entity {
|
|||
protected $permissions;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('ownerId', 'string');
|
||||
$this->addType('proxyId', 'string');
|
||||
$this->addType('permissions', 'int');
|
||||
$this->addType('ownerId', Types::STRING);
|
||||
$this->addType('proxyId', Types::STRING);
|
||||
$this->addType('permissions', Types::INTEGER);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
namespace OCA\DAV\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* @method string getUserId()
|
||||
|
|
@ -34,9 +35,9 @@ class Direct extends Entity {
|
|||
protected $expiration;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('userId', 'string');
|
||||
$this->addType('fileId', 'int');
|
||||
$this->addType('token', 'string');
|
||||
$this->addType('expiration', 'int');
|
||||
$this->addType('userId', Types::STRING);
|
||||
$this->addType('fileId', Types::INTEGER);
|
||||
$this->addType('token', Types::STRING);
|
||||
$this->addType('expiration', Types::INTEGER);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ class FederatedShareProvider implements IShareProvider {
|
|||
->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
|
||||
->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
|
||||
->setValue('permissions', $qb->createNamedParameter($permissions))
|
||||
->setValue('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
|
||||
->setValue('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->setValue('token', $qb->createNamedParameter($token))
|
||||
->setValue('stime', $qb->createNamedParameter(time()));
|
||||
|
||||
|
|
@ -333,7 +333,7 @@ class FederatedShareProvider implements IShareProvider {
|
|||
->set('permissions', $qb->createNamedParameter($share->getPermissions()))
|
||||
->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
|
||||
->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
|
||||
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
|
||||
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->executeStatement();
|
||||
|
||||
// send the updated permission to the owner/initiator, if they are not the same
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ class ReminderMapper extends QBMapper {
|
|||
$qb->select('id', 'user_id', 'file_id', 'due_date', 'updated_at', 'created_at', 'notified')
|
||||
->from($this->getTableName())
|
||||
->where($qb->expr()->eq('notified', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL)))
|
||||
->andWhere($qb->expr()->lt('due_date', $qb->createNamedParameter($buffer, IQueryBuilder::PARAM_DATE)))
|
||||
->andWhere($qb->expr()->lt('due_date', $qb->createNamedParameter($buffer, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
|
||||
->orderBy('due_date', 'ASC')
|
||||
->setMaxResults($limit);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
namespace OCA\OAuth2\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* @method int getTokenId()
|
||||
|
|
@ -36,12 +37,12 @@ class AccessToken extends Entity {
|
|||
protected $tokenCount;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('id', 'int');
|
||||
$this->addType('tokenId', 'int');
|
||||
$this->addType('clientId', 'int');
|
||||
$this->addType('id', Types::INTEGER);
|
||||
$this->addType('tokenId', Types::INTEGER);
|
||||
$this->addType('clientId', Types::INTEGER);
|
||||
$this->addType('hashedCode', 'string');
|
||||
$this->addType('encryptedToken', 'string');
|
||||
$this->addType('codeCreatedAt', 'int');
|
||||
$this->addType('tokenCount', 'int');
|
||||
$this->addType('codeCreatedAt', Types::INTEGER);
|
||||
$this->addType('tokenCount', Types::INTEGER);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
namespace OCA\OAuth2\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* @method string getClientIdentifier()
|
||||
|
|
@ -28,7 +29,7 @@ class Client extends Entity {
|
|||
protected $secret;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('id', 'int');
|
||||
$this->addType('id', Types::INTEGER);
|
||||
$this->addType('name', 'string');
|
||||
$this->addType('redirectUri', 'string');
|
||||
$this->addType('clientIdentifier', 'string');
|
||||
|
|
|
|||
|
|
@ -699,7 +699,7 @@ class ShareByMailProvider extends DefaultShareProvider implements IShareProvider
|
|||
->setValue('permissions', $qb->createNamedParameter($permissions))
|
||||
->setValue('token', $qb->createNamedParameter($token))
|
||||
->setValue('password', $qb->createNamedParameter($password))
|
||||
->setValue('password_expiration_time', $qb->createNamedParameter($passwordExpirationTime, IQueryBuilder::PARAM_DATE))
|
||||
->setValue('password_expiration_time', $qb->createNamedParameter($passwordExpirationTime, IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL))
|
||||
->setValue('stime', $qb->createNamedParameter(time()))
|
||||
->setValue('hide_download', $qb->createNamedParameter((int)$hideDownload, IQueryBuilder::PARAM_INT))
|
||||
|
|
@ -712,7 +712,7 @@ class ShareByMailProvider extends DefaultShareProvider implements IShareProvider
|
|||
|
||||
$qb->setValue('attributes', $qb->createNamedParameter($shareAttributes));
|
||||
if ($expirationTime !== null) {
|
||||
$qb->setValue('expiration', $qb->createNamedParameter($expirationTime, IQueryBuilder::PARAM_DATE));
|
||||
$qb->setValue('expiration', $qb->createNamedParameter($expirationTime, IQueryBuilder::PARAM_DATETIME_MUTABLE));
|
||||
}
|
||||
|
||||
$qb->executeStatement();
|
||||
|
|
@ -752,10 +752,10 @@ class ShareByMailProvider extends DefaultShareProvider implements IShareProvider
|
|||
->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
|
||||
->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
|
||||
->set('password', $qb->createNamedParameter($share->getPassword()))
|
||||
->set('password_expiration_time', $qb->createNamedParameter($share->getPasswordExpirationTime(), IQueryBuilder::PARAM_DATE))
|
||||
->set('password_expiration_time', $qb->createNamedParameter($share->getPasswordExpirationTime(), IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->set('label', $qb->createNamedParameter($share->getLabel()))
|
||||
->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL))
|
||||
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
|
||||
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->set('note', $qb->createNamedParameter($share->getNote()))
|
||||
->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT))
|
||||
->set('attributes', $qb->createNamedParameter($shareAttributes))
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
namespace OCA\UserStatus\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* Class UserStatus
|
||||
|
|
@ -73,13 +74,13 @@ class UserStatus extends Entity {
|
|||
public function __construct() {
|
||||
$this->addType('userId', 'string');
|
||||
$this->addType('status', 'string');
|
||||
$this->addType('statusTimestamp', 'int');
|
||||
$this->addType('statusTimestamp', Types::INTEGER);
|
||||
$this->addType('isUserDefined', 'boolean');
|
||||
$this->addType('messageId', 'string');
|
||||
$this->addType('customIcon', 'string');
|
||||
$this->addType('customMessage', 'string');
|
||||
$this->addType('clearAt', 'int');
|
||||
$this->addType('clearAt', Types::INTEGER);
|
||||
$this->addType('isBackup', 'boolean');
|
||||
$this->addType('statusMessageTimestamp', 'int');
|
||||
$this->addType('statusMessageTimestamp', Types::INTEGER);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
namespace OC\Core\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* @method int getTimestamp()
|
||||
|
|
@ -55,8 +56,8 @@ class LoginFlowV2 extends Entity {
|
|||
protected $appPassword;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('timestamp', 'int');
|
||||
$this->addType('started', 'int');
|
||||
$this->addType('timestamp', Types::INTEGER);
|
||||
$this->addType('started', Types::INTEGER);
|
||||
$this->addType('pollToken', 'string');
|
||||
$this->addType('loginToken', 'string');
|
||||
$this->addType('publicKey', 'string');
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace OC\Authentication\Token;
|
|||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\Authentication\Token\IToken;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* @method void setId(int $id)
|
||||
|
|
@ -88,16 +89,16 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
|
|||
$this->addType('passwordHash', 'string');
|
||||
$this->addType('name', 'string');
|
||||
$this->addType('token', 'string');
|
||||
$this->addType('type', 'int');
|
||||
$this->addType('remember', 'int');
|
||||
$this->addType('lastActivity', 'int');
|
||||
$this->addType('lastCheck', 'int');
|
||||
$this->addType('type', Types::INTEGER);
|
||||
$this->addType('remember', Types::INTEGER);
|
||||
$this->addType('lastActivity', Types::INTEGER);
|
||||
$this->addType('lastCheck', Types::INTEGER);
|
||||
$this->addType('scope', 'string');
|
||||
$this->addType('expires', 'int');
|
||||
$this->addType('expires', Types::INTEGER);
|
||||
$this->addType('publicKey', 'string');
|
||||
$this->addType('privateKey', 'string');
|
||||
$this->addType('version', 'int');
|
||||
$this->addType('passwordInvalid', 'bool');
|
||||
$this->addType('version', Types::INTEGER);
|
||||
$this->addType('passwordInvalid', Types::BOOLEAN);
|
||||
}
|
||||
|
||||
public function getId(): int {
|
||||
|
|
|
|||
|
|
@ -440,14 +440,14 @@ class Manager implements ICommentsManager {
|
|||
$query->expr()->orX(
|
||||
$query->expr()->lt(
|
||||
'creation_timestamp',
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
|
||||
IQueryBuilder::PARAM_DATE
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
IQueryBuilder::PARAM_DATETIME_MUTABLE
|
||||
),
|
||||
$query->expr()->andX(
|
||||
$query->expr()->eq(
|
||||
'creation_timestamp',
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
|
||||
IQueryBuilder::PARAM_DATE
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
IQueryBuilder::PARAM_DATETIME_MUTABLE
|
||||
),
|
||||
$idComparison
|
||||
)
|
||||
|
|
@ -463,14 +463,14 @@ class Manager implements ICommentsManager {
|
|||
$query->expr()->orX(
|
||||
$query->expr()->gt(
|
||||
'creation_timestamp',
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
|
||||
IQueryBuilder::PARAM_DATE
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
IQueryBuilder::PARAM_DATETIME_MUTABLE
|
||||
),
|
||||
$query->expr()->andX(
|
||||
$query->expr()->eq(
|
||||
'creation_timestamp',
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
|
||||
IQueryBuilder::PARAM_DATE
|
||||
$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
IQueryBuilder::PARAM_DATETIME_MUTABLE
|
||||
),
|
||||
$idComparison
|
||||
)
|
||||
|
|
@ -740,7 +740,7 @@ class Manager implements ICommentsManager {
|
|||
->from('comments')
|
||||
->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
|
||||
->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
|
||||
->andWhere($query->expr()->lt('creation_timestamp', $query->createNamedParameter($beforeDate, IQueryBuilder::PARAM_DATE)))
|
||||
->andWhere($query->expr()->lt('creation_timestamp', $query->createNamedParameter($beforeDate, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
|
||||
->orderBy('creation_timestamp', 'desc');
|
||||
|
||||
if ($verb !== '') {
|
||||
|
|
@ -1551,7 +1551,7 @@ class Manager implements ICommentsManager {
|
|||
$qb = $this->dbConn->getQueryBuilder();
|
||||
$qb->delete('comments')
|
||||
->where($qb->expr()->lte('expire_date',
|
||||
$qb->createNamedParameter($this->timeFactory->getDateTime(), IQueryBuilder::PARAM_DATE)))
|
||||
$qb->createNamedParameter($this->timeFactory->getDateTime(), IQueryBuilder::PARAM_DATETIME_MUTABLE)))
|
||||
->andWhere($qb->expr()->eq('object_type', $qb->createNamedParameter($objectType)));
|
||||
|
||||
if ($objectId !== '') {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,11 @@ class SqliteExpressionBuilder extends ExpressionBuilder {
|
|||
* @return array|IQueryFunction|string
|
||||
*/
|
||||
protected function prepareColumn($column, $type) {
|
||||
if ($type === IQueryBuilder::PARAM_DATE && !is_array($column) && !($column instanceof IParameter) && !($column instanceof ILiteral)) {
|
||||
if ($type !== null
|
||||
&& !is_array($column)
|
||||
&& !($column instanceof IParameter)
|
||||
&& !($column instanceof ILiteral)
|
||||
&& (str_starts_with($type, 'date') || str_starts_with($type, 'time'))) {
|
||||
return $this->castColumn($column, $type);
|
||||
}
|
||||
|
||||
|
|
@ -44,9 +48,21 @@ class SqliteExpressionBuilder extends ExpressionBuilder {
|
|||
* @return IQueryFunction
|
||||
*/
|
||||
public function castColumn($column, $type): IQueryFunction {
|
||||
if ($type === IQueryBuilder::PARAM_DATE) {
|
||||
$column = $this->helper->quoteColumnName($column);
|
||||
return new QueryFunction('DATETIME(' . $column . ')');
|
||||
switch ($type) {
|
||||
case IQueryBuilder::PARAM_DATE_MUTABLE:
|
||||
case IQueryBuilder::PARAM_DATE_IMMUTABLE:
|
||||
$column = $this->helper->quoteColumnName($column);
|
||||
return new QueryFunction('DATE(' . $column . ')');
|
||||
case IQueryBuilder::PARAM_DATETIME_MUTABLE:
|
||||
case IQueryBuilder::PARAM_DATETIME_IMMUTABLE:
|
||||
case IQueryBuilder::PARAM_DATETIME_TZ_MUTABLE:
|
||||
case IQueryBuilder::PARAM_DATETIME_TZ_IMMUTABLE:
|
||||
$column = $this->helper->quoteColumnName($column);
|
||||
return new QueryFunction('DATETIME(' . $column . ')');
|
||||
case IQueryBuilder::PARAM_TIME_MUTABLE:
|
||||
case IQueryBuilder::PARAM_TIME_IMMUTABLE:
|
||||
$column = $this->helper->quoteColumnName($column);
|
||||
return new QueryFunction('TIME(' . $column . ')');
|
||||
}
|
||||
|
||||
return parent::castColumn($column, $type);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class DatabaseBackend implements IBackend {
|
|||
$qb = $this->dbConnection->getQueryBuilder();
|
||||
$qb->delete(self::TABLE_NAME)
|
||||
->where(
|
||||
$qb->expr()->lte('delete_after', $qb->createNamedParameter($currentTime, IQueryBuilder::PARAM_DATE))
|
||||
$qb->expr()->lte('delete_after', $qb->createNamedParameter($currentTime, IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
)
|
||||
->executeStatement();
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ class DatabaseBackend implements IBackend {
|
|||
$qb->insert(self::TABLE_NAME)
|
||||
->values([
|
||||
'hash' => $qb->createNamedParameter($identifier, IQueryBuilder::PARAM_STR),
|
||||
'delete_after' => $qb->createNamedParameter($deleteAfter, IQueryBuilder::PARAM_DATE),
|
||||
'delete_after' => $qb->createNamedParameter($deleteAfter, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
]);
|
||||
|
||||
if (!$this->config->getSystemValueBool('ratelimit.protection.enabled', true)) {
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv
|
|||
->set('attributes', $qb->createNamedParameter($shareAttributes))
|
||||
->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->set('note', $qb->createNamedParameter($share->getNote()))
|
||||
->set('accepted', $qb->createNamedParameter($share->getStatus()))
|
||||
->set('reminder_sent', $qb->createNamedParameter($share->getReminderSent(), IQueryBuilder::PARAM_BOOL))
|
||||
|
|
@ -237,7 +237,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv
|
|||
->set('attributes', $qb->createNamedParameter($shareAttributes))
|
||||
->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->set('note', $qb->createNamedParameter($share->getNote()))
|
||||
->executeStatement();
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv
|
|||
->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
|
||||
->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->set('note', $qb->createNamedParameter($share->getNote()))
|
||||
->executeStatement();
|
||||
|
||||
|
|
@ -279,7 +279,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv
|
|||
->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
|
||||
->set('token', $qb->createNamedParameter($share->getToken()))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATE))
|
||||
->set('expiration', $qb->createNamedParameter($expirationDate, IQueryBuilder::PARAM_DATETIME_MUTABLE))
|
||||
->set('note', $qb->createNamedParameter($share->getNote()))
|
||||
->set('label', $qb->createNamedParameter($share->getLabel()))
|
||||
->set('hide_download', $qb->createNamedParameter($share->getHideDownload() ? 1 : 0), IQueryBuilder::PARAM_INT)
|
||||
|
|
|
|||
|
|
@ -95,11 +95,11 @@ class TaskMapper extends QBMapper {
|
|||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from($this->tableName)
|
||||
->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter($datetime, IQueryBuilder::PARAM_DATE)));
|
||||
->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter($datetime, IQueryBuilder::PARAM_DATETIME_MUTABLE)));
|
||||
$deletedTasks = $this->findEntities($qb);
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete($this->tableName)
|
||||
->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter($datetime, IQueryBuilder::PARAM_DATE)));
|
||||
->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter($datetime, IQueryBuilder::PARAM_DATETIME_MUTABLE)));
|
||||
$qb->executeStatement();
|
||||
return $deletedTasks;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
namespace OC\Updater;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
|
||||
/**
|
||||
* Class Changes
|
||||
|
|
@ -39,7 +40,7 @@ class Changes extends Entity {
|
|||
public function __construct() {
|
||||
$this->addType('version', 'string');
|
||||
$this->addType('etag', 'string');
|
||||
$this->addType('lastCheck', 'int');
|
||||
$this->addType('lastCheck', Types::INTEGER);
|
||||
$this->addType('data', 'string');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,14 @@
|
|||
*/
|
||||
namespace OCP\AppFramework\Db;
|
||||
|
||||
use OCP\DB\Types;
|
||||
|
||||
use function lcfirst;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* @method int getId()
|
||||
* @method void setId(int $id)
|
||||
* @psalm-type AllowedTypes = 'json'|'blob'|'datetime'|'string'|'int'|'integer'|'bool'|'boolean'|'float'|'double'|'array'|'object'
|
||||
* @since 7.0.0
|
||||
* @psalm-consistent-constructor
|
||||
*/
|
||||
|
|
@ -24,7 +25,7 @@ abstract class Entity {
|
|||
public $id;
|
||||
|
||||
private array $_updatedFields = [];
|
||||
/** @var array<string, AllowedTypes> */
|
||||
/** @var array<string, \OCP\DB\Types::*> */
|
||||
private array $_fieldTypes = ['id' => 'integer'];
|
||||
|
||||
/**
|
||||
|
|
@ -65,7 +66,7 @@ abstract class Entity {
|
|||
|
||||
|
||||
/**
|
||||
* @return array<string, AllowedTypes> with attribute and type
|
||||
* @return array<string, \OCP\DB\Types::*> with attribute and type
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public function getFieldTypes(): array {
|
||||
|
|
@ -102,33 +103,38 @@ abstract class Entity {
|
|||
// if type definition exists, cast to correct type
|
||||
if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) {
|
||||
$type = $this->_fieldTypes[$name];
|
||||
if ($type === 'blob') {
|
||||
if ($type === Types::BLOB) {
|
||||
// (B)LOB is treated as string when we read from the DB
|
||||
if (is_resource($args[0])) {
|
||||
$args[0] = stream_get_contents($args[0]);
|
||||
}
|
||||
$type = 'string';
|
||||
$type = Types::STRING;
|
||||
}
|
||||
|
||||
if ($type === 'datetime') {
|
||||
if (!$args[0] instanceof \DateTime) {
|
||||
$args[0] = new \DateTime($args[0]);
|
||||
}
|
||||
} elseif ($type === 'json') {
|
||||
if (!is_array($args[0])) {
|
||||
$args[0] = json_decode($args[0], true);
|
||||
}
|
||||
} else {
|
||||
$args[0] = match($type) {
|
||||
'string' => (string)$args[0],
|
||||
'bool', 'boolean', => (bool)$args[0],
|
||||
'int', 'integer', => (int)$args[0],
|
||||
'float' => (float)$args[0],
|
||||
'double' => (float)$args[0],
|
||||
'array' => (array)$args[0],
|
||||
'object' => (object)$args[0],
|
||||
default => new \InvalidArgumentException()
|
||||
};
|
||||
switch ($type) {
|
||||
case Types::TIME:
|
||||
case Types::DATE:
|
||||
case Types::DATETIME:
|
||||
case Types::DATETIME_TZ:
|
||||
if (!$args[0] instanceof \DateTime) {
|
||||
$args[0] = new \DateTime($args[0]);
|
||||
}
|
||||
break;
|
||||
case Types::TIME_IMMUTABLE:
|
||||
case Types::DATE_IMMUTABLE:
|
||||
case Types::DATETIME_IMMUTABLE:
|
||||
case Types::DATETIME_TZ_IMMUTABLE:
|
||||
if (!$args[0] instanceof \DateTimeImmutable) {
|
||||
$args[0] = new \DateTimeImmutable($args[0]);
|
||||
}
|
||||
break;
|
||||
case Types::JSON:
|
||||
if (!is_array($args[0])) {
|
||||
$args[0] = json_decode($args[0], true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
settype($args[0], $type);
|
||||
}
|
||||
}
|
||||
$this->$name = $args[0];
|
||||
|
|
@ -253,7 +259,7 @@ abstract class Entity {
|
|||
* that value once its being returned from the database
|
||||
*
|
||||
* @param string $fieldName the name of the attribute
|
||||
* @param AllowedTypes $type the type which will be used to match a cast
|
||||
* @param \OCP\DB\Types::* $type the type which will be used to match a cast
|
||||
* @since 7.0.0
|
||||
*/
|
||||
protected function addType(string $fieldName, string $type): void {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace OCP\AppFramework\Db;
|
|||
use Generator;
|
||||
use OCP\DB\Exception;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\DB\Types;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
/**
|
||||
|
|
@ -218,18 +219,33 @@ abstract class QBMapper {
|
|||
|
||||
switch ($types[ $property ]) {
|
||||
case 'int':
|
||||
case 'integer':
|
||||
case Types::INTEGER:
|
||||
case Types::SMALLINT:
|
||||
return IQueryBuilder::PARAM_INT;
|
||||
case 'string':
|
||||
case Types::STRING:
|
||||
return IQueryBuilder::PARAM_STR;
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
case Types::BOOLEAN:
|
||||
return IQueryBuilder::PARAM_BOOL;
|
||||
case 'blob':
|
||||
case Types::BLOB:
|
||||
return IQueryBuilder::PARAM_LOB;
|
||||
case 'datetime':
|
||||
return IQueryBuilder::PARAM_DATE;
|
||||
case 'json':
|
||||
case Types::DATE:
|
||||
return IQueryBuilder::PARAM_DATETIME_MUTABLE;
|
||||
case Types::DATETIME:
|
||||
return IQueryBuilder::PARAM_DATETIME_MUTABLE;
|
||||
case Types::DATETIME_TZ:
|
||||
return IQueryBuilder::PARAM_DATETIME_TZ_MUTABLE;
|
||||
case Types::DATE_IMMUTABLE:
|
||||
return IQueryBuilder::PARAM_DATE_IMMUTABLE;
|
||||
case Types::DATETIME_IMMUTABLE:
|
||||
return IQueryBuilder::PARAM_DATETIME_IMMUTABLE;
|
||||
case Types::DATETIME_TZ_IMMUTABLE:
|
||||
return IQueryBuilder::PARAM_DATETIME_TZ_IMMUTABLE;
|
||||
case Types::TIME:
|
||||
return IQueryBuilder::PARAM_TIME_MUTABLE;
|
||||
case Types::TIME_IMMUTABLE:
|
||||
return IQueryBuilder::PARAM_TIME_IMMUTABLE;
|
||||
case Types::JSON:
|
||||
return IQueryBuilder::PARAM_JSON;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,10 +42,60 @@ interface IQueryBuilder {
|
|||
* @since 9.0.0
|
||||
*/
|
||||
public const PARAM_LOB = ParameterType::LARGE_OBJECT;
|
||||
|
||||
/**
|
||||
* @since 9.0.0
|
||||
* @deprecated 31.0.0 - use PARAM_DATETIME_MUTABLE instead
|
||||
*/
|
||||
public const PARAM_DATE = 'datetime';
|
||||
public const PARAM_DATE = Types::DATETIME_MUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTime instance when only interested in the time part (without timezone support)
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const PARAM_TIME_MUTABLE = Types::TIME_MUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTime instance when only interested in the date part (without timezone support)
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const PARAM_DATE_MUTABLE = Types::DATE_MUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTime instance (without timezone support)
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const PARAM_DATETIME_MUTABLE = Types::DATETIME_MUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTime instance with timezone support
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const PARAM_DATETIME_TZ_MUTABLE = Types::DATETIMETZ_MUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTimeImmutable instance when only interested in the time part (without timezone support)
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const PARAM_TIME_IMMUTABLE = Types::TIME_MUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTime instance when only interested in the date part (without timezone support)
|
||||
* @since 9.0.0
|
||||
*/
|
||||
public const PARAM_DATE_IMMUTABLE = Types::DATE_IMMUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTime instance (without timezone support)
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const PARAM_DATETIME_IMMUTABLE = Types::DATETIME_IMMUTABLE;
|
||||
|
||||
/**
|
||||
* For passing a \DateTime instance with timezone support
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const PARAM_DATETIME_TZ_IMMUTABLE = Types::DATETIMETZ_IMMUTABLE;
|
||||
|
||||
/**
|
||||
* @since 24.0.0
|
||||
|
|
|
|||
|
|
@ -41,17 +41,76 @@ final class Types {
|
|||
public const BOOLEAN = 'boolean';
|
||||
|
||||
/**
|
||||
* A datetime instance with only the date set.
|
||||
* This will be (de)serialized into a \DateTime instance,
|
||||
* it is recommended to instead use the `DATE_IMMUTABLE` instead.
|
||||
*
|
||||
* Warning: When deserialized the timezone will be set to UTC.
|
||||
* @var string
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const DATE = 'date';
|
||||
|
||||
/**
|
||||
* An immutable datetime instance with only the date set.
|
||||
* This will be (de)serialized into a \DateTimeImmutable instance,
|
||||
* It is recommended to use this over the `DATE` type because
|
||||
* out `Entity` class works detecting changes through the setter,
|
||||
* changes on mutable objects can not be detected.
|
||||
*
|
||||
* Warning: When deserialized the timezone will be set to UTC.
|
||||
* @var string
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const DATE_IMMUTABLE = 'date_immutable';
|
||||
|
||||
/**
|
||||
* A datetime instance with date and time support.
|
||||
* This will be (de)serialized into a \DateTime instance,
|
||||
* it is recommended to instead use the `DATETIME_IMMUTABLE` instead.
|
||||
*
|
||||
* Warning: When deserialized the timezone will be set to UTC.
|
||||
* @var string
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const DATETIME = 'datetime';
|
||||
|
||||
/**
|
||||
* An immutable datetime instance with date and time set.
|
||||
* This will be (de)serialized into a \DateTimeImmutable instance,
|
||||
* It is recommended to use this over the `DATETIME` type because
|
||||
* out `Entity` class works detecting changes through the setter,
|
||||
* changes on mutable objects can not be detected.
|
||||
*
|
||||
* Warning: When deserialized the timezone will be set to UTC.
|
||||
* @var string
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const DATETIME_IMMUTABLE = 'datetime_immutable';
|
||||
|
||||
|
||||
/**
|
||||
* A datetime instance with timezone support
|
||||
* This will be (de)serialized into a \DateTime instance,
|
||||
* it is recommended to instead use the `DATETIME_TZ_IMMUTABLE` instead.
|
||||
*
|
||||
* @var string
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const DATETIME_TZ = 'datetimetz';
|
||||
|
||||
/**
|
||||
* An immutable timezone aware datetime instance with date and time set.
|
||||
* This will be (de)serialized into a \DateTimeImmutable instance,
|
||||
* It is recommended to use this over the `DATETIME_TZ` type because
|
||||
* out `Entity` class works detecting changes through the setter,
|
||||
* changes on mutable objects can not be detected.
|
||||
*
|
||||
* @var string
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const DATETIME_TZ_IMMUTABLE = 'datetimetz_immutable';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 21.0.0
|
||||
|
|
@ -89,11 +148,29 @@ final class Types {
|
|||
public const TEXT = 'text';
|
||||
|
||||
/**
|
||||
* A datetime instance with only the time set.
|
||||
* This will be (de)serialized into a \DateTime instance,
|
||||
* it is recommended to instead use the `TIME_IMMUTABLE` instead.
|
||||
*
|
||||
* Warning: When deserialized the timezone will be set to UTC.
|
||||
* @var string
|
||||
* @since 21.0.0
|
||||
*/
|
||||
public const TIME = 'time';
|
||||
|
||||
/**
|
||||
* A datetime instance with only the time set.
|
||||
* This will be (de)serialized into a \DateTime instance.
|
||||
*
|
||||
* It is recommended to use this over the `DATETIME_TZ` type because
|
||||
* out `Entity` class works detecting changes through the setter,
|
||||
* changes on mutable objects can not be detected.
|
||||
*
|
||||
* @var string
|
||||
* @since 31.0.0
|
||||
*/
|
||||
public const TIME_IMMUTABLE = 'time_immutable';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 24.0.0
|
||||
|
|
|
|||
|
|
@ -23,10 +23,24 @@ enum ColumnType : string {
|
|||
case BLOB = 'blob';
|
||||
/** @since 30.0.0 */
|
||||
case BOOLEAN = 'boolean';
|
||||
/** @since 30.0.0 */
|
||||
/**
|
||||
* A column created with `DATE` can be used for both `DATE` and `DATE_IMMUTABLE`
|
||||
* on the `\OCP\AppFramework\Db\Entity`.
|
||||
* @since 30.0.0
|
||||
*/
|
||||
case DATE = 'date';
|
||||
/** @since 30.0.0 */
|
||||
/**
|
||||
* A column created with `DATETIME` can be used for both `DATETIME` and `DATETIME_IMMUTABLE`
|
||||
* on the `\OCP\AppFramework\Db\Entity`.
|
||||
* @since 30.0.0
|
||||
*/
|
||||
case DATETIME = 'datetime';
|
||||
/**
|
||||
* A column created with `DATETIME_TZ` can be used for both `DATETIME_TZ` and `DATETIME_TZ_IMMUTABLE`
|
||||
* on the `\OCP\AppFramework\Db\Entity`.
|
||||
* @since 31.0.0
|
||||
*/
|
||||
case DATETIME_TZ = 'datetimetz';
|
||||
/** @since 30.0.0 */
|
||||
case DECIMAL = 'decimal';
|
||||
/** @since 30.0.0 */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
namespace Test\AppFramework\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\DB\Types;
|
||||
use PHPUnit\Framework\Constraint\IsType;
|
||||
|
||||
/**
|
||||
|
|
@ -29,6 +30,10 @@ use PHPUnit\Framework\Constraint\IsType;
|
|||
* @method bool isAnotherBool()
|
||||
* @method string getLongText()
|
||||
* @method void setLongText(string $longText)
|
||||
* @method \DateTime getTime()
|
||||
* @method void setTime(\DateTime $time)
|
||||
* @method \DateTimeImmutable getDatetime()
|
||||
* @method void setDatetime(\DateTimeImmutable $datetime)
|
||||
*/
|
||||
class TestEntity extends Entity {
|
||||
protected $name;
|
||||
|
|
@ -38,12 +43,16 @@ class TestEntity extends Entity {
|
|||
protected $trueOrFalse;
|
||||
protected $anotherBool;
|
||||
protected $longText;
|
||||
protected $time;
|
||||
protected $datetime;
|
||||
|
||||
public function __construct($name = null) {
|
||||
$this->addType('testId', 'integer');
|
||||
$this->addType('testId', Types::INTEGER);
|
||||
$this->addType('trueOrFalse', 'bool');
|
||||
$this->addType('anotherBool', 'boolean');
|
||||
$this->addType('longText', 'blob');
|
||||
$this->addType('anotherBool', Types::BOOLEAN);
|
||||
$this->addType('longText', Types::BLOB);
|
||||
$this->addType('time', Types::TIME);
|
||||
$this->addType('datetime', Types::DATETIME_IMMUTABLE);
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
|
@ -216,15 +225,34 @@ class EntityTest extends \Test\TestCase {
|
|||
$this->assertSame($string, $entity->getLongText());
|
||||
}
|
||||
|
||||
public function testSetterConvertsDatetime() {
|
||||
$entity = new TestEntity();
|
||||
$entity->setDatetime('2024-08-19 15:26:00');
|
||||
$this->assertEquals(new \DateTimeImmutable('2024-08-19 15:26:00'), $entity->getDatetime());
|
||||
}
|
||||
|
||||
public function testSetterDoesNotConvertNullOnDatetime() {
|
||||
$entity = new TestEntity();
|
||||
$entity->setDatetime(null);
|
||||
$this->assertNull($entity->getDatetime());
|
||||
}
|
||||
|
||||
public function testSetterConvertsTime() {
|
||||
$entity = new TestEntity();
|
||||
$entity->setTime('15:26:00');
|
||||
$this->assertEquals(new \DateTime('15:26:00'), $entity->getTime());
|
||||
}
|
||||
|
||||
public function testGetFieldTypes(): void {
|
||||
$entity = new TestEntity();
|
||||
$this->assertEquals([
|
||||
'id' => 'integer',
|
||||
'testId' => 'integer',
|
||||
'id' => Types::INTEGER,
|
||||
'testId' => Types::INTEGER,
|
||||
'trueOrFalse' => 'bool',
|
||||
'anotherBool' => 'boolean',
|
||||
'longText' => 'blob',
|
||||
'anotherBool' => Types::BOOLEAN,
|
||||
'longText' => Types::BLOB,
|
||||
'time' => Types::TIME,
|
||||
'datetime' => Types::DATETIME_IMMUTABLE,
|
||||
], $entity->getFieldTypes());
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +260,7 @@ class EntityTest extends \Test\TestCase {
|
|||
public function testGetItInt(): void {
|
||||
$entity = new TestEntity();
|
||||
$entity->setId(3);
|
||||
$this->assertEquals('integer', gettype($entity->getId()));
|
||||
$this->assertEquals(Types::INTEGER, gettype($entity->getId()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
159
tests/lib/AppFramework/Db/QBMapperDBTest.php
Normal file
159
tests/lib/AppFramework/Db/QBMapperDBTest.php
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Test\AppFramework\Db;
|
||||
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\DB\Types;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Server;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
* @method void setTime(?\DateTime $time)
|
||||
* @method ?\DateTime getTime()
|
||||
* @method void setDatetime(?\DateTimeImmutable $datetime)
|
||||
* @method ?\DateTimeImmutable getDatetime()
|
||||
*/
|
||||
class QBDBTestEntity extends Entity {
|
||||
protected ?\DateTime $time = null;
|
||||
protected ?\DateTimeImmutable $datetime = null;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('time', Types::TIME);
|
||||
$this->addType('datetime', Types::DATETIME_IMMUTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class QBDBTestMapper
|
||||
*
|
||||
* @package Test\AppFramework\Db
|
||||
*/
|
||||
class QBDBTestMapper extends QBMapper {
|
||||
public function __construct(IDBConnection $db) {
|
||||
parent::__construct($db, 'testing', QBDBTestEntity::class);
|
||||
}
|
||||
|
||||
public function getParameterTypeForPropertyForTest(Entity $entity, string $property) {
|
||||
return parent::getParameterTypeForProperty($entity, $property);
|
||||
}
|
||||
|
||||
public function getById(int $id): QBDBTestEntity {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$query = $qb
|
||||
->select('*')
|
||||
->from($this->tableName)
|
||||
->where(
|
||||
$qb->expr()->eq('id', $qb->createPositionalParameter($id, IQueryBuilder::PARAM_INT)),
|
||||
);
|
||||
return $this->findEntity($query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test real database handling (serialization)
|
||||
* @group DB
|
||||
*/
|
||||
class QBMapperDBTest extends TestCase {
|
||||
/** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */
|
||||
protected $connection;
|
||||
protected $schemaSetup = false;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->connection = \OCP\Server::get(IDBConnection::class);
|
||||
$this->prepareTestingTable();
|
||||
}
|
||||
|
||||
public function testInsertDateTime(): void {
|
||||
$mapper = new QBDBTestMapper($this->connection);
|
||||
$entity = new QBDBTestEntity();
|
||||
$entity->setTime(new \DateTime('2003-01-01 12:34:00'));
|
||||
$entity->setDatetime(new \DateTimeImmutable('2000-01-01 23:45:00'));
|
||||
|
||||
$result = $mapper->insert($entity);
|
||||
$this->assertNotNull($result->getId());
|
||||
}
|
||||
|
||||
public function testRetrieveDateTime(): void {
|
||||
$time = new \DateTime('2000-01-01 01:01:00');
|
||||
$datetime = new \DateTimeImmutable('2000-01-01 02:02:00');
|
||||
|
||||
$mapper = new QBDBTestMapper($this->connection);
|
||||
$entity = new QBDBTestEntity();
|
||||
$entity->setTime($time);
|
||||
$entity->setDatetime($datetime);
|
||||
|
||||
$result = $mapper->insert($entity);
|
||||
$this->assertNotNull($result->getId());
|
||||
|
||||
$dbEntity = $mapper->getById($result->getId());
|
||||
$this->assertEquals($time->format('H:i:s'), $dbEntity->getTime()->format('H:i:s'));
|
||||
$this->assertEquals($datetime->format('Y-m-d H:i:s'), $dbEntity->getDatetime()->format('Y-m-d H:i:s'));
|
||||
// The date is not saved for "time"
|
||||
$this->assertNotEquals($time->format('Y'), $dbEntity->getTime()->format('Y'));
|
||||
}
|
||||
|
||||
public function testUpdateDateTime(): void {
|
||||
$time = new \DateTime('2000-01-01 01:01:00');
|
||||
$datetime = new \DateTimeImmutable('2000-01-01 02:02:00');
|
||||
|
||||
$mapper = new QBDBTestMapper($this->connection);
|
||||
$entity = new QBDBTestEntity();
|
||||
$entity->setTime('now');
|
||||
$entity->setDatetime('now');
|
||||
|
||||
/** @var QBDBTestEntity */
|
||||
$entity = $mapper->insert($entity);
|
||||
$this->assertNotNull($entity->getId());
|
||||
|
||||
// Update the values
|
||||
$entity->setTime($time);
|
||||
$entity->setDatetime($datetime);
|
||||
$mapper->update($entity);
|
||||
|
||||
$dbEntity = $mapper->getById($entity->getId());
|
||||
$this->assertEquals($time->format('H:i:s'), $dbEntity->getTime()->format('H:i:s'));
|
||||
$this->assertEquals($datetime->format('Y-m-d H:i:s'), $dbEntity->getDatetime()->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
protected function prepareTestingTable(): void {
|
||||
if ($this->schemaSetup) {
|
||||
$this->connection->getQueryBuilder()->delete('testing')->executeStatement();
|
||||
}
|
||||
|
||||
$prefix = Server::get(IConfig::class)->getSystemValueString('dbtableprefix', 'oc_');
|
||||
$schema = $this->connection->createSchema();
|
||||
try {
|
||||
$schema->getTable($prefix . 'testing');
|
||||
$this->connection->getQueryBuilder()->delete('testing')->executeStatement();
|
||||
} catch (SchemaException $e) {
|
||||
$this->schemaSetup = true;
|
||||
$table = $schema->createTable($prefix . 'testing');
|
||||
$table->addColumn('id', Types::BIGINT, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
|
||||
$table->addColumn('time', Types::TIME, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
|
||||
$table->addColumn('datetime', Types::DATETIME_IMMUTABLE, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
|
||||
$table->setPrimaryKey(['id']);
|
||||
$this->connection->migrateToSchema($schema);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,9 @@ use OCP\AppFramework\Db\Entity;
|
|||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\QueryBuilder\IExpressionBuilder;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\DB\Types;
|
||||
use OCP\IDBConnection;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
/**
|
||||
* @method bool getBoolProp()
|
||||
|
|
@ -23,6 +25,8 @@ use OCP\IDBConnection;
|
|||
* @method void setBooleanProp(bool $booleanProp)
|
||||
* @method integer getIntegerProp()
|
||||
* @method void setIntegerProp(integer $integerProp)
|
||||
* @method ?\DateTimeImmutable getDatetimeProp()
|
||||
* @method void setDatetimeProp(?\DateTimeImmutable $datetime)
|
||||
*/
|
||||
class QBTestEntity extends Entity {
|
||||
protected $intProp;
|
||||
|
|
@ -31,14 +35,16 @@ class QBTestEntity extends Entity {
|
|||
protected $integerProp;
|
||||
protected $booleanProp;
|
||||
protected $jsonProp;
|
||||
protected $datetimeProp;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('intProp', 'int');
|
||||
$this->addType('boolProp', 'bool');
|
||||
$this->addType('stringProp', 'string');
|
||||
$this->addType('integerProp', 'integer');
|
||||
$this->addType('booleanProp', 'boolean');
|
||||
$this->addType('jsonProp', 'json');
|
||||
$this->addType('stringProp', Types::STRING);
|
||||
$this->addType('integerProp', Types::INTEGER);
|
||||
$this->addType('booleanProp', Types::BOOLEAN);
|
||||
$this->addType('jsonProp', Types::JSON);
|
||||
$this->addType('datetimeProp', Types::DATETIME_IMMUTABLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,25 +69,11 @@ class QBTestMapper extends QBMapper {
|
|||
* @package Test\AppFramework\Db
|
||||
*/
|
||||
class QBMapperTest extends \Test\TestCase {
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IDBConnection
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IQueryBuilder
|
||||
*/
|
||||
protected $qb;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IExpressionBuilder
|
||||
*/
|
||||
protected $expr;
|
||||
|
||||
/**
|
||||
* @var \Test\AppFramework\Db\QBTestMapper
|
||||
*/
|
||||
protected $mapper;
|
||||
protected IDBConnection&MockObject $db;
|
||||
protected IQueryBuilder&MockObject $qb;
|
||||
protected IExpressionBuilder&MockObject $expr;
|
||||
protected QBTestMapper $mapper;
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
|
|
@ -109,36 +101,41 @@ class QBMapperTest extends \Test\TestCase {
|
|||
|
||||
|
||||
public function testInsertEntityParameterTypeMapping(): void {
|
||||
$datetime = new \DateTimeImmutable();
|
||||
$entity = new QBTestEntity();
|
||||
$entity->setIntProp(123);
|
||||
$entity->setBoolProp(true);
|
||||
$entity->setStringProp('string');
|
||||
$entity->setIntegerProp(456);
|
||||
$entity->setBooleanProp(false);
|
||||
$entity->setDatetimeProp($datetime);
|
||||
|
||||
$intParam = $this->qb->createNamedParameter('int_prop', IQueryBuilder::PARAM_INT);
|
||||
$boolParam = $this->qb->createNamedParameter('bool_prop', IQueryBuilder::PARAM_BOOL);
|
||||
$stringParam = $this->qb->createNamedParameter('string_prop', IQueryBuilder::PARAM_STR);
|
||||
$integerParam = $this->qb->createNamedParameter('integer_prop', IQueryBuilder::PARAM_INT);
|
||||
$booleanParam = $this->qb->createNamedParameter('boolean_prop', IQueryBuilder::PARAM_BOOL);
|
||||
$datetimeParam = $this->qb->createNamedParameter('datetime_prop', IQueryBuilder::PARAM_DATETIME_IMMUTABLE);
|
||||
|
||||
$this->qb->expects($this->exactly(5))
|
||||
$this->qb->expects($this->exactly(6))
|
||||
->method('createNamedParameter')
|
||||
->withConsecutive(
|
||||
[$this->equalTo(123), $this->equalTo(IQueryBuilder::PARAM_INT)],
|
||||
[$this->equalTo(true), $this->equalTo(IQueryBuilder::PARAM_BOOL)],
|
||||
[$this->equalTo('string'), $this->equalTo(IQueryBuilder::PARAM_STR)],
|
||||
[$this->equalTo(456), $this->equalTo(IQueryBuilder::PARAM_INT)],
|
||||
[$this->equalTo(false), $this->equalTo(IQueryBuilder::PARAM_BOOL)]
|
||||
[$this->equalTo(false), $this->equalTo(IQueryBuilder::PARAM_BOOL)],
|
||||
[$this->equalTo($datetime), $this->equalTo(IQueryBuilder::PARAM_DATETIME_IMMUTABLE)],
|
||||
);
|
||||
$this->qb->expects($this->exactly(5))
|
||||
$this->qb->expects($this->exactly(6))
|
||||
->method('setValue')
|
||||
->withConsecutive(
|
||||
[$this->equalTo('int_prop'), $this->equalTo($intParam)],
|
||||
[$this->equalTo('bool_prop'), $this->equalTo($boolParam)],
|
||||
[$this->equalTo('string_prop'), $this->equalTo($stringParam)],
|
||||
[$this->equalTo('integer_prop'), $this->equalTo($integerParam)],
|
||||
[$this->equalTo('boolean_prop'), $this->equalTo($booleanParam)]
|
||||
[$this->equalTo('boolean_prop'), $this->equalTo($booleanParam)],
|
||||
[$this->equalTo('datetime_prop'), $this->equalTo($datetimeParam)],
|
||||
);
|
||||
|
||||
$this->mapper->insert($entity);
|
||||
|
|
@ -146,6 +143,7 @@ class QBMapperTest extends \Test\TestCase {
|
|||
|
||||
|
||||
public function testUpdateEntityParameterTypeMapping(): void {
|
||||
$datetime = new \DateTimeImmutable();
|
||||
$entity = new QBTestEntity();
|
||||
$entity->setId(789);
|
||||
$entity->setIntProp(123);
|
||||
|
|
@ -154,6 +152,7 @@ class QBMapperTest extends \Test\TestCase {
|
|||
$entity->setIntegerProp(456);
|
||||
$entity->setBooleanProp(false);
|
||||
$entity->setJsonProp(['hello' => 'world']);
|
||||
$entity->setDatetimeProp($datetime);
|
||||
|
||||
$idParam = $this->qb->createNamedParameter('id', IQueryBuilder::PARAM_INT);
|
||||
$intParam = $this->qb->createNamedParameter('int_prop', IQueryBuilder::PARAM_INT);
|
||||
|
|
@ -162,8 +161,9 @@ class QBMapperTest extends \Test\TestCase {
|
|||
$integerParam = $this->qb->createNamedParameter('integer_prop', IQueryBuilder::PARAM_INT);
|
||||
$booleanParam = $this->qb->createNamedParameter('boolean_prop', IQueryBuilder::PARAM_BOOL);
|
||||
$jsonParam = $this->qb->createNamedParameter('json_prop', IQueryBuilder::PARAM_JSON);
|
||||
$datetimeParam = $this->qb->createNamedParameter('datetime_prop', IQueryBuilder::PARAM_DATETIME_IMMUTABLE);
|
||||
|
||||
$this->qb->expects($this->exactly(7))
|
||||
$this->qb->expects($this->exactly(8))
|
||||
->method('createNamedParameter')
|
||||
->withConsecutive(
|
||||
[$this->equalTo(123), $this->equalTo(IQueryBuilder::PARAM_INT)],
|
||||
|
|
@ -172,10 +172,11 @@ class QBMapperTest extends \Test\TestCase {
|
|||
[$this->equalTo(456), $this->equalTo(IQueryBuilder::PARAM_INT)],
|
||||
[$this->equalTo(false), $this->equalTo(IQueryBuilder::PARAM_BOOL)],
|
||||
[$this->equalTo(['hello' => 'world']), $this->equalTo(IQueryBuilder::PARAM_JSON)],
|
||||
[$this->equalTo($datetime), $this->equalTo(IQueryBuilder::PARAM_DATETIME_IMMUTABLE)],
|
||||
[$this->equalTo(789), $this->equalTo(IQueryBuilder::PARAM_INT)],
|
||||
);
|
||||
|
||||
$this->qb->expects($this->exactly(6))
|
||||
$this->qb->expects($this->exactly(7))
|
||||
->method('set')
|
||||
->withConsecutive(
|
||||
[$this->equalTo('int_prop'), $this->equalTo($intParam)],
|
||||
|
|
@ -183,7 +184,8 @@ class QBMapperTest extends \Test\TestCase {
|
|||
[$this->equalTo('string_prop'), $this->equalTo($stringParam)],
|
||||
[$this->equalTo('integer_prop'), $this->equalTo($integerParam)],
|
||||
[$this->equalTo('boolean_prop'), $this->equalTo($booleanParam)],
|
||||
[$this->equalTo('json_prop'), $this->equalTo($jsonParam)]
|
||||
[$this->equalTo('json_prop'), $this->equalTo($jsonParam)],
|
||||
[$this->equalTo('datetime_prop'), $this->equalTo($datetimeParam)],
|
||||
);
|
||||
|
||||
$this->expr->expects($this->once())
|
||||
|
|
@ -216,6 +218,9 @@ class QBMapperTest extends \Test\TestCase {
|
|||
$jsonType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'jsonProp');
|
||||
$this->assertEquals(IQueryBuilder::PARAM_JSON, $jsonType, 'JSON type property mapping incorrect');
|
||||
|
||||
$datetimeType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'datetimeProp');
|
||||
$this->assertEquals(IQueryBuilder::PARAM_DATETIME_IMMUTABLE, $datetimeType, 'DateTimeImmutable type property mapping incorrect');
|
||||
|
||||
$unknownType = $this->mapper->getParameterTypeForPropertyForTest($entity, 'someProp');
|
||||
$this->assertEquals(IQueryBuilder::PARAM_STR, $unknownType, 'Unknown type property mapping incorrect');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use OCP\Comments\IComment;
|
|||
use OCP\Comments\ICommentsEventHandler;
|
||||
use OCP\Comments\ICommentsManager;
|
||||
use OCP\Comments\NotFoundException;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\Files\Folder;
|
||||
use OCP\Files\IRootFolder;
|
||||
|
|
@ -70,11 +71,11 @@ class ManagerTest extends TestCase {
|
|||
'actor_id' => $qb->createNamedParameter('alice'),
|
||||
'message' => $qb->createNamedParameter('nice one'),
|
||||
'verb' => $qb->createNamedParameter('comment'),
|
||||
'creation_timestamp' => $qb->createNamedParameter($creationDT, 'datetime'),
|
||||
'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, 'datetime'),
|
||||
'creation_timestamp' => $qb->createNamedParameter($creationDT, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
'latest_child_timestamp' => $qb->createNamedParameter($latestChildDT, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
'object_type' => $qb->createNamedParameter('files'),
|
||||
'object_id' => $qb->createNamedParameter($objectId),
|
||||
'expire_date' => $qb->createNamedParameter($expireDate, 'datetime'),
|
||||
'expire_date' => $qb->createNamedParameter($expireDate, IQueryBuilder::PARAM_DATETIME_MUTABLE),
|
||||
'reference_id' => $qb->createNamedParameter('referenceId'),
|
||||
'meta_data' => $qb->createNamedParameter(json_encode(['last_edit_actor_id' => 'admin'])),
|
||||
])
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
namespace Test\DB\QueryBuilder;
|
||||
|
||||
use Doctrine\DBAL\Schema\SchemaException;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use OC\DB\QueryBuilder\Literal;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\DB\Types;
|
||||
use OCP\IConfig;
|
||||
use OCP\Server;
|
||||
use Test\TestCase;
|
||||
|
|
@ -145,13 +145,13 @@ class ExpressionBuilderDBTest extends TestCase {
|
|||
$dateTime = new \DateTime('2023-01-01');
|
||||
$insert = $this->connection->getQueryBuilder();
|
||||
$insert->insert('testing')
|
||||
->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE)])
|
||||
->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
|
||||
->executeStatement();
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$result = $query->select('*')
|
||||
->from('testing')
|
||||
->where($query->expr()->eq('datetime', $query->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE)))
|
||||
->where($query->expr()->eq('datetime', $query->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
|
||||
->executeQuery();
|
||||
$entries = $result->fetchAll();
|
||||
$result->closeCursor();
|
||||
|
|
@ -163,13 +163,13 @@ class ExpressionBuilderDBTest extends TestCase {
|
|||
$dateTimeCompare = new \DateTime('2022-01-02');
|
||||
$insert = $this->connection->getQueryBuilder();
|
||||
$insert->insert('testing')
|
||||
->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE)])
|
||||
->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
|
||||
->executeStatement();
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$result = $query->select('*')
|
||||
->from('testing')
|
||||
->where($query->expr()->lt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATE)))
|
||||
->where($query->expr()->lt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
|
||||
->executeQuery();
|
||||
$entries = $result->fetchAll();
|
||||
$result->closeCursor();
|
||||
|
|
@ -181,13 +181,13 @@ class ExpressionBuilderDBTest extends TestCase {
|
|||
$dateTimeCompare = new \DateTime('2023-01-01');
|
||||
$insert = $this->connection->getQueryBuilder();
|
||||
$insert->insert('testing')
|
||||
->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE)])
|
||||
->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)])
|
||||
->executeStatement();
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$result = $query->select('*')
|
||||
->from('testing')
|
||||
->where($query->expr()->gt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATE)))
|
||||
->where($query->expr()->gt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
|
||||
->executeQuery();
|
||||
$entries = $result->fetchAll();
|
||||
$result->closeCursor();
|
||||
|
|
@ -223,7 +223,7 @@ class ExpressionBuilderDBTest extends TestCase {
|
|||
'notnull' => true,
|
||||
]);
|
||||
|
||||
$table->addColumn('datetime', Types::DATETIME_MUTABLE, [
|
||||
$table->addColumn('datetime', Types::DATETIME, [
|
||||
'notnull' => false,
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
|
|||
$qb->setValue('token', $qb->expr()->literal($token));
|
||||
}
|
||||
if ($expiration) {
|
||||
$qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATE));
|
||||
$qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATETIME_MUTABLE));
|
||||
}
|
||||
if ($parent) {
|
||||
$qb->setValue('parent', $qb->expr()->literal($parent));
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ class ShareByMailProviderTest extends TestCase {
|
|||
$qb->setValue('token', $qb->expr()->literal($token));
|
||||
}
|
||||
if ($expiration) {
|
||||
$qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATE));
|
||||
$qb->setValue('expiration', $qb->createNamedParameter($expiration, IQueryBuilder::PARAM_DATETIME_MUTABLE));
|
||||
}
|
||||
if ($parent) {
|
||||
$qb->setValue('parent', $qb->expr()->literal($parent));
|
||||
|
|
|
|||
Loading…
Reference in a new issue