aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/DB
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/DB')
-rw-r--r--tests/lib/DB/AdapterTest.php69
-rw-r--r--tests/lib/DB/ConnectionFactoryTest.php11
-rw-r--r--tests/lib/DB/Exception/DbalExceptionTest.php4
-rw-r--r--tests/lib/DB/MigrationsTest.php277
-rw-r--r--tests/lib/DB/MigratorTest.php40
-rw-r--r--tests/lib/DB/OCPostgreSqlPlatformTest.php9
-rw-r--r--tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php48
-rw-r--r--tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php90
-rw-r--r--tests/lib/DB/QueryBuilder/FunctionBuilderTest.php92
-rw-r--r--tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php74
-rw-r--r--tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php223
-rw-r--r--tests/lib/DB/QueryBuilder/QueryBuilderTest.php287
-rw-r--r--tests/lib/DB/QueryBuilder/QuoteHelperTest.php13
-rw-r--r--tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php128
14 files changed, 1040 insertions, 325 deletions
diff --git a/tests/lib/DB/AdapterTest.php b/tests/lib/DB/AdapterTest.php
new file mode 100644
index 00000000000..394428337f1
--- /dev/null
+++ b/tests/lib/DB/AdapterTest.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\DB;
+
+use OCP\IDBConnection;
+use OCP\Server;
+use Test\TestCase;
+
+class AdapterTest extends TestCase {
+ private string $appId;
+ private $connection;
+
+ public function setUp(): void {
+ $this->connection = Server::get(IDBConnection::class);
+ $this->appId = substr(uniqid('test_db_adapter', true), 0, 32);
+ }
+
+ public function tearDown(): void {
+ $qb = $this->connection->getQueryBuilder();
+
+ $qb->delete('appconfig')
+ ->from('appconfig')
+ ->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId)))
+ ->execute();
+ }
+
+ public function testInsertIgnoreOnConflictDuplicate(): void {
+ $configKey = uniqid('key', true);
+ $expected = [
+ [
+ 'configkey' => $configKey,
+ 'configvalue' => '1',
+ ]
+ ];
+ $result = $this->connection->insertIgnoreConflict('appconfig', [
+ 'appid' => $this->appId,
+ 'configkey' => $configKey,
+ 'configvalue' => '1',
+ ]);
+ $this->assertEquals(1, $result);
+ $rows = $this->getRows($configKey);
+ $this->assertSame($expected, $rows);
+
+
+ $result = $this->connection->insertIgnoreConflict('appconfig', [
+ 'appid' => $this->appId,
+ 'configkey' => $configKey,
+ 'configvalue' => '2',
+ ]);
+ $this->assertEquals(0, $result);
+ $rows = $this->getRows($configKey);
+ $this->assertSame($expected, $rows);
+ }
+
+ private function getRows(string $configKey): array {
+ $qb = $this->connection->getQueryBuilder();
+ return $qb->select(['configkey', 'configvalue'])
+ ->from('appconfig')
+ ->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId)))
+ ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($configKey)))
+ ->execute()
+ ->fetchAll();
+ }
+}
diff --git a/tests/lib/DB/ConnectionFactoryTest.php b/tests/lib/DB/ConnectionFactoryTest.php
index 208f78f4512..d09a83ca856 100644
--- a/tests/lib/DB/ConnectionFactoryTest.php
+++ b/tests/lib/DB/ConnectionFactoryTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -8,10 +9,11 @@ namespace Test\DB;
use OC\DB\ConnectionFactory;
use OC\SystemConfig;
+use OCP\ICacheFactory;
use Test\TestCase;
class ConnectionFactoryTest extends TestCase {
- public function splitHostFromPortAndSocketData() {
+ public static function splitHostFromPortAndSocketData(): array {
return [
['127.0.0.1', ['host' => '127.0.0.1']],
['db.example.org', ['host' => 'db.example.org']],
@@ -26,14 +28,15 @@ class ConnectionFactoryTest extends TestCase {
}
/**
- * @dataProvider splitHostFromPortAndSocketData
* @param string $host
* @param array $expected
*/
- public function testSplitHostFromPortAndSocket($host, array $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('splitHostFromPortAndSocketData')]
+ public function testSplitHostFromPortAndSocket($host, array $expected): void {
/** @var SystemConfig $config */
$config = $this->createMock(SystemConfig::class);
- $factory = new ConnectionFactory($config);
+ $cacheFactory = $this->createMock(ICacheFactory::class);
+ $factory = new ConnectionFactory($config, $cacheFactory);
$this->assertEquals($expected, self::invokePrivate($factory, 'splitHostFromPortAndSocket', [$host]));
}
diff --git a/tests/lib/DB/Exception/DbalExceptionTest.php b/tests/lib/DB/Exception/DbalExceptionTest.php
index 470beff9080..eac74291749 100644
--- a/tests/lib/DB/Exception/DbalExceptionTest.php
+++ b/tests/lib/DB/Exception/DbalExceptionTest.php
@@ -35,16 +35,16 @@ class DbalExceptionTest extends \Test\TestCase {
}
/**
- * @dataProvider dataDriverException
* @param string $class
* @param int $reason
*/
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataDriverException')]
public function testDriverException(string $class, int $reason): void {
$result = DbalException::wrap(new $class($this->driverException, null));
$this->assertSame($reason, $result->getReason());
}
- public function dataDriverException(): array {
+ public static function dataDriverException(): array {
return [
[LockWaitTimeoutException::class, DbalException::REASON_LOCK_WAIT_TIMEOUT],
[ForeignKeyConstraintViolationException::class, DbalException::REASON_FOREIGN_KEY_VIOLATION],
diff --git a/tests/lib/DB/MigrationsTest.php b/tests/lib/DB/MigrationsTest.php
index 6cd489258bf..2b39b26d852 100644
--- a/tests/lib/DB/MigrationsTest.php
+++ b/tests/lib/DB/MigrationsTest.php
@@ -8,8 +8,6 @@
namespace Test\DB;
-use Doctrine\DBAL\Platforms\OraclePlatform;
-use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index;
@@ -21,8 +19,21 @@ use Doctrine\DBAL\Types\Type;
use OC\DB\Connection;
use OC\DB\MigrationService;
use OC\DB\SchemaWrapper;
+use OC\Migration\MetadataManager;
+use OCP\App\IAppManager;
use OCP\IDBConnection;
+use OCP\Migration\Attributes\AddColumn;
+use OCP\Migration\Attributes\AddIndex;
+use OCP\Migration\Attributes\ColumnType;
+use OCP\Migration\Attributes\CreateTable;
+use OCP\Migration\Attributes\DropColumn;
+use OCP\Migration\Attributes\DropIndex;
+use OCP\Migration\Attributes\DropTable;
+use OCP\Migration\Attributes\IndexType;
+use OCP\Migration\Attributes\ModifyColumn;
use OCP\Migration\IMigrationStep;
+use OCP\Server;
+use PHPUnit\Framework\MockObject\MockObject;
/**
* Class MigrationsTest
@@ -30,10 +41,9 @@ use OCP\Migration\IMigrationStep;
* @package Test\DB
*/
class MigrationsTest extends \Test\TestCase {
- /** @var MigrationService | \PHPUnit\Framework\MockObject\MockObject */
- private $migrationService;
- /** @var \PHPUnit\Framework\MockObject\MockObject | IDBConnection $db */
- private $db;
+ private MigrationService|MockObject $migrationService;
+ private MockObject|IDBConnection $db;
+ private IAppManager $appManager;
protected function setUp(): void {
parent::setUp();
@@ -41,16 +51,18 @@ class MigrationsTest extends \Test\TestCase {
$this->db = $this->createMock(Connection::class);
$this->db->expects($this->any())->method('getPrefix')->willReturn('test_oc_');
$this->migrationService = new MigrationService('testing', $this->db);
+
+ $this->appManager = Server::get(IAppManager::class);
}
- public function testGetters() {
+ public function testGetters(): void {
$this->assertEquals('testing', $this->migrationService->getApp());
$this->assertEquals(\OC::$SERVERROOT . '/apps/testing/lib/Migration', $this->migrationService->getMigrationsDirectory());
$this->assertEquals('OCA\Testing\Migration', $this->migrationService->getMigrationsNamespace());
$this->assertEquals('test_oc_migrations', $this->migrationService->getMigrationsTableName());
}
- public function testCore() {
+ public function testCore(): void {
$this->migrationService = new MigrationService('core', $this->db);
$this->assertEquals('core', $this->migrationService->getApp());
@@ -60,7 +72,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testExecuteUnknownStep() {
+ public function testExecuteUnknownStep(): void {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Version 20170130180000 is unknown.');
@@ -68,7 +80,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testUnknownApp() {
+ public function testUnknownApp(): void {
$this->expectException(\Exception::class);
$this->expectExceptionMessage('App not found');
@@ -76,12 +88,12 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testExecuteStepWithUnknownClass() {
+ public function testExecuteStepWithUnknownClass(): void {
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Migration step \'X\' is unknown');
$this->migrationService = $this->getMockBuilder(MigrationService::class)
- ->setMethods(['findMigrations'])
+ ->onlyMethods(['findMigrations'])
->setConstructorArgs(['testing', $this->db])
->getMock();
$this->migrationService->expects($this->any())->method('findMigrations')->willReturn(
@@ -90,7 +102,7 @@ class MigrationsTest extends \Test\TestCase {
$this->migrationService->executeStep('20170130180000');
}
- public function testExecuteStepWithSchemaChange() {
+ public function testExecuteStepWithSchemaChange(): void {
$schema = $this->createMock(Schema::class);
$this->db->expects($this->any())
->method('createSchema')
@@ -122,7 +134,7 @@ class MigrationsTest extends \Test\TestCase {
->method('postSchemaChange');
$this->migrationService = $this->getMockBuilder(MigrationService::class)
- ->setMethods(['createInstance'])
+ ->onlyMethods(['createInstance'])
->setConstructorArgs(['testing', $this->db])
->getMock();
@@ -133,7 +145,7 @@ class MigrationsTest extends \Test\TestCase {
$this->migrationService->executeStep('20170130180000');
}
- public function testExecuteStepWithoutSchemaChange() {
+ public function testExecuteStepWithoutSchemaChange(): void {
$schema = $this->createMock(Schema::class);
$this->db->expects($this->any())
->method('createSchema')
@@ -152,7 +164,7 @@ class MigrationsTest extends \Test\TestCase {
->method('postSchemaChange');
$this->migrationService = $this->getMockBuilder(MigrationService::class)
- ->setMethods(['createInstance'])
+ ->onlyMethods(['createInstance'])
->setConstructorArgs(['testing', $this->db])
->getMock();
@@ -163,7 +175,7 @@ class MigrationsTest extends \Test\TestCase {
$this->migrationService->executeStep('20170130180000');
}
- public function dataGetMigration() {
+ public static function dataGetMigration(): array {
return [
['current', '20170130180001'],
['prev', '20170130180000'],
@@ -173,13 +185,13 @@ class MigrationsTest extends \Test\TestCase {
}
/**
- * @dataProvider dataGetMigration
* @param string $alias
* @param string $expected
*/
- public function testGetMigration($alias, $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetMigration')]
+ public function testGetMigration($alias, $expected): void {
$this->migrationService = $this->getMockBuilder(MigrationService::class)
- ->setMethods(['getMigratedVersions', 'findMigrations'])
+ ->onlyMethods(['getMigratedVersions', 'findMigrations'])
->setConstructorArgs(['testing', $this->db])
->getMock();
$this->migrationService->expects($this->any())->method('getMigratedVersions')->willReturn(
@@ -197,28 +209,39 @@ class MigrationsTest extends \Test\TestCase {
$this->assertEquals($expected, $migration);
}
- public function testMigrate() {
+ public function testMigrate(): void {
$this->migrationService = $this->getMockBuilder(MigrationService::class)
- ->setMethods(['getMigratedVersions', 'findMigrations', 'executeStep'])
+ ->onlyMethods(['getMigratedVersions', 'findMigrations', 'executeStep'])
->setConstructorArgs(['testing', $this->db])
->getMock();
- $this->migrationService->expects($this->any())->method('getMigratedVersions')->willReturn(
- ['20170130180000', '20170130180001']
- );
- $this->migrationService->expects($this->any())->method('findMigrations')->willReturn(
- ['20170130180000' => 'X', '20170130180001' => 'Y', '20170130180002' => 'Z', '20170130180003' => 'A']
- );
+ $this->migrationService->method('getMigratedVersions')
+ ->willReturn(
+ ['20170130180000', '20170130180001']
+ );
+ $this->migrationService->method('findMigrations')
+ ->willReturn(
+ ['20170130180000' => 'X', '20170130180001' => 'Y', '20170130180002' => 'Z', '20170130180003' => 'A']
+ );
$this->assertEquals(
['20170130180000', '20170130180001', '20170130180002', '20170130180003'],
- $this->migrationService->getAvailableVersions());
+ $this->migrationService->getAvailableVersions()
+ );
- $this->migrationService->expects($this->exactly(2))->method('executeStep')
- ->withConsecutive(['20170130180002'], ['20170130180003']);
+ $calls = [
+ ['20170130180002', false],
+ ['20170130180003', false],
+ ];
+ $this->migrationService->expects($this->exactly(2))
+ ->method('executeStep')
+ ->willReturnCallback(function () use (&$calls): void {
+ $expected = array_shift($calls);
+ $this->assertEquals($expected, func_get_args());
+ });
$this->migrationService->migrate();
}
- public function testEnsureOracleConstraintsValid() {
+ public function testEnsureOracleConstraintsValid(): void {
$column = $this->createMock(Column::class);
$column->expects($this->once())
->method('getName')
@@ -281,7 +304,7 @@ class MigrationsTest extends \Test\TestCase {
self::invokePrivate($this->migrationService, 'ensureOracleConstraints', [$sourceSchema, $schema, 3]);
}
- public function testEnsureOracleConstraintsValidWithPrimaryKey() {
+ public function testEnsureOracleConstraintsValidWithPrimaryKey(): void {
$index = $this->createMock(Index::class);
$index->expects($this->any())
->method('getName')
@@ -324,11 +347,11 @@ class MigrationsTest extends \Test\TestCase {
self::invokePrivate($this->migrationService, 'ensureOracleConstraints', [$sourceSchema, $schema, 3]);
}
- public function testEnsureOracleConstraintsValidWithPrimaryKeyDefault() {
+ public function testEnsureOracleConstraintsValidWithPrimaryKeyDefault(): void {
$defaultName = 'PRIMARY';
- if ($this->db->getDatabasePlatform() instanceof PostgreSqlPlatform) {
+ if ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_POSTGRES) {
$defaultName = \str_repeat('a', 26) . '_' . \str_repeat('b', 30) . '_seq';
- } elseif ($this->db->getDatabasePlatform() instanceof OraclePlatform) {
+ } elseif ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) {
$defaultName = \str_repeat('a', 26) . '_seq';
}
@@ -378,7 +401,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsTooLongTableName() {
+ public function testEnsureOracleConstraintsTooLongTableName(): void {
$this->expectException(\InvalidArgumentException::class);
$table = $this->createMock(Table::class);
@@ -403,13 +426,13 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsTooLongPrimaryWithDefault() {
+ public function testEnsureOracleConstraintsTooLongPrimaryWithDefault(): void {
$this->expectException(\InvalidArgumentException::class);
$defaultName = 'PRIMARY';
- if ($this->db->getDatabasePlatform() instanceof PostgreSqlPlatform) {
+ if ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_POSTGRES) {
$defaultName = \str_repeat('a', 27) . '_' . \str_repeat('b', 30) . '_seq';
- } elseif ($this->db->getDatabasePlatform() instanceof OraclePlatform) {
+ } elseif ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) {
$defaultName = \str_repeat('a', 27) . '_seq';
}
@@ -456,7 +479,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsTooLongPrimaryWithName() {
+ public function testEnsureOracleConstraintsTooLongPrimaryWithName(): void {
$this->expectException(\InvalidArgumentException::class);
$index = $this->createMock(Index::class);
@@ -499,7 +522,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsTooLongColumnName() {
+ public function testEnsureOracleConstraintsTooLongColumnName(): void {
$this->expectException(\InvalidArgumentException::class);
$column = $this->createMock(Column::class);
@@ -533,7 +556,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsTooLongIndexName() {
+ public function testEnsureOracleConstraintsTooLongIndexName(): void {
$this->expectException(\InvalidArgumentException::class);
$index = $this->createMock(Index::class);
@@ -570,7 +593,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsTooLongForeignKeyName() {
+ public function testEnsureOracleConstraintsTooLongForeignKeyName(): void {
$this->expectException(\InvalidArgumentException::class);
$foreignKey = $this->createMock(ForeignKeyConstraint::class);
@@ -610,7 +633,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsNoPrimaryKey() {
+ public function testEnsureOracleConstraintsNoPrimaryKey(): void {
$this->markTestSkipped('Test disabled for now due to multiple reasons, see https://github.com/nextcloud/server/pull/31580#issuecomment-1069182234 for details.');
$this->expectException(\InvalidArgumentException::class);
@@ -651,7 +674,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsTooLongSequenceName() {
+ public function testEnsureOracleConstraintsTooLongSequenceName(): void {
$this->expectException(\InvalidArgumentException::class);
$sequence = $this->createMock(Sequence::class);
@@ -679,7 +702,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsBooleanNotNull() {
+ public function testEnsureOracleConstraintsBooleanNotNull(): void {
$this->expectException(\InvalidArgumentException::class);
$column = $this->createMock(Column::class);
@@ -719,7 +742,7 @@ class MigrationsTest extends \Test\TestCase {
}
- public function testEnsureOracleConstraintsStringLength4000() {
+ public function testEnsureOracleConstraintsStringLength4000(): void {
$this->expectException(\InvalidArgumentException::class);
$column = $this->createMock(Column::class);
@@ -757,4 +780,162 @@ class MigrationsTest extends \Test\TestCase {
self::invokePrivate($this->migrationService, 'ensureOracleConstraints', [$sourceSchema, $schema, 3]);
}
+
+
+ public function testExtractMigrationAttributes(): void {
+ $metadataManager = Server::get(MetadataManager::class);
+ $this->appManager->loadApp('testing');
+
+ $this->assertEquals($this->getMigrationMetadata(), json_decode(json_encode($metadataManager->extractMigrationAttributes('testing')), true));
+
+ $this->appManager->disableApp('testing');
+ }
+
+ public function testDeserializeMigrationMetadata(): void {
+ $metadataManager = Server::get(MetadataManager::class);
+ $this->assertEquals(
+ [
+ 'core' => [],
+ 'apps' => [
+ 'testing' => [
+ '30000Date20240102030405' => [
+ new DropTable('old_table'),
+ new CreateTable('new_table',
+ description: 'Table is used to store things, but also to get more things',
+ notes: ['this is a notice', 'and another one, if really needed']
+ ),
+ new AddColumn('my_table'),
+ new AddColumn('my_table', 'another_field'),
+ new AddColumn('other_table', 'last_one', ColumnType::DATE),
+ new AddIndex('my_table'),
+ new AddIndex('my_table', IndexType::PRIMARY),
+ new DropColumn('other_table'),
+ new DropColumn('other_table', 'old_column',
+ description: 'field is not used anymore and replaced by \'last_one\''
+ ),
+ new DropIndex('other_table'),
+ new ModifyColumn('other_table'),
+ new ModifyColumn('other_table', 'this_field'),
+ new ModifyColumn('other_table', 'this_field', ColumnType::BIGINT)
+ ]
+ ]
+ ]
+ ],
+ $metadataManager->getMigrationsAttributesFromReleaseMetadata(
+ [
+ 'core' => [],
+ 'apps' => ['testing' => $this->getMigrationMetadata()]
+ ]
+ )
+ );
+ }
+
+ private function getMigrationMetadata(): array {
+ return [
+ '30000Date20240102030405' => [
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\DropTable',
+ 'table' => 'old_table',
+ 'description' => '',
+ 'notes' => [],
+ 'columns' => []
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\CreateTable',
+ 'table' => 'new_table',
+ 'description' => 'Table is used to store things, but also to get more things',
+ 'notes' => [
+ 'this is a notice',
+ 'and another one, if really needed'
+ ],
+ 'columns' => []
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\AddColumn',
+ 'table' => 'my_table',
+ 'description' => '',
+ 'notes' => [],
+ 'name' => '',
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\AddColumn',
+ 'table' => 'my_table',
+ 'description' => '',
+ 'notes' => [],
+ 'name' => 'another_field',
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\AddColumn',
+ 'table' => 'other_table',
+ 'description' => '',
+ 'notes' => [],
+ 'name' => 'last_one',
+ 'type' => 'date'
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\AddIndex',
+ 'table' => 'my_table',
+ 'description' => '',
+ 'notes' => [],
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\AddIndex',
+ 'table' => 'my_table',
+ 'description' => '',
+ 'notes' => [],
+ 'type' => 'primary'
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\DropColumn',
+ 'table' => 'other_table',
+ 'description' => '',
+ 'notes' => [],
+ 'name' => '',
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\DropColumn',
+ 'table' => 'other_table',
+ 'description' => 'field is not used anymore and replaced by \'last_one\'',
+ 'notes' => [],
+ 'name' => 'old_column',
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\DropIndex',
+ 'table' => 'other_table',
+ 'description' => '',
+ 'notes' => [],
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn',
+ 'table' => 'other_table',
+ 'description' => '',
+ 'notes' => [],
+ 'name' => '',
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn',
+ 'table' => 'other_table',
+ 'description' => '',
+ 'notes' => [],
+ 'name' => 'this_field',
+ 'type' => ''
+ ],
+ [
+ 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn',
+ 'table' => 'other_table',
+ 'description' => '',
+ 'notes' => [],
+ 'name' => 'this_field',
+ 'type' => 'bigint'
+ ],
+ ]
+ ];
+ }
}
diff --git a/tests/lib/DB/MigratorTest.php b/tests/lib/DB/MigratorTest.php
index eaa6540b93b..9d8ee6791a9 100644
--- a/tests/lib/DB/MigratorTest.php
+++ b/tests/lib/DB/MigratorTest.php
@@ -10,16 +10,16 @@ namespace Test\DB;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\ParameterType;
-use Doctrine\DBAL\Platforms\OraclePlatform;
-use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaConfig;
use OC\DB\Migrator;
use OC\DB\OracleMigrator;
use OC\DB\SQLiteMigrator;
use OCP\DB\Types;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
-use OCP\Security\ISecureRandom;
+use OCP\IDBConnection;
+use OCP\Server;
/**
* Class MigratorTest
@@ -48,20 +48,18 @@ class MigratorTest extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
- $this->config = \OC::$server->getConfig();
- $this->connection = \OC::$server->get(\OC\DB\Connection::class);
+ $this->config = Server::get(IConfig::class);
+ $this->connection = Server::get(\OC\DB\Connection::class);
$this->tableName = $this->getUniqueTableName();
$this->tableNameTmp = $this->getUniqueTableName();
}
private function getMigrator(): Migrator {
- $platform = $this->connection->getDatabasePlatform();
- $random = \OC::$server->get(ISecureRandom::class);
- $dispatcher = \OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class);
- if ($platform instanceof SqlitePlatform) {
+ $dispatcher = Server::get(IEventDispatcher::class);
+ if ($this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_SQLITE) {
return new SQLiteMigrator($this->connection, $this->config, $dispatcher);
- } elseif ($platform instanceof OraclePlatform) {
+ } elseif ($this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) {
return new OracleMigrator($this->connection, $this->config, $dispatcher);
}
return new Migrator($this->connection, $this->config, $dispatcher);
@@ -130,7 +128,7 @@ class MigratorTest extends \Test\TestCase {
return $config;
}
- public function testUpgrade() {
+ public function testUpgrade(): void {
[$startSchema, $endSchema] = $this->getDuplicateKeySchemas();
$migrator = $this->getMigrator();
$migrator->migrate($startSchema);
@@ -143,7 +141,7 @@ class MigratorTest extends \Test\TestCase {
$this->addToAssertionCount(1);
}
- public function testUpgradeDifferentPrefix() {
+ public function testUpgradeDifferentPrefix(): void {
$oldTablePrefix = $this->config->getSystemValueString('dbtableprefix', 'oc_');
$this->config->setSystemValue('dbtableprefix', 'ownc_');
@@ -163,7 +161,7 @@ class MigratorTest extends \Test\TestCase {
$this->config->setSystemValue('dbtableprefix', $oldTablePrefix);
}
- public function testInsertAfterUpgrade() {
+ public function testInsertAfterUpgrade(): void {
[$startSchema, $endSchema] = $this->getDuplicateKeySchemas();
$migrator = $this->getMigrator();
$migrator->migrate($startSchema);
@@ -180,7 +178,7 @@ class MigratorTest extends \Test\TestCase {
}
}
- public function testAddingPrimaryKeyWithAutoIncrement() {
+ public function testAddingPrimaryKeyWithAutoIncrement(): void {
$startSchema = new Schema([], [], $this->getSchemaConfig());
$table = $startSchema->createTable($this->tableName);
$table->addColumn('id', 'integer');
@@ -200,7 +198,7 @@ class MigratorTest extends \Test\TestCase {
$this->addToAssertionCount(1);
}
- public function testReservedKeywords() {
+ public function testReservedKeywords(): void {
$startSchema = new Schema([], [], $this->getSchemaConfig());
$table = $startSchema->createTable($this->tableName);
$table->addColumn('id', 'integer', ['autoincrement' => true]);
@@ -224,7 +222,7 @@ class MigratorTest extends \Test\TestCase {
/**
* Test for nextcloud/server#36803
*/
- public function testColumnCommentsInUpdate() {
+ public function testColumnCommentsInUpdate(): void {
$startSchema = new Schema([], [], $this->getSchemaConfig());
$table = $startSchema->createTable($this->tableName);
$table->addColumn('id', 'integer', ['autoincrement' => true, 'comment' => 'foo']);
@@ -245,14 +243,14 @@ class MigratorTest extends \Test\TestCase {
$this->addToAssertionCount(1);
}
- public function testAddingForeignKey() {
+ public function testAddingForeignKey(): void {
$startSchema = new Schema([], [], $this->getSchemaConfig());
$table = $startSchema->createTable($this->tableName);
$table->addColumn('id', 'integer', ['autoincrement' => true]);
$table->addColumn('name', 'string');
$table->setPrimaryKey(['id']);
- $fkName = "fkc";
+ $fkName = 'fkc';
$tableFk = $startSchema->createTable($this->tableNameTmp);
$tableFk->addColumn('fk_id', 'integer');
$tableFk->addColumn('name', 'string');
@@ -265,7 +263,7 @@ class MigratorTest extends \Test\TestCase {
$this->assertTrue($startSchema->getTable($this->tableNameTmp)->hasForeignKey($fkName));
}
- public function dataNotNullEmptyValuesFailOracle(): array {
+ public static function dataNotNullEmptyValuesFailOracle(): array {
return [
[ParameterType::BOOLEAN, true, Types::BOOLEAN, false],
[ParameterType::BOOLEAN, false, Types::BOOLEAN, true],
@@ -281,13 +279,13 @@ class MigratorTest extends \Test\TestCase {
}
/**
- * @dataProvider dataNotNullEmptyValuesFailOracle
*
* @param int $parameterType
* @param bool|int|string $value
* @param string $columnType
* @param bool $oracleThrows
*/
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataNotNullEmptyValuesFailOracle')]
public function testNotNullEmptyValuesFailOracle(int $parameterType, $value, string $columnType, bool $oracleThrows): void {
$startSchema = new Schema([], [], $this->getSchemaConfig());
$table = $startSchema->createTable($this->tableName);
@@ -300,7 +298,7 @@ class MigratorTest extends \Test\TestCase {
$migrator = $this->getMigrator();
$migrator->migrate($startSchema);
- if ($oracleThrows && $this->connection->getDatabasePlatform() instanceof OraclePlatform) {
+ if ($oracleThrows && $this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) {
// Oracle can not store false|empty string in notnull columns
$this->expectException(\Doctrine\DBAL\Exception\NotNullConstraintViolationException::class);
}
diff --git a/tests/lib/DB/OCPostgreSqlPlatformTest.php b/tests/lib/DB/OCPostgreSqlPlatformTest.php
index 4f83e866a7c..af17b01fc13 100644
--- a/tests/lib/DB/OCPostgreSqlPlatformTest.php
+++ b/tests/lib/DB/OCPostgreSqlPlatformTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2017 ownCloud, Inc.
@@ -7,7 +8,7 @@
namespace Test\DB;
-use Doctrine\DBAL\Platforms\PostgreSQL100Platform;
+use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Types;
@@ -23,8 +24,8 @@ use Doctrine\DBAL\Types\Types;
* @package Test\DB
*/
class OCPostgreSqlPlatformTest extends \Test\TestCase {
- public function testAlterBigint() {
- $platform = new PostgreSQL100Platform();
+ public function testAlterBigint(): void {
+ $platform = new PostgreSQLPlatform();
$sourceSchema = new Schema();
$targetSchema = new Schema();
@@ -48,7 +49,7 @@ class OCPostgreSqlPlatformTest extends \Test\TestCase {
}
protected function createTableAndColumn($schema, $type) {
- $table = $schema->createTable("poor_yorick");
+ $table = $schema->createTable('poor_yorick');
$table->addColumn('id', $type, [
'autoincrement' => true,
'unsigned' => true,
diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php
index 671bcfc209e..153993f396e 100644
--- a/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php
+++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
@@ -7,10 +8,11 @@
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\IDBConnection;
use OCP\Server;
use Test\TestCase;
@@ -18,19 +20,19 @@ use Test\TestCase;
* @group DB
*/
class ExpressionBuilderDBTest extends TestCase {
- /** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */
+ /** @var \Doctrine\DBAL\Connection|IDBConnection */
protected $connection;
protected $schemaSetup = false;
protected function setUp(): void {
parent::setUp();
- $this->connection = \OC::$server->getDatabaseConnection();
+ $this->connection = Server::get(IDBConnection::class);
$this->prepareTestingTable();
}
- public function likeProvider() {
- $connection = \OC::$server->getDatabaseConnection();
+ public static function likeProvider(): array {
+ $connection = Server::get(IDBConnection::class);
return [
['foo', 'bar', false],
@@ -46,13 +48,13 @@ class ExpressionBuilderDBTest extends TestCase {
}
/**
- * @dataProvider likeProvider
*
* @param string $param1
* @param string $param2
* @param boolean $match
*/
- public function testLike($param1, $param2, $match) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('likeProvider')]
+ public function testLike($param1, $param2, $match): void {
$query = $this->connection->getQueryBuilder();
$query->select(new Literal('1'))
@@ -65,8 +67,8 @@ class ExpressionBuilderDBTest extends TestCase {
$this->assertEquals($match, $column);
}
- public function ilikeProvider() {
- $connection = \OC::$server->getDatabaseConnection();
+ public static function ilikeProvider(): array {
+ $connection = Server::get(IDBConnection::class);
return [
['foo', 'bar', false],
@@ -83,13 +85,13 @@ class ExpressionBuilderDBTest extends TestCase {
}
/**
- * @dataProvider ilikeProvider
*
* @param string $param1
* @param string $param2
* @param boolean $match
*/
- public function testILike($param1, $param2, $match) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('ilikeProvider')]
+ public function testILike($param1, $param2, $match): void {
$query = $this->connection->getQueryBuilder();
$query->select(new Literal('1'))
@@ -141,53 +143,53 @@ class ExpressionBuilderDBTest extends TestCase {
self::assertEquals('myvalue', $entries[0]['configvalue']);
}
- public function testDateTimeEquals() {
+ public function testDateTimeEquals(): void {
$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();
self::assertCount(1, $entries);
}
- public function testDateTimeLess() {
+ public function testDateTimeLess(): void {
$dateTime = new \DateTime('2022-01-01');
$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();
self::assertCount(1, $entries);
}
- public function testDateTimeGreater() {
+ public function testDateTimeGreater(): void {
$dateTime = new \DateTime('2023-01-02');
$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();
@@ -199,8 +201,8 @@ class ExpressionBuilderDBTest extends TestCase {
$query->insert('appconfig')
->values([
'appid' => $query->createNamedParameter($appId),
- 'configkey' => $query->createNamedParameter((string) $key),
- 'configvalue' => $query->createNamedParameter((string) $value),
+ 'configkey' => $query->createNamedParameter((string)$key),
+ 'configvalue' => $query->createNamedParameter((string)$value),
])
->execute();
}
@@ -223,7 +225,7 @@ class ExpressionBuilderDBTest extends TestCase {
'notnull' => true,
]);
- $table->addColumn('datetime', Types::DATETIME_MUTABLE, [
+ $table->addColumn('datetime', Types::DATETIME, [
'notnull' => false,
]);
diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
index d8147035b16..1f84ebfbec1 100644
--- a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
+++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -10,6 +11,9 @@ namespace Test\DB\QueryBuilder;
use Doctrine\DBAL\Query\Expression\ExpressionBuilder as DoctrineExpressionBuilder;
use OC\DB\QueryBuilder\ExpressionBuilder\ExpressionBuilder;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\Server;
+use Psr\Log\LoggerInterface;
use Test\TestCase;
/**
@@ -26,27 +30,31 @@ class ExpressionBuilderTest extends TestCase {
/** @var DoctrineExpressionBuilder */
protected $doctrineExpressionBuilder;
- /** @var \OCP\IDBConnection */
+ /** @var IDBConnection */
protected $connection;
/** @var \Doctrine\DBAL\Connection */
protected $internalConnection;
+ /** @var LoggerInterface */
+ protected $logger;
+
protected function setUp(): void {
parent::setUp();
- $this->connection = \OC::$server->getDatabaseConnection();
- $this->internalConnection = \OC::$server->get(\OC\DB\Connection::class);
+ $this->connection = Server::get(IDBConnection::class);
+ $this->internalConnection = Server::get(\OC\DB\Connection::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
$queryBuilder = $this->createMock(IQueryBuilder::class);
- $this->expressionBuilder = new ExpressionBuilder($this->connection, $queryBuilder);
+ $this->expressionBuilder = new ExpressionBuilder($this->connection, $queryBuilder, $this->logger);
$this->doctrineExpressionBuilder = new DoctrineExpressionBuilder($this->internalConnection);
}
- public function dataComparison() {
- $valueSets = $this->dataComparisons();
+ public static function dataComparison(): array {
+ $valueSets = self::dataComparisons();
$comparisonOperators = ['=', '<>', '<', '>', '<=', '>='];
$testSets = [];
@@ -59,7 +67,6 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataComparison
*
* @param string $comparison
* @param mixed $input1
@@ -67,7 +74,8 @@ class ExpressionBuilderTest extends TestCase {
* @param mixed $input2
* @param bool $isInput2Literal
*/
- public function testComparison($comparison, $input1, $isInput1Literal, $input2, $isInput2Literal) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataComparison')]
+ public function testComparison($comparison, $input1, $isInput1Literal, $input2, $isInput2Literal): void {
[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
@@ -77,7 +85,7 @@ class ExpressionBuilderTest extends TestCase {
);
}
- public function dataComparisons() {
+ public static function dataComparisons(): array {
return [
['value', false, 'value', false],
['value', false, 'value', true],
@@ -87,14 +95,14 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataComparisons
*
* @param mixed $input1
* @param bool $isInput1Literal
* @param mixed $input2
* @param bool $isInput2Literal
*/
- public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
+ public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
@@ -105,14 +113,14 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataComparisons
*
* @param mixed $input1
* @param bool $isInput1Literal
* @param mixed $input2
* @param bool $isInput2Literal
*/
- public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Literal) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
+ public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
@@ -123,14 +131,14 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataComparisons
*
* @param mixed $input1
* @param bool $isInput1Literal
* @param mixed $input2
* @param bool $isInput2Literal
*/
- public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Literal) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
+ public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Literal): void {
[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
@@ -141,14 +149,14 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataComparisons
*
* @param mixed $input1
* @param bool $isInput1Literal
* @param mixed $input2
* @param bool $isInput2Literal
*/
- public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
+ public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
@@ -159,14 +167,14 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataComparisons
*
* @param mixed $input1
* @param bool $isInput1Literal
* @param mixed $input2
* @param bool $isInput2Literal
*/
- public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Literal) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
+ public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Literal): void {
[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
@@ -177,14 +185,14 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataComparisons
*
* @param mixed $input1
* @param bool $isInput1Literal
* @param mixed $input2
* @param bool $isInput2Literal
*/
- public function testGreaterThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')]
+ public function testGreaterThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void {
[$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal);
[$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal);
@@ -194,21 +202,21 @@ class ExpressionBuilderTest extends TestCase {
);
}
- public function testIsNull() {
+ public function testIsNull(): void {
$this->assertEquals(
$this->doctrineExpressionBuilder->isNull('`test`'),
$this->expressionBuilder->isNull('test')
);
}
- public function testIsNotNull() {
+ public function testIsNotNull(): void {
$this->assertEquals(
$this->doctrineExpressionBuilder->isNotNull('`test`'),
$this->expressionBuilder->isNotNull('test')
);
}
- public function dataLike() {
+ public static function dataLike(): array {
return [
['value', false],
['value', true],
@@ -216,12 +224,12 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataLike
*
* @param mixed $input
* @param bool $isLiteral
*/
- public function testLike($input, $isLiteral) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')]
+ public function testLike($input, $isLiteral): void {
[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
$this->assertEquals(
@@ -231,12 +239,12 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataLike
*
* @param mixed $input
* @param bool $isLiteral
*/
- public function testNotLike($input, $isLiteral) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')]
+ public function testNotLike($input, $isLiteral): void {
[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
$this->assertEquals(
@@ -245,7 +253,7 @@ class ExpressionBuilderTest extends TestCase {
);
}
- public function dataIn() {
+ public static function dataIn(): array {
return [
['value', false],
['value', true],
@@ -255,12 +263,12 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataIn
*
* @param mixed $input
* @param bool $isLiteral
*/
- public function testIn($input, $isLiteral) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')]
+ public function testIn($input, $isLiteral): void {
[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
$this->assertEquals(
@@ -270,12 +278,12 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataIn
*
* @param mixed $input
* @param bool $isLiteral
*/
- public function testNotIn($input, $isLiteral) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')]
+ public function testNotIn($input, $isLiteral): void {
[$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral);
$this->assertEquals(
@@ -312,7 +320,7 @@ class ExpressionBuilderTest extends TestCase {
return [$doctrineInput, $ocInput];
}
- public function dataLiteral() {
+ public static function dataLiteral(): array {
return [
['value', null],
['1', null],
@@ -324,12 +332,12 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataLiteral
*
* @param mixed $input
* @param string|null $type
*/
- public function testLiteral($input, $type) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataLiteral')]
+ public function testLiteral($input, $type): void {
/** @var \OC\DB\QueryBuilder\Literal $actual */
$actual = $this->expressionBuilder->literal($input, $type);
@@ -340,7 +348,7 @@ class ExpressionBuilderTest extends TestCase {
);
}
- public function dataClobComparisons() {
+ public static function dataClobComparisons(): array {
return [
['eq', '5', IQueryBuilder::PARAM_STR, false, 3],
['eq', '5', IQueryBuilder::PARAM_STR, true, 1],
@@ -368,14 +376,14 @@ class ExpressionBuilderTest extends TestCase {
}
/**
- * @dataProvider dataClobComparisons
* @param string $function
* @param mixed $value
* @param mixed $type
* @param bool $compareKeyToValue
* @param int $expected
*/
- public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataClobComparisons')]
+ public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected): void {
$appId = $this->getUniqueID('testing');
$this->createConfig($appId, 1, 4);
$this->createConfig($appId, 2, 5);
@@ -415,8 +423,8 @@ class ExpressionBuilderTest extends TestCase {
$query->insert('appconfig')
->values([
'appid' => $query->createNamedParameter($appId),
- 'configkey' => $query->createNamedParameter((string) $key),
- 'configvalue' => $query->createNamedParameter((string) $value),
+ 'configkey' => $query->createNamedParameter((string)$key),
+ 'configvalue' => $query->createNamedParameter((string)$value),
])
->execute();
}
diff --git a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
index d991c78f113..5a111c91aa7 100644
--- a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
+++ b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
@@ -8,6 +9,8 @@ namespace Test\DB\QueryBuilder;
use OC\DB\QueryBuilder\Literal;
use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\Server;
use Test\TestCase;
/**
@@ -18,19 +21,17 @@ use Test\TestCase;
* @package Test\DB\QueryBuilder
*/
class FunctionBuilderTest extends TestCase {
- /** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */
+ /** @var \Doctrine\DBAL\Connection|IDBConnection */
protected $connection;
protected function setUp(): void {
parent::setUp();
- $this->connection = \OC::$server->getDatabaseConnection();
+ $this->connection = Server::get(IDBConnection::class);
}
- /**
- * @dataProvider providerTestConcatString
- */
- public function testConcatString($closure) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('providerTestConcatString')]
+ public function testConcatString($closure): void {
$query = $this->connection->getQueryBuilder();
[$real, $arguments, $return] = $closure($query);
if ($real) {
@@ -49,39 +50,39 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals($return, $column);
}
- public function providerTestConcatString(): array {
+ public static function providerTestConcatString(): array {
return [
- '1 column: string param unicode' =>
- [function ($q) {
+ '1 column: string param unicode'
+ => [function ($q) {
return [false, [$q->createNamedParameter('👍')], '👍'];
}],
- '2 columns: string param and string param' =>
- [function ($q) {
+ '2 columns: string param and string param'
+ => [function ($q) {
return [false, [$q->createNamedParameter('foo'), $q->createNamedParameter('bar')], 'foobar'];
}],
- '2 columns: string param and int literal' =>
- [function ($q) {
+ '2 columns: string param and int literal'
+ => [function ($q) {
return [false, [$q->createNamedParameter('foo'), $q->expr()->literal(1)], 'foo1'];
}],
- '2 columns: string param and string literal' =>
- [function ($q) {
+ '2 columns: string param and string literal'
+ => [function ($q) {
return [false, [$q->createNamedParameter('foo'), $q->expr()->literal('bar')], 'foobar'];
}],
- '2 columns: string real and int literal' =>
- [function ($q) {
+ '2 columns: string real and int literal'
+ => [function ($q) {
return [true, ['configkey', $q->expr()->literal(2)], '12'];
}],
- '4 columns: string literal' =>
- [function ($q) {
+ '4 columns: string literal'
+ => [function ($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) {
+ '4 columns: int literal'
+ => [function ($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) {
- return [false, [$q->createNamedParameter("b"), $q->createNamedParameter("'"), $q->createNamedParameter('||'), $q->createNamedParameter(','), $q->createNamedParameter('a')], "b'||,a"];
+ '5 columns: string param with special chars used in the function'
+ => [function ($q) {
+ return [false, [$q->createNamedParameter('b'), $q->createNamedParameter("'"), $q->createNamedParameter('||'), $q->createNamedParameter(','), $q->createNamedParameter('a')], "b'||,a"];
}],
];
}
@@ -232,7 +233,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEqualsCanonicalizing([1,2,3], $actual);
}
- public function testMd5() {
+ public function testMd5(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->md5($query->createNamedParameter('foobar')));
@@ -245,7 +246,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(md5('foobar'), $column);
}
- public function testSubstring() {
+ public function testSubstring(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->substring($query->createNamedParameter('foobar'), new Literal(2), $query->createNamedParameter(2)));
@@ -258,7 +259,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals('oo', $column);
}
- public function testSubstringNoLength() {
+ public function testSubstringNoLength(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->substring($query->createNamedParameter('foobar'), new Literal(2)));
@@ -271,7 +272,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals('oobar', $column);
}
- public function testLower() {
+ public function testLower(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->lower($query->createNamedParameter('FooBar')));
@@ -284,7 +285,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals('foobar', $column);
}
- public function testAdd() {
+ public function testAdd(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->add($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1)));
@@ -297,7 +298,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(3, $column);
}
- public function testSubtract() {
+ public function testSubtract(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->subtract($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1)));
@@ -310,7 +311,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(1, $column);
}
- public function testCount() {
+ public function testCount(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->count('appid'));
@@ -323,7 +324,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertGreaterThan(1, $column);
}
- public function octetLengthProvider() {
+ public static function octetLengthProvider(): array {
return [
['', 0],
['foobar', 6],
@@ -332,10 +333,8 @@ class FunctionBuilderTest extends TestCase {
];
}
- /**
- * @dataProvider octetLengthProvider
- */
- public function testOctetLength(string $str, int $bytes) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('octetLengthProvider')]
+ public function testOctetLength(string $str, int $bytes): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->octetLength($query->createNamedParameter($str, IQueryBuilder::PARAM_STR)));
@@ -348,7 +347,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals($bytes, $column);
}
- public function charLengthProvider() {
+ public static function charLengthProvider(): array {
return [
['', 0],
['foobar', 6],
@@ -357,10 +356,8 @@ class FunctionBuilderTest extends TestCase {
];
}
- /**
- * @dataProvider charLengthProvider
- */
- public function testCharLength(string $str, int $bytes) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('charLengthProvider')]
+ public function testCharLength(string $str, int $bytes): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->charLength($query->createNamedParameter($str, IQueryBuilder::PARAM_STR)));
@@ -370,6 +367,7 @@ class FunctionBuilderTest extends TestCase {
$result = $query->execute();
$column = $result->fetchOne();
$result->closeCursor();
+ $this->assertNotNull($column);
$this->assertEquals($bytes, $column);
}
@@ -393,7 +391,7 @@ class FunctionBuilderTest extends TestCase {
$query->execute();
}
- public function testMaxEmpty() {
+ public function testMaxEmpty(): void {
$this->clearMinMax();
$query = $this->connection->getQueryBuilder();
@@ -409,7 +407,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(null, $row);
}
- public function testMinEmpty() {
+ public function testMinEmpty(): void {
$this->clearMinMax();
$query = $this->connection->getQueryBuilder();
@@ -425,7 +423,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(null, $row);
}
- public function testMax() {
+ public function testMax(): void {
$this->clearMinMax();
$this->setUpMinMax(10);
$this->setUpMinMax(11);
@@ -444,7 +442,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(20, $row);
}
- public function testMin() {
+ public function testMin(): void {
$this->clearMinMax();
$this->setUpMinMax(10);
$this->setUpMinMax(11);
@@ -463,7 +461,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(10, $row);
}
- public function testGreatest() {
+ public function testGreatest(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->greatest($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1)));
@@ -476,7 +474,7 @@ class FunctionBuilderTest extends TestCase {
$this->assertEquals(2, $row);
}
- public function testLeast() {
+ public function testLeast(): void {
$query = $this->connection->getQueryBuilder();
$query->select($query->func()->least($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1)));
diff --git a/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php b/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php
new file mode 100644
index 00000000000..8f84d6a0d2c
--- /dev/null
+++ b/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php
@@ -0,0 +1,74 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Robin Appelman <robin@icewind.nl>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace lib\DB\QueryBuilder\Partitioned;
+
+use OC\DB\ConnectionAdapter;
+use OC\DB\QueryBuilder\Partitioned\JoinCondition;
+use OC\DB\QueryBuilder\QueryBuilder;
+use OC\SystemConfig;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use Psr\Log\LoggerInterface;
+use Test\TestCase;
+
+class JoinConditionTest extends TestCase {
+ protected function setUp(): void {
+ parent::setUp();
+ }
+
+ public static function platformProvider(): array {
+ return [
+ [IDBConnection::PLATFORM_SQLITE],
+ [IDBConnection::PLATFORM_POSTGRES],
+ [IDBConnection::PLATFORM_MYSQL],
+ [IDBConnection::PLATFORM_ORACLE],
+ ];
+ }
+
+ private function getBuilder(string $platform): IQueryBuilder {
+ $connection = $this->createMock(ConnectionAdapter::class);
+ $connection->method('getDatabaseProvider')->willReturn($platform);
+ return new QueryBuilder(
+ $connection,
+ $this->createMock(SystemConfig::class),
+ $this->createMock(LoggerInterface::class)
+ );
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('platformProvider')]
+ public function testParseCondition(string $platform): void {
+ $query = $this->getBuilder($platform);
+ $param1 = $query->createNamedParameter('files');
+ $param2 = $query->createNamedParameter('test');
+ $condition = $query->expr()->andX(
+ $query->expr()->eq('tagmap.categoryid', 'tag.id'),
+ $query->expr()->eq('tag.type', $param1),
+ $query->expr()->eq('tag.uid', $param2)
+ );
+ $parsed = JoinCondition::parse($condition, 'vcategory', 'tag', 'tagmap');
+ $this->assertEquals('tagmap.categoryid', $parsed->fromColumn);
+ $this->assertEquals('tag.id', $parsed->toColumn);
+ $this->assertEquals([], $parsed->fromConditions);
+ $this->assertEquals([
+ $query->expr()->eq('tag.type', $param1),
+ $query->expr()->eq('tag.uid', $param2),
+ ], $parsed->toConditions);
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('platformProvider')]
+ public function testParseCastCondition(string $platform): void {
+ $query = $this->getBuilder($platform);
+
+ $condition = $query->expr()->eq($query->expr()->castColumn('m.objectid', IQueryBuilder::PARAM_INT), 'f.fileid');
+ $parsed = JoinCondition::parse($condition, 'filecache', 'f', 'm');
+ $this->assertEquals('m.objectid', $parsed->fromColumn);
+ $this->assertEquals('f.fileid', $parsed->toColumn);
+ $this->assertEquals([], $parsed->fromConditions);
+ }
+}
diff --git a/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php b/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php
new file mode 100644
index 00000000000..f99adc73aa8
--- /dev/null
+++ b/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php
@@ -0,0 +1,223 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+declare(strict_types=1);
+
+namespace Test\DB\QueryBuilder\Partitioned;
+
+use OC\DB\QueryBuilder\Partitioned\PartitionedQueryBuilder;
+use OC\DB\QueryBuilder\Partitioned\PartitionSplit;
+use OC\DB\QueryBuilder\Sharded\AutoIncrementHandler;
+use OC\DB\QueryBuilder\Sharded\ShardConnectionManager;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\Server;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class PartitionedQueryBuilderTest extends TestCase {
+ private IDBConnection $connection;
+ private ShardConnectionManager $shardConnectionManager;
+ private AutoIncrementHandler $autoIncrementHandler;
+
+ protected function setUp(): void {
+ if (PHP_INT_SIZE < 8) {
+ $this->markTestSkipped('Test requires 64bit');
+ }
+ $this->connection = Server::get(IDBConnection::class);
+ $this->shardConnectionManager = Server::get(ShardConnectionManager::class);
+ $this->autoIncrementHandler = Server::get(AutoIncrementHandler::class);
+
+ $this->setupFileCache();
+ }
+
+ protected function tearDown(): void {
+ $this->cleanupDb();
+ parent::tearDown();
+ }
+
+
+ private function getQueryBuilder(): PartitionedQueryBuilder {
+ $builder = $this->connection->getQueryBuilder();
+ if ($builder instanceof PartitionedQueryBuilder) {
+ return $builder;
+ } else {
+ return new PartitionedQueryBuilder($builder, [], $this->shardConnectionManager, $this->autoIncrementHandler);
+ }
+ }
+
+ private function setupFileCache(): void {
+ $this->cleanupDb();
+ $query = $this->getQueryBuilder();
+ $query->insert('storages')
+ ->values([
+ 'numeric_id' => $query->createNamedParameter(1001001, IQueryBuilder::PARAM_INT),
+ 'id' => $query->createNamedParameter('test1'),
+ ]);
+ $query->executeStatement();
+
+ $query = $this->getQueryBuilder();
+ $query->insert('filecache')
+ ->values([
+ 'storage' => $query->createNamedParameter(1001001, IQueryBuilder::PARAM_INT),
+ 'path' => $query->createNamedParameter('file1'),
+ 'path_hash' => $query->createNamedParameter(md5('file1')),
+ ]);
+ $query->executeStatement();
+ $fileId = $query->getLastInsertId();
+
+ $query = $this->getQueryBuilder();
+ $query->insert('filecache_extended')
+ ->hintShardKey('storage', 1001001)
+ ->values([
+ 'fileid' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT),
+ 'upload_time' => $query->createNamedParameter(1234, IQueryBuilder::PARAM_INT),
+ ]);
+ $query->executeStatement();
+
+ $query = $this->getQueryBuilder();
+ $query->insert('mounts')
+ ->values([
+ 'storage_id' => $query->createNamedParameter(1001001, IQueryBuilder::PARAM_INT),
+ 'user_id' => $query->createNamedParameter('partitioned_test'),
+ 'mount_point' => $query->createNamedParameter('/mount/point'),
+ 'mount_provider_class' => $query->createNamedParameter('test'),
+ 'root_id' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT),
+ ]);
+ $query->executeStatement();
+ }
+
+ private function cleanupDb(): void {
+ $query = $this->getQueryBuilder();
+ $query->delete('storages')
+ ->where($query->expr()->gt('numeric_id', $query->createNamedParameter(1000000, IQueryBuilder::PARAM_INT)));
+ $query->executeStatement();
+
+ $query = $this->getQueryBuilder();
+ $query->delete('filecache')
+ ->where($query->expr()->gt('storage', $query->createNamedParameter(1000000, IQueryBuilder::PARAM_INT)))
+ ->runAcrossAllShards();
+ $query->executeStatement();
+
+ $query = $this->getQueryBuilder();
+ $query->delete('filecache_extended')
+ ->runAcrossAllShards();
+ $query->executeStatement();
+
+ $query = $this->getQueryBuilder();
+ $query->delete('mounts')
+ ->where($query->expr()->like('user_id', $query->createNamedParameter('partitioned_%')));
+ $query->executeStatement();
+ }
+
+ public function testSimpleOnlyPartitionQuery(): void {
+ $builder = $this->getQueryBuilder();
+ $builder->addPartition(new PartitionSplit('filecache', ['filecache']));
+
+ // query borrowed from UserMountCache
+ $query = $builder->select('path')
+ ->from('filecache')
+ ->where($builder->expr()->eq('storage', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT)));
+
+ $results = $query->executeQuery()->fetchAll();
+ $this->assertCount(1, $results);
+ $this->assertEquals($results[0]['path'], 'file1');
+ }
+
+ public function testSimplePartitionedQuery(): void {
+ $builder = $this->getQueryBuilder();
+ $builder->addPartition(new PartitionSplit('filecache', ['filecache']));
+
+ // query borrowed from UserMountCache
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
+ ->from('mounts', 'm')
+ ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
+ ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT)));
+
+ $query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter('partitioned_test')));
+
+ $this->assertEquals(2, $query->getPartitionCount());
+
+ $results = $query->executeQuery()->fetchAll();
+ $this->assertCount(1, $results);
+ $this->assertEquals($results[0]['user_id'], 'partitioned_test');
+ $this->assertEquals($results[0]['mount_point'], '/mount/point');
+ $this->assertEquals($results[0]['mount_provider_class'], 'test');
+ $this->assertEquals($results[0]['path'], 'file1');
+ }
+
+ public function testMultiTablePartitionedQuery(): void {
+ $builder = $this->getQueryBuilder();
+ $builder->addPartition(new PartitionSplit('filecache', ['filecache', 'filecache_extended']));
+
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class', 'fe.upload_time')
+ ->from('mounts', 'm')
+ ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
+ ->innerJoin('f', 'filecache_extended', 'fe', $builder->expr()->eq('f.fileid', 'fe.fileid'))
+ ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT)));
+
+ $query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter('partitioned_test')));
+
+ $this->assertEquals(2, $query->getPartitionCount());
+
+ $results = $query->executeQuery()->fetchAll();
+ $this->assertCount(1, $results);
+ $this->assertEquals($results[0]['user_id'], 'partitioned_test');
+ $this->assertEquals($results[0]['mount_point'], '/mount/point');
+ $this->assertEquals($results[0]['mount_provider_class'], 'test');
+ $this->assertEquals($results[0]['path'], 'file1');
+ $this->assertEquals($results[0]['upload_time'], 1234);
+ }
+
+ public function testPartitionedQueryFromSplit(): void {
+ $builder = $this->getQueryBuilder();
+ $builder->addPartition(new PartitionSplit('filecache', ['filecache']));
+
+ $query = $builder->select('storage', 'm.root_id', 'm.user_id', 'm.mount_point', 'm.mount_id', 'path', 'm.mount_provider_class')
+ ->from('filecache', 'f')
+ ->innerJoin('f', 'mounts', 'm', $builder->expr()->eq('m.root_id', 'f.fileid'));
+ $query->where($builder->expr()->eq('storage', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT)));
+
+ $query->andWhere($builder->expr()->eq('m.user_id', $builder->createNamedParameter('partitioned_test')));
+
+ $this->assertEquals(2, $query->getPartitionCount());
+
+ $results = $query->executeQuery()->fetchAll();
+ $this->assertCount(1, $results);
+ $this->assertEquals($results[0]['user_id'], 'partitioned_test');
+ $this->assertEquals($results[0]['mount_point'], '/mount/point');
+ $this->assertEquals($results[0]['mount_provider_class'], 'test');
+ $this->assertEquals($results[0]['path'], 'file1');
+ }
+
+ public function testMultiJoinPartitionedQuery(): void {
+ $builder = $this->getQueryBuilder();
+ $builder->addPartition(new PartitionSplit('filecache', ['filecache']));
+
+ // query borrowed from UserMountCache
+ $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
+ ->selectAlias('s.id', 'storage_string_id')
+ ->from('mounts', 'm')
+ ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
+ ->innerJoin('f', 'storages', 's', $builder->expr()->eq('f.storage', 's.numeric_id'))
+ ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT)));
+
+ $query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter('partitioned_test')));
+
+ $this->assertEquals(3, $query->getPartitionCount());
+
+ $results = $query->executeQuery()->fetchAll();
+ $this->assertCount(1, $results);
+ $this->assertEquals($results[0]['user_id'], 'partitioned_test');
+ $this->assertEquals($results[0]['mount_point'], '/mount/point');
+ $this->assertEquals($results[0]['mount_provider_class'], 'test');
+ $this->assertEquals($results[0]['path'], 'file1');
+ $this->assertEquals($results[0]['storage_string_id'], 'test1');
+ }
+}
diff --git a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php
index 96cde8ba1f9..990191a9ff5 100644
--- a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php
+++ b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -9,13 +10,15 @@ namespace Test\DB\QueryBuilder;
use Doctrine\DBAL\Query\Expression\CompositeExpression;
use Doctrine\DBAL\Query\QueryException;
-use Doctrine\DBAL\Result;
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\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
use OCP\IDBConnection;
+use OCP\Server;
use Psr\Log\LoggerInterface;
/**
@@ -41,7 +44,7 @@ class QueryBuilderTest extends \Test\TestCase {
protected function setUp(): void {
parent::setUp();
- $this->connection = \OC::$server->getDatabaseConnection();
+ $this->connection = Server::get(IDBConnection::class);
$this->config = $this->createMock(SystemConfig::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->queryBuilder = new QueryBuilder($this->connection, $this->config, $this->logger);
@@ -87,7 +90,7 @@ class QueryBuilderTest extends \Test\TestCase {
->execute();
}
- public function dataFirstResult() {
+ public static function dataFirstResult(): array {
return [
[0, [99, 98, 97, 96, 95, 94, 93, 92, 91]],
[0, [99, 98, 97, 96, 95, 94, 93, 92, 91]],
@@ -97,12 +100,12 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataFirstResult
*
* @param int|null $firstResult
* @param array $expectedSet
*/
- public function testFirstResult($firstResult, $expectedSet) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataFirstResult')]
+ public function testFirstResult($firstResult, $expectedSet): void {
$this->deleteTestingRows();
$this->createTestingRows();
@@ -123,7 +126,7 @@ class QueryBuilderTest extends \Test\TestCase {
$this->deleteTestingRows();
}
- public function dataMaxResults() {
+ public static function dataMaxResults(): array {
return [
[null, [99, 98, 97, 96, 95, 94, 93, 92, 91]],
// Limit 0 gives mixed results: either all entries or none is returned
@@ -134,12 +137,12 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataMaxResults
*
* @param int $maxResult
* @param array $expectedSet
*/
- public function testMaxResults($maxResult, $expectedSet) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataMaxResults')]
+ public function testMaxResults($maxResult, $expectedSet): void {
$this->deleteTestingRows();
$this->createTestingRows();
@@ -160,10 +163,10 @@ class QueryBuilderTest extends \Test\TestCase {
$this->deleteTestingRows();
}
- public function dataSelect() {
+ public function dataSelect(): array {
$config = $this->createMock(SystemConfig::class);
$logger = $this->createMock(LoggerInterface::class);
- $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
+ $queryBuilder = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger);
return [
// select('column1')
[['configvalue'], ['configvalue' => '99']],
@@ -186,13 +189,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataSelect
*
* @param array $selectArguments
* @param array $expected
* @param string $expectedLiteral
*/
- public function testSelect($selectArguments, $expected, $expectedLiteral = '') {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSelect')]
+ public function testSelect($selectArguments, $expected, $expectedLiteral = ''): void {
$this->deleteTestingRows();
$this->createTestingRows();
@@ -228,10 +231,10 @@ class QueryBuilderTest extends \Test\TestCase {
$this->deleteTestingRows();
}
- public function dataSelectAlias() {
+ public function dataSelectAlias(): array {
$config = $this->createMock(SystemConfig::class);
$logger = $this->createMock(LoggerInterface::class);
- $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
+ $queryBuilder = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger);
return [
['configvalue', 'cv', ['cv' => '99']],
[$queryBuilder->expr()->literal('column1'), 'thing', ['thing' => 'column1']],
@@ -239,13 +242,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataSelectAlias
*
* @param mixed $select
* @param array $alias
* @param array $expected
*/
- public function testSelectAlias($select, $alias, $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSelectAlias')]
+ public function testSelectAlias($select, $alias, $expected): void {
$this->deleteTestingRows();
$this->createTestingRows();
@@ -271,7 +274,7 @@ class QueryBuilderTest extends \Test\TestCase {
$this->deleteTestingRows();
}
- public function testSelectDistinct() {
+ public function testSelectDistinct(): void {
$this->deleteTestingRows('testFirstResult1');
$this->deleteTestingRows('testFirstResult2');
$this->createTestingRows('testFirstResult1');
@@ -299,7 +302,7 @@ class QueryBuilderTest extends \Test\TestCase {
$this->deleteTestingRows('testFirstResult2');
}
- public function testSelectDistinctMultiple() {
+ public function testSelectDistinctMultiple(): void {
$this->deleteTestingRows('testFirstResult1');
$this->deleteTestingRows('testFirstResult2');
$this->createTestingRows('testFirstResult1');
@@ -337,10 +340,10 @@ class QueryBuilderTest extends \Test\TestCase {
$this->deleteTestingRows('testFirstResult2');
}
- public function dataAddSelect() {
+ public function dataAddSelect(): array {
$config = $this->createMock(SystemConfig::class);
$logger = $this->createMock(LoggerInterface::class);
- $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
+ $queryBuilder = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger);
return [
// addSelect('column1')
[['configvalue'], ['appid' => 'testFirstResult', 'configvalue' => '99']],
@@ -363,13 +366,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataAddSelect
*
* @param array $selectArguments
* @param array $expected
* @param string $expectedLiteral
*/
- public function testAddSelect($selectArguments, $expected, $expectedLiteral = '') {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAddSelect')]
+ public function testAddSelect($selectArguments, $expected, $expectedLiteral = ''): void {
$this->deleteTestingRows();
$this->createTestingRows();
@@ -407,7 +410,7 @@ class QueryBuilderTest extends \Test\TestCase {
$this->deleteTestingRows();
}
- public function dataDelete() {
+ public static function dataDelete(): array {
return [
['data', null, ['table' => '`*PREFIX*data`', 'alias' => null], '`*PREFIX*data`'],
['data', 't', ['table' => '`*PREFIX*data`', 'alias' => 't'], '`*PREFIX*data` t'],
@@ -415,14 +418,14 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataDelete
*
* @param string $tableName
* @param string $tableAlias
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testDelete($tableName, $tableAlias, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataDelete')]
+ public function testDelete($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->delete($tableName, $tableAlias);
$this->assertSame(
@@ -436,7 +439,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataUpdate() {
+ public static function dataUpdate(): array {
return [
['data', null, ['table' => '`*PREFIX*data`', 'alias' => null], '`*PREFIX*data`'],
['data', 't', ['table' => '`*PREFIX*data`', 'alias' => 't'], '`*PREFIX*data` t'],
@@ -444,14 +447,14 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataUpdate
*
* @param string $tableName
* @param string $tableAlias
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testUpdate($tableName, $tableAlias, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdate')]
+ public function testUpdate($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->update($tableName, $tableAlias);
$this->assertSame(
@@ -465,20 +468,20 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataInsert() {
+ public static function dataInsert(): array {
return [
['data', ['table' => '`*PREFIX*data`'], '`*PREFIX*data`'],
];
}
/**
- * @dataProvider dataInsert
*
* @param string $tableName
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testInsert($tableName, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataInsert')]
+ public function testInsert($tableName, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->insert($tableName);
$this->assertSame(
@@ -492,10 +495,10 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataFrom() {
+ public function dataFrom(): array {
$config = $this->createMock(SystemConfig::class);
$logger = $this->createMock(LoggerInterface::class);
- $qb = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
+ $qb = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger);
return [
[$qb->createFunction('(' . $qb->select('*')->from('test')->getSQL() . ')'), 'q', null, null, [
['table' => '(SELECT * FROM `*PREFIX*test`)', 'alias' => '`q`']
@@ -514,7 +517,6 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataFrom
*
* @param string|IQueryFunction $table1Name
* @param string $table1Alias
@@ -523,7 +525,8 @@ class QueryBuilderTest extends \Test\TestCase {
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testFrom($table1Name, $table1Alias, $table2Name, $table2Alias, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataFrom')]
+ public function testFrom($table1Name, $table1Alias, $table2Name, $table2Alias, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->from($table1Name, $table1Alias);
if ($table2Name !== null) {
$this->queryBuilder->from($table2Name, $table2Alias);
@@ -540,7 +543,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataJoin() {
+ public static function dataJoin(): array {
return [
[
'd1', 'data2', null, null,
@@ -562,7 +565,6 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataJoin
*
* @param string $fromAlias
* @param string $tableName
@@ -571,7 +573,8 @@ class QueryBuilderTest extends \Test\TestCase {
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataJoin')]
+ public function testJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->from('data1', 'd1');
$this->queryBuilder->join(
$fromAlias,
@@ -592,7 +595,6 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataJoin
*
* @param string $fromAlias
* @param string $tableName
@@ -601,7 +603,8 @@ class QueryBuilderTest extends \Test\TestCase {
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testInnerJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataJoin')]
+ public function testInnerJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->from('data1', 'd1');
$this->queryBuilder->innerJoin(
$fromAlias,
@@ -621,7 +624,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataLeftJoin() {
+ public static function dataLeftJoin(): array {
return [
[
'd1', 'data2', null, null,
@@ -642,7 +645,6 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataLeftJoin
*
* @param string $fromAlias
* @param string $tableName
@@ -651,7 +653,8 @@ class QueryBuilderTest extends \Test\TestCase {
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testLeftJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataLeftJoin')]
+ public function testLeftJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->from('data1', 'd1');
$this->queryBuilder->leftJoin(
$fromAlias,
@@ -671,7 +674,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataRightJoin() {
+ public static function dataRightJoin(): array {
return [
[
'd1', 'data2', null, null,
@@ -692,7 +695,6 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataRightJoin
*
* @param string $fromAlias
* @param string $tableName
@@ -701,7 +703,8 @@ class QueryBuilderTest extends \Test\TestCase {
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testRightJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataRightJoin')]
+ public function testRightJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->from('data1', 'd1');
$this->queryBuilder->rightJoin(
$fromAlias,
@@ -721,7 +724,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataSet() {
+ public static function dataSet(): array {
return [
['column1', new Literal('value'), null, null, ['`column1` = value'], '`column1` = value'],
['column1', new Parameter(':param'), null, null, ['`column1` = :param'], '`column1` = :param'],
@@ -731,7 +734,6 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataSet
*
* @param string $partOne1
* @param string $partOne2
@@ -740,7 +742,8 @@ class QueryBuilderTest extends \Test\TestCase {
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testSet($partOne1, $partOne2, $partTwo1, $partTwo2, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSet')]
+ public function testSet($partOne1, $partOne2, $partTwo1, $partTwo2, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->update('data');
$this->queryBuilder->set($partOne1, $partOne2);
if ($partTwo1 !== null) {
@@ -758,7 +761,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataWhere() {
+ public static function dataWhere(): array {
return [
[['where1'], new CompositeExpression('AND', ['where1']), 'where1'],
[['where1', 'where2'], new CompositeExpression('AND', ['where1', 'where2']), '(where1) AND (where2)'],
@@ -766,13 +769,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataWhere
*
* @param array $whereArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testWhere($whereArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataWhere')]
+ public function testWhere($whereArguments, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->select('column');
call_user_func_array(
[$this->queryBuilder, 'where'],
@@ -791,13 +794,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataWhere
*
* @param array $whereArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testAndWhere($whereArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataWhere')]
+ public function testAndWhere($whereArguments, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->select('column');
call_user_func_array(
[$this->queryBuilder, 'andWhere'],
@@ -815,7 +818,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataOrWhere() {
+ public static function dataOrWhere(): array {
return [
[['where1'], new CompositeExpression('OR', ['where1']), 'where1'],
[['where1', 'where2'], new CompositeExpression('OR', ['where1', 'where2']), '(where1) OR (where2)'],
@@ -823,13 +826,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataOrWhere
*
* @param array $whereArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testOrWhere($whereArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataOrWhere')]
+ public function testOrWhere($whereArguments, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->select('column');
call_user_func_array(
[$this->queryBuilder, 'orWhere'],
@@ -847,7 +850,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataGroupBy() {
+ public static function dataGroupBy(): array {
return [
[['column1'], ['`column1`'], '`column1`'],
[['column1', 'column2'], ['`column1`', '`column2`'], '`column1`, `column2`'],
@@ -855,13 +858,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataGroupBy
*
* @param array $groupByArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGroupBy')]
+ public function testGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->select('column');
call_user_func_array(
[$this->queryBuilder, 'groupBy'],
@@ -879,7 +882,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataAddGroupBy() {
+ public static function dataAddGroupBy(): array {
return [
[['column2'], ['`column1`', '`column2`'], '`column1`, `column2`'],
[['column2', 'column3'], ['`column1`', '`column2`', '`column3`'], '`column1`, `column2`, `column3`'],
@@ -887,13 +890,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataAddGroupBy
*
* @param array $groupByArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testAddGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAddGroupBy')]
+ public function testAddGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->select('column');
$this->queryBuilder->groupBy('column1');
call_user_func_array(
@@ -912,21 +915,21 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataSetValue() {
+ public static function dataSetValue(): array {
return [
['column', 'value', ['`column`' => 'value'], '(`column`) VALUES(value)'],
];
}
/**
- * @dataProvider dataSetValue
*
* @param string $column
* @param string $value
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testSetValue($column, $value, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSetValue')]
+ public function testSetValue($column, $value, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->insert('data');
$this->queryBuilder->setValue($column, $value);
@@ -942,14 +945,14 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataSetValue
*
* @param string $column
* @param string $value
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testValues($column, $value, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataSetValue')]
+ public function testValues($column, $value, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->insert('data');
$this->queryBuilder->values([
$column => $value,
@@ -966,7 +969,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataHaving() {
+ public static function dataHaving(): array {
return [
[['condition1'], new CompositeExpression('AND', ['condition1']), 'HAVING condition1'],
[['condition1', 'condition2'], new CompositeExpression('AND', ['condition1', 'condition2']), 'HAVING (condition1) AND (condition2)'],
@@ -984,13 +987,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataHaving
*
* @param array $havingArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testHaving($havingArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataHaving')]
+ public function testHaving($havingArguments, $expectedQueryPart, $expectedQuery): void {
call_user_func_array(
[$this->queryBuilder, 'having'],
$havingArguments
@@ -1007,7 +1010,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataAndHaving() {
+ public static function dataAndHaving(): array {
return [
[['condition2'], new CompositeExpression('AND', ['condition1', 'condition2']), 'HAVING (condition1) AND (condition2)'],
[['condition2', 'condition3'], new CompositeExpression('AND', ['condition1', 'condition2', 'condition3']), 'HAVING (condition1) AND (condition2) AND (condition3)'],
@@ -1025,13 +1028,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataAndHaving
*
* @param array $havingArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testAndHaving($havingArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAndHaving')]
+ public function testAndHaving($havingArguments, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->having('condition1');
call_user_func_array(
[$this->queryBuilder, 'andHaving'],
@@ -1049,7 +1052,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataOrHaving() {
+ public static function dataOrHaving(): array {
return [
[['condition2'], new CompositeExpression('OR', ['condition1', 'condition2']), 'HAVING (condition1) OR (condition2)'],
[['condition2', 'condition3'], new CompositeExpression('OR', ['condition1', 'condition2', 'condition3']), 'HAVING (condition1) OR (condition2) OR (condition3)'],
@@ -1067,13 +1070,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataOrHaving
*
* @param array $havingArguments
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testOrHaving($havingArguments, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataOrHaving')]
+ public function testOrHaving($havingArguments, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->having('condition1');
call_user_func_array(
[$this->queryBuilder, 'orHaving'],
@@ -1091,7 +1094,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataOrderBy() {
+ public static function dataOrderBy(): array {
return [
['column', null, ['`column` ASC'], 'ORDER BY `column` ASC'],
['column', 'ASC', ['`column` ASC'], 'ORDER BY `column` ASC'],
@@ -1100,14 +1103,14 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataOrderBy
*
* @param string $sort
* @param string $order
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testOrderBy($sort, $order, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataOrderBy')]
+ public function testOrderBy($sort, $order, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->orderBy($sort, $order);
$this->assertEquals(
@@ -1121,7 +1124,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataAddOrderBy() {
+ public static function dataAddOrderBy(): array {
return [
['column2', null, null, ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'],
['column2', null, 'ASC', ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'],
@@ -1136,7 +1139,6 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataAddOrderBy
*
* @param string $sort2
* @param string $order2
@@ -1144,7 +1146,8 @@ class QueryBuilderTest extends \Test\TestCase {
* @param array $expectedQueryPart
* @param string $expectedQuery
*/
- public function testAddOrderBy($sort2, $order2, $order1, $expectedQueryPart, $expectedQuery) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataAddOrderBy')]
+ public function testAddOrderBy($sort2, $order2, $order1, $expectedQueryPart, $expectedQuery): void {
$this->queryBuilder->orderBy('column1', $order1);
$this->queryBuilder->addOrderBy($sort2, $order2);
@@ -1159,7 +1162,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function testGetLastInsertId() {
+ public function testGetLastInsertId(): void {
$qB = $this->connection->getQueryBuilder();
try {
@@ -1196,10 +1199,10 @@ class QueryBuilderTest extends \Test\TestCase {
}
}
- public function dataGetTableName() {
+ public function dataGetTableName(): array {
$config = $this->createMock(SystemConfig::class);
$logger = $this->createMock(LoggerInterface::class);
- $qb = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger);
+ $qb = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger);
return [
['*PREFIX*table', null, '`*PREFIX*table`'],
['*PREFIX*table', true, '`*PREFIX*table`'],
@@ -1216,13 +1219,13 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataGetTableName
*
* @param string|IQueryFunction $tableName
* @param bool $automatic
* @param string $expected
*/
- public function testGetTableName($tableName, $automatic, $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetTableName')]
+ public function testGetTableName($tableName, $automatic, $expected): void {
if ($automatic !== null) {
$this->queryBuilder->automaticTablePrefix($automatic);
}
@@ -1233,7 +1236,7 @@ class QueryBuilderTest extends \Test\TestCase {
);
}
- public function dataGetColumnName() {
+ public static function dataGetColumnName(): array {
return [
['column', '', '`column`'],
['column', 'a', '`a`.`column`'],
@@ -1241,28 +1244,41 @@ class QueryBuilderTest extends \Test\TestCase {
}
/**
- * @dataProvider dataGetColumnName
* @param string $column
* @param string $prefix
* @param string $expected
*/
- public function testGetColumnName($column, $prefix, $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetColumnName')]
+ public function testGetColumnName($column, $prefix, $expected): void {
$this->assertSame(
$expected,
$this->queryBuilder->getColumnName($column, $prefix)
);
}
- public function testExecuteWithoutLogger() {
+ private function getConnection(): IDBConnection {
+ $connection = $this->createMock(IDBConnection::class);
+ $connection->method('executeStatement')
+ ->willReturn(3);
+ $connection->method('executeQuery')
+ ->willReturn($this->createMock(IResult::class));
+ return $connection;
+ }
+
+ public function testExecuteWithoutLogger(): void {
$queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
$queryBuilder
- ->expects($this->once())
- ->method('execute')
- ->willReturn(3);
+ ->method('getSQL')
+ ->willReturn('');
$queryBuilder
- ->expects($this->any())
->method('getParameters')
->willReturn([]);
+ $queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([]);
+ $queryBuilder
+ ->method('getType')
+ ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
$this->logger
->expects($this->never())
->method('debug');
@@ -1273,10 +1289,11 @@ class QueryBuilderTest extends \Test\TestCase {
->willReturn(false);
$this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
+ $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
$this->assertEquals(3, $this->queryBuilder->execute());
}
- public function testExecuteWithLoggerAndNamedArray() {
+ public function testExecuteWithLoggerAndNamedArray(): void {
$queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
$queryBuilder
->expects($this->any())
@@ -1286,20 +1303,25 @@ class QueryBuilderTest extends \Test\TestCase {
'key' => 'value',
]);
$queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([
+ 'foo' => IQueryBuilder::PARAM_STR,
+ 'key' => IQueryBuilder::PARAM_STR,
+ ]);
+ $queryBuilder
+ ->method('getType')
+ ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
+ $queryBuilder
->expects($this->any())
->method('getSQL')
- ->willReturn('SELECT * FROM FOO WHERE BAR = ?');
- $queryBuilder
- ->expects($this->once())
- ->method('execute')
- ->willReturn(3);
+ ->willReturn('UPDATE FOO SET bar = 1 WHERE BAR = ?');
$this->logger
->expects($this->once())
->method('debug')
->with(
'DB QueryBuilder: \'{query}\' with parameters: {params}',
[
- 'query' => 'SELECT * FROM FOO WHERE BAR = ?',
+ 'query' => 'UPDATE FOO SET bar = 1 WHERE BAR = ?',
'params' => 'foo => \'bar\', key => \'value\'',
'app' => 'core',
]
@@ -1311,30 +1333,33 @@ class QueryBuilderTest extends \Test\TestCase {
->willReturn(true);
$this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
+ $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
$this->assertEquals(3, $this->queryBuilder->execute());
}
- public function testExecuteWithLoggerAndUnnamedArray() {
+ public function testExecuteWithLoggerAndUnnamedArray(): void {
$queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
$queryBuilder
->expects($this->any())
->method('getParameters')
->willReturn(['Bar']);
$queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([IQueryBuilder::PARAM_STR]);
+ $queryBuilder
+ ->method('getType')
+ ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
+ $queryBuilder
->expects($this->any())
->method('getSQL')
- ->willReturn('SELECT * FROM FOO WHERE BAR = ?');
- $queryBuilder
- ->expects($this->once())
- ->method('execute')
- ->willReturn(3);
+ ->willReturn('UPDATE FOO SET bar = false WHERE BAR = ?');
$this->logger
->expects($this->once())
->method('debug')
->with(
'DB QueryBuilder: \'{query}\' with parameters: {params}',
[
- 'query' => 'SELECT * FROM FOO WHERE BAR = ?',
+ 'query' => 'UPDATE FOO SET bar = false WHERE BAR = ?',
'params' => '0 => \'Bar\'',
'app' => 'core',
]
@@ -1346,30 +1371,33 @@ class QueryBuilderTest extends \Test\TestCase {
->willReturn(true);
$this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
+ $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
$this->assertEquals(3, $this->queryBuilder->execute());
}
- public function testExecuteWithLoggerAndNoParams() {
+ public function testExecuteWithLoggerAndNoParams(): void {
$queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
$queryBuilder
->expects($this->any())
->method('getParameters')
->willReturn([]);
$queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([]);
+ $queryBuilder
+ ->method('getType')
+ ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE);
+ $queryBuilder
->expects($this->any())
->method('getSQL')
- ->willReturn('SELECT * FROM FOO WHERE BAR = ?');
- $queryBuilder
- ->expects($this->once())
- ->method('execute')
- ->willReturn(3);
+ ->willReturn('UPDATE FOO SET bar = false WHERE BAR = ?');
$this->logger
->expects($this->once())
->method('debug')
->with(
'DB QueryBuilder: \'{query}\'',
[
- 'query' => 'SELECT * FROM FOO WHERE BAR = ?',
+ 'query' => 'UPDATE FOO SET bar = false WHERE BAR = ?',
'app' => 'core',
]
);
@@ -1380,10 +1408,11 @@ class QueryBuilderTest extends \Test\TestCase {
->willReturn(true);
$this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
+ $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
$this->assertEquals(3, $this->queryBuilder->execute());
}
- public function testExecuteWithParameterTooLarge() {
+ public function testExecuteWithParameterTooLarge(): void {
$queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
$p = array_fill(0, 1001, 'foo');
$queryBuilder
@@ -1391,17 +1420,16 @@ class QueryBuilderTest extends \Test\TestCase {
->method('getParameters')
->willReturn([$p]);
$queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([IQueryBuilder::PARAM_STR_ARRAY]);
+ $queryBuilder
->expects($this->any())
->method('getSQL')
->willReturn('SELECT * FROM FOO WHERE BAR IN (?)');
- $queryBuilder
- ->expects($this->once())
- ->method('execute')
- ->willReturn($this->createMock(Result::class));
$this->logger
->expects($this->once())
->method('error')
- ->willReturnCallback(function ($message, $parameters) {
+ ->willReturnCallback(function ($message, $parameters): void {
$this->assertInstanceOf(QueryException::class, $parameters['exception']);
$this->assertSame(
'More than 1000 expressions in a list are not allowed on Oracle.',
@@ -1415,10 +1443,11 @@ class QueryBuilderTest extends \Test\TestCase {
->willReturn(false);
$this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
+ $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
$this->queryBuilder->execute();
}
- public function testExecuteWithParametersTooMany() {
+ public function testExecuteWithParametersTooMany(): void {
$queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class);
$p = array_fill(0, 999, 'foo');
$queryBuilder
@@ -1426,17 +1455,16 @@ class QueryBuilderTest extends \Test\TestCase {
->method('getParameters')
->willReturn(array_fill(0, 66, $p));
$queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([IQueryBuilder::PARAM_STR_ARRAY]);
+ $queryBuilder
->expects($this->any())
->method('getSQL')
->willReturn('SELECT * FROM FOO WHERE BAR IN (?) OR BAR IN (?)');
- $queryBuilder
- ->expects($this->once())
- ->method('execute')
- ->willReturn($this->createMock(Result::class));
$this->logger
->expects($this->once())
->method('error')
- ->willReturnCallback(function ($message, $parameters) {
+ ->willReturnCallback(function ($message, $parameters): void {
$this->assertInstanceOf(QueryException::class, $parameters['exception']);
$this->assertSame(
'The number of parameters must not exceed 65535. Restriction by PostgreSQL.',
@@ -1450,6 +1478,7 @@ class QueryBuilderTest extends \Test\TestCase {
->willReturn(false);
$this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]);
+ $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]);
$this->queryBuilder->execute();
}
}
diff --git a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php
index 12984bac3e0..6efb55708a1 100644
--- a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php
+++ b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php
@@ -1,4 +1,5 @@
<?php
+
/**
* SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -23,7 +24,7 @@ class QuoteHelperTest extends \Test\TestCase {
$this->helper = new QuoteHelper();
}
- public function dataQuoteColumnName() {
+ public static function dataQuoteColumnName(): array {
return [
['column', '`column`'],
[new Literal('literal'), 'literal'],
@@ -37,18 +38,18 @@ class QuoteHelperTest extends \Test\TestCase {
}
/**
- * @dataProvider dataQuoteColumnName
* @param mixed $input
* @param string $expected
*/
- public function testQuoteColumnName($input, $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataQuoteColumnName')]
+ public function testQuoteColumnName($input, $expected): void {
$this->assertSame(
$expected,
$this->helper->quoteColumnName($input)
);
}
- public function dataQuoteColumnNames() {
+ public static function dataQuoteColumnNames(): array {
return [
// Single case
['d.column', '`d`.`column`'],
@@ -72,11 +73,11 @@ class QuoteHelperTest extends \Test\TestCase {
}
/**
- * @dataProvider dataQuoteColumnNames
* @param mixed $input
* @param string $expected
*/
- public function testQuoteColumnNames($input, $expected) {
+ #[\PHPUnit\Framework\Attributes\DataProvider('dataQuoteColumnNames')]
+ public function testQuoteColumnNames($input, $expected): void {
$this->assertSame(
$expected,
$this->helper->quoteColumnNames($input)
diff --git a/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php b/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php
new file mode 100644
index 00000000000..d0f232cb03f
--- /dev/null
+++ b/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php
@@ -0,0 +1,128 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Robin Appelman <robin@icewind.nl>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\DB\QueryBuilder\Sharded;
+
+use OC\DB\QueryBuilder\Sharded\AutoIncrementHandler;
+use OC\DB\QueryBuilder\Sharded\InvalidShardedQueryException;
+use OC\DB\QueryBuilder\Sharded\RoundRobinShardMapper;
+use OC\DB\QueryBuilder\Sharded\ShardConnectionManager;
+use OC\DB\QueryBuilder\Sharded\ShardDefinition;
+use OC\DB\QueryBuilder\Sharded\ShardedQueryBuilder;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+use OCP\Server;
+use Test\TestCase;
+
+/**
+ * @group DB
+ */
+class SharedQueryBuilderTest extends TestCase {
+ private IDBConnection $connection;
+ private AutoIncrementHandler $autoIncrementHandler;
+
+ protected function setUp(): void {
+ if (PHP_INT_SIZE < 8) {
+ $this->markTestSkipped('Test requires 64bit');
+ }
+ $this->connection = Server::get(IDBConnection::class);
+ $this->autoIncrementHandler = Server::get(AutoIncrementHandler::class);
+ }
+
+
+ private function getQueryBuilder(string $table, string $shardColumn, string $primaryColumn, array $companionTables = []): ShardedQueryBuilder {
+ return new ShardedQueryBuilder(
+ $this->connection->getQueryBuilder(),
+ [
+ new ShardDefinition($table, $primaryColumn, [], $shardColumn, new RoundRobinShardMapper(), $companionTables, [], 0, 0),
+ ],
+ $this->createMock(ShardConnectionManager::class),
+ $this->autoIncrementHandler,
+ );
+ }
+
+ public function testGetShardKeySingleParam(): void {
+ $query = $this->getQueryBuilder('filecache', 'storage', 'fileid');
+ $query->select('fileid', 'path')
+ ->from('filecache')
+ ->where($query->expr()->eq('storage', $query->createNamedParameter(10, IQueryBuilder::PARAM_INT)));
+
+ $this->assertEquals([], $query->getPrimaryKeys());
+ $this->assertEquals([10], $query->getShardKeys());
+ }
+
+ public function testGetPrimaryKeyParam(): void {
+ $query = $this->getQueryBuilder('filecache', 'storage', 'fileid');
+ $query->select('fileid', 'path')
+ ->from('filecache')
+ ->where($query->expr()->in('fileid', $query->createNamedParameter([10, 11], IQueryBuilder::PARAM_INT)));
+
+ $this->assertEquals([10, 11], $query->getPrimaryKeys());
+ $this->assertEquals([], $query->getShardKeys());
+ }
+
+ public function testValidateWithShardKey(): void {
+ $query = $this->getQueryBuilder('filecache', 'storage', 'fileid');
+ $query->select('fileid', 'path')
+ ->from('filecache')
+ ->where($query->expr()->eq('storage', $query->createNamedParameter(10)));
+
+ $query->validate();
+ $this->assertTrue(true);
+ }
+
+ public function testValidateWithPrimaryKey(): void {
+ $query = $this->getQueryBuilder('filecache', 'storage', 'fileid');
+ $query->select('fileid', 'path')
+ ->from('filecache')
+ ->where($query->expr()->in('fileid', $query->createNamedParameter([10, 11], IQueryBuilder::PARAM_INT)));
+
+ $query->validate();
+ $this->assertTrue(true);
+ }
+
+ public function testValidateWithNoKey(): void {
+ $query = $this->getQueryBuilder('filecache', 'storage', 'fileid');
+ $query->select('fileid', 'path')
+ ->from('filecache')
+ ->where($query->expr()->lt('size', $query->createNamedParameter(0)));
+
+ $this->expectException(InvalidShardedQueryException::class);
+ $query->validate();
+ $this->fail('exception expected');
+ }
+
+ public function testValidateNonSharedTable(): void {
+ $query = $this->getQueryBuilder('filecache', 'storage', 'fileid');
+ $query->select('configvalue')
+ ->from('appconfig')
+ ->where($query->expr()->eq('configkey', $query->createNamedParameter('test')));
+
+ $query->validate();
+ $this->assertTrue(true);
+ }
+
+ public function testGetShardKeyMultipleSingleParam(): void {
+ $query = $this->getQueryBuilder('filecache', 'storage', 'fileid');
+ $query->select('fileid', 'path')
+ ->from('filecache')
+ ->where($query->expr()->andX(
+ $query->expr()->gt('mtime', $query->createNamedParameter(0), IQueryBuilder::PARAM_INT),
+ $query->expr()->orX(
+ $query->expr()->eq('storage', $query->createNamedParameter(10, IQueryBuilder::PARAM_INT)),
+ $query->expr()->andX(
+ $query->expr()->eq('storage', $query->createNamedParameter(11, IQueryBuilder::PARAM_INT)),
+ $query->expr()->like('path', $query->createNamedParameter('foo/%'))
+ )
+ )
+ ));
+
+ $this->assertEquals([], $query->getPrimaryKeys());
+ $this->assertEquals([10, 11], $query->getShardKeys());
+ }
+}