Repository navigation
perf(rows): index cell values by column for number, selection, datetime and usergroup #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
rjzondervan
wants to merge
5
commits into
review-base/main
Choose a base branch
from
feat/3092/cell-value-indices
base: review-base/main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
fd4dca6
perf(rows): index cell values by column for number, selection, dateti…
rjzondervan 7844e24
Merge remote-tracking branch 'origin/main' into feat/3092/cell-value-…
rjzondervan cc87ff5
Merge remote-tracking branch 'origin/main' into feat/3092/cell-value-…
rjzondervan 9fe3687
fix(rows): leave the selection value index out on PostgreSQL
rjzondervan 73014e0
test(rows): check the migrations create the value indices the listene…
rjzondervan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| /** | ||
| * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors | ||
| * SPDX-License-Identifier: AGPL-3.0-or-later | ||
| */ | ||
|
|
||
| namespace OCA\Tables\Tests\Unit\Listener; | ||
|
|
||
| use OCA\Tables\Listener\AddMissingIndicesListener; | ||
| use OCP\DB\Events\AddMissingIndicesEvent; | ||
| use OCP\IDBConnection; | ||
| use PHPUnit\Framework\TestCase; | ||
|
|
||
| class AddMissingIndicesListenerTest extends TestCase { | ||
| /** | ||
| * @return array<string, array{string}> | ||
| */ | ||
| public static function platformsWithTextIndicesProvider(): array { | ||
| return [ | ||
| 'MySQL' => [IDBConnection::PLATFORM_MYSQL], | ||
| 'PostgreSQL' => [IDBConnection::PLATFORM_POSTGRES], | ||
| 'SQLite' => [IDBConnection::PLATFORM_SQLITE], | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * @dataProvider platformsWithTextIndicesProvider | ||
| */ | ||
| public function testIndexesTheValuesOfEveryCellTableButText(string $platform): void { | ||
| $indices = $this->missingIndicesOn($platform); | ||
|
|
||
| $this->assertSame('tables_row_cells_number', $indices['tables_row_cells_number_cv']['tableName']); | ||
| $this->assertSame(['column_id', 'value'], $indices['tables_row_cells_number_cv']['columns']); | ||
|
rjzondervan marked this conversation as resolved.
Resolved
|
||
| $this->assertSame([], $indices['tables_row_cells_number_cv']['options']); | ||
| foreach (AddMissingIndicesListener::TEXT_VALUE_INDICES as $tableName => $indexName) { | ||
| if ($platform === IDBConnection::PLATFORM_POSTGRES && in_array($tableName, AddMissingIndicesListener::UNBOUNDED_TEXT_VALUE_TABLES, true)) { | ||
| continue; | ||
| } | ||
| $this->assertSame($tableName, $indices[$indexName]['tableName']); | ||
| $this->assertSame(['column_id', 'value'], $indices[$indexName]['columns']); | ||
| $this->assertSame(['lengths' => [null, AddMissingIndicesListener::TEXT_VALUE_PREFIX_LENGTH]], $indices[$indexName]['options']); | ||
| } | ||
| $this->assertNotContains('tables_row_cells_text', array_column($indices, 'tableName')); | ||
| } | ||
|
|
||
| public function testLeavesOutTheSelectionValueIndexOnPostgreSql(): void { | ||
| $indices = $this->missingIndicesOn(IDBConnection::PLATFORM_POSTGRES); | ||
|
|
||
| $this->assertArrayNotHasKey('tables_row_cells_selection_cv', $indices); | ||
| $this->assertArrayHasKey('tables_row_cells_datetime_cv', $indices); | ||
| $this->assertArrayHasKey('tables_row_cells_usergroup_cv', $indices); | ||
| } | ||
|
|
||
| public function testLeavesOutTheTextValueIndicesOnOracle(): void { | ||
| $indices = $this->missingIndicesOn(IDBConnection::PLATFORM_ORACLE); | ||
|
|
||
| $this->assertArrayHasKey('tables_row_cells_number_cv', $indices); | ||
| foreach (AddMissingIndicesListener::TEXT_VALUE_INDICES as $indexName) { | ||
| $this->assertArrayNotHasKey($indexName, $indices); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @return array<string, array{tableName: string, columns: string[], options: array}> | ||
| */ | ||
| private function missingIndicesOn(string $platform): array { | ||
| $connection = $this->createMock(IDBConnection::class); | ||
| $connection->method('getDatabaseProvider')->willReturn($platform); | ||
| $event = new AddMissingIndicesEvent(); | ||
|
|
||
| (new AddMissingIndicesListener($connection))->handle($event); | ||
|
|
||
| $indices = []; | ||
| foreach ($event->getMissingIndices() as $index) { | ||
| $indices[$index['indexName']] = ['tableName' => $index['tableName'], 'columns' => $index['columns'], 'options' => $index['options']]; | ||
| } | ||
| return $indices; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| /** | ||
| * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors | ||
| * SPDX-License-Identifier: AGPL-3.0-or-later | ||
| */ | ||
|
|
||
| namespace OCA\Tables\Tests\Unit\Migration; | ||
|
|
||
| use Doctrine\DBAL\Schema\Table; | ||
| use OCA\Tables\Listener\AddMissingIndicesListener; | ||
| use OCA\Tables\Migration\Version000700Date20230916000000; | ||
| use OCA\Tables\Migration\Version000800Date20240712000000; | ||
| use OCP\DB\Events\AddMissingIndicesEvent; | ||
| use OCP\DB\ISchemaWrapper; | ||
| use OCP\DB\Schema\ITable; | ||
| use OCP\IDBConnection; | ||
| use OCP\Migration\IOutput; | ||
| use PHPUnit\Framework\TestCase; | ||
|
|
||
| /** | ||
| * Fresh installations get the cell value indices from the migrations that create the cell tables, | ||
| * existing installations from AddMissingIndicesListener. Both must define the same indices: as | ||
| * occ db:add-missing-indices compares by name, a drifted name gives fresh installations a second | ||
| * index and a drifted definition gives them a different one than upgraded installations. | ||
| */ | ||
| class CellValueIndicesTest extends TestCase { | ||
| /** | ||
| * @return array<string, array{string}> | ||
| */ | ||
| public static function platformsProvider(): array { | ||
| return [ | ||
| 'MySQL' => [IDBConnection::PLATFORM_MYSQL], | ||
| 'PostgreSQL' => [IDBConnection::PLATFORM_POSTGRES], | ||
| 'SQLite' => [IDBConnection::PLATFORM_SQLITE], | ||
| 'Oracle' => [IDBConnection::PLATFORM_ORACLE], | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * @dataProvider platformsProvider | ||
| */ | ||
| public function testMigrationsCreateTheIndicesTheListenerAdds(string $platform): void { | ||
| $connection = $this->createMock(IDBConnection::class); | ||
| $connection->method('getDatabaseProvider')->willReturn($platform); | ||
|
|
||
| $this->assertSame($this->valueIndicesFromListener($connection), $this->valueIndicesFromMigrations($connection)); | ||
| } | ||
|
|
||
| /** | ||
| * @return array<string, array{tableName: string, columns: string[], options: array}> | ||
| */ | ||
| private function valueIndicesFromListener(IDBConnection $connection): array { | ||
| $event = new AddMissingIndicesEvent(); | ||
| (new AddMissingIndicesListener($connection))->handle($event); | ||
|
|
||
| $indices = []; | ||
| foreach ($event->getMissingIndices() as $index) { | ||
| if (str_ends_with($index['indexName'], '_cv')) { | ||
| $indices[$index['indexName']] = ['tableName' => $index['tableName'], 'columns' => $index['columns'], 'options' => $index['options']]; | ||
| } | ||
| } | ||
| ksort($indices); | ||
| return $indices; | ||
| } | ||
|
|
||
| /** | ||
| * @return array<string, array{tableName: string, columns: string[], options: array}> | ||
| */ | ||
| private function valueIndicesFromMigrations(IDBConnection $connection): array { | ||
| $indices = []; | ||
| $schema = $this->createMock(ISchemaWrapper::class); | ||
| $schema->method('hasTable')->willReturn(false); | ||
| $schema->method('createTable')->willReturnCallback(function (string $tableName) use (&$indices) { | ||
| $table = $this->createMock(interface_exists(ITable::class) ? ITable::class : Table::class); | ||
| $table->method('addIndex')->willReturnCallback( | ||
| function (array $columns, ?string $indexName = null, array $flags = [], array $options = []) use (&$indices, $tableName, $table) { | ||
| if ($indexName !== null && str_ends_with($indexName, '_cv')) { | ||
| $indices[$indexName] = ['tableName' => $tableName, 'columns' => $columns, 'options' => $options]; | ||
| } | ||
| return $table; | ||
| } | ||
| ); | ||
| return $table; | ||
| }); | ||
| $output = $this->createMock(IOutput::class); | ||
|
|
||
| (new Version000700Date20230916000000($connection))->changeSchema($output, static fn () => $schema, []); | ||
| (new Version000800Date20240712000000($connection))->changeSchema($output, static fn () => $schema, []); | ||
|
|
||
| ksort($indices); | ||
| return $indices; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.