Skip to content

Commit

Permalink
Base refresh materialized view
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerych1984 committed Jan 22, 2024
1 parent ef81e8b commit d38325b
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/Command/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Closure;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\Expression;
use Yiisoft\Db\Query\Data\DataReaderInterface;
use Yiisoft\Db\Query\QueryInterface;
Expand All @@ -21,6 +22,7 @@
use function is_scalar;
use function is_string;
use function preg_replace_callback;
use function sprintf;
use function str_starts_with;
use function stream_get_contents;

Expand Down Expand Up @@ -526,6 +528,13 @@ public function upsert(
return $this->setSql($sql)->bindValues($params);
}

public function refreshMaterializedView(string $viewName, ?bool $concurrently = null, ?bool $withData = null): bool
{
$sql = $this->getQueryBuilder()->refreshMaterializedView($viewName, $concurrently ?? false, $withData);

throw new NotSupportedException(sprintf('"%s" command not supported', $sql));
}

/**
* @return QueryBuilderInterface The query builder instance.
*/
Expand Down
10 changes: 10 additions & 0 deletions src/Command/CommandInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -833,4 +833,14 @@ public function upsert(
bool|array $updateColumns = true,
array $params = []
): static;

/**
*
* Execute `REFRESH MATERIALIZED VIEW` command
* @param string $viewName
* @param bool|null $concurrently If `null` then auto choice from depends on DBMS
* @param bool|null $withData
* @return bool
*/
public function refreshMaterializedView(string $viewName, ?bool $concurrently = null, ?bool $withData = null): bool;
}
18 changes: 18 additions & 0 deletions src/QueryBuilder/AbstractDDLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Yiisoft\Db\Schema\SchemaInterface;

use function implode;
use function is_bool;
use function is_string;
use function preg_split;

Expand Down Expand Up @@ -302,4 +303,21 @@ public function truncateTable(string $table): string
{
return 'TRUNCATE TABLE ' . $this->quoter->quoteTableName($table);
}

public function refreshMaterializedView(string $viewName, bool $concurrently = false, ?bool $withData = null): string
{
$sql = 'REFRESH MATERIALIZED VIEW ';

if ($concurrently) {
$sql .= 'CONCURRENTLY ';
}

$sql .= $this->quoter->quoteTableName($viewName);

if (is_bool($withData)) {
$sql .= ' WITH ' . ($withData ? 'DATA' : 'NO DATA');
}

return $sql;
}
}
11 changes: 11 additions & 0 deletions src/QueryBuilder/DDLQueryBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -424,4 +424,15 @@ public function renameTable(string $oldName, string $newName): string;
* Note: The method will quote the `table` parameter before using it in the generated SQL.
*/
public function truncateTable(string $table): string;

/**
* Refresh materialized view
*
* @param string $viewName The name of the view to refresh.
* @param bool $concurrently Refresh the materialized view without locking out concurrent selects on the materialized view.
* @param bool|null $withData When `true` then the backing query is executed to provide the new data. Otherwise if `false` then no new data is generated and the materialized view is left in an unscannable state
*
* @return string The `REFRESH MATERIALIZED VIEW` SQL statement
*/
public function refreshMaterializedView(string $viewName, bool $concurrently = false, ?bool $withData = null): string;
}
35 changes: 35 additions & 0 deletions tests/Db/Command/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -727,4 +727,39 @@ public function testProfilerData(string $sql = null): void
);
parent::testProfilerData();
}

public static function refreshMaterializedViewDataProvider(): array
{
return [
[
'default_mt',
null,
null,
],
[
'concurrently_mt',
true,
null,
],
[
'concurrently_with_data_mt',
true,
true,
],
[
'concurrently_without_data_mt',
true,
false,
],
];
}


public function testRefreshMaterializedView(string $viewName, ?bool $concurrently, ?bool $withData): void
{
$db = $this->getConnection();
$this->expectException(NotSupportedException::class);

$db->createCommand()->refreshMaterializedView($viewName, $concurrently, $withData);
}
}
62 changes: 61 additions & 1 deletion tests/Db/QueryBuilder/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public function testGetExpressionBuilderException(): void

$this->expectException(Exception::class);

$expression = new class () implements ExpressionInterface {
$expression = new class() implements ExpressionInterface {
};
$qb = $db->getQueryBuilder();
$qb->getExpressionBuilder($expression);
Expand Down Expand Up @@ -310,4 +310,64 @@ public function testUpsertExecute(
$actualParams = [];
$actualSQL = $db->getQueryBuilder()->upsert($table, $insertColumns, $updateColumns, $actualParams);
}


public static function refreshMaterializedViewDataProvider(): array
{
return [
[
'concurrently_mt',
true,
null,
'REFRESH MATERIALIZED VIEW CONCURRENTLY [[concurrently_mt]]',
],
[
'concurrently_with_data_mt',
true,
true,
'REFRESH MATERIALIZED VIEW CONCURRENTLY [[concurrently_mt]] WITH DATA',
],
[
'concurrently_without_data_mt',
true,
false,
'REFRESH MATERIALIZED VIEW CONCURRENTLY [[concurrently_mt]] WITH NO DATA',
],
[
'not_concurrently_mt',
false,
null,
'REFRESH MATERIALIZED VIEW [[concurrently_mt]]',
],
[
'not_concurrently_with_data_mt',
false,
true,
'REFRESH MATERIALIZED VIEW [[concurrently_mt]] WITH DATA',
],
[
'not_concurrently_without_data_mt',
false,
false,
'REFRESH MATERIALIZED VIEW [[concurrently_mt]] WITH NO DATA',
],
];
}

/**
* @dataProvider refreshMaterializedViewDataProvider
* @param bool $concurrently
* @param bool|null $withData
* @return void
*/
public function testRefreshMaterializedView(string $viewName, bool $concurrently, ?bool $withData, string $expected): void
{
$db = $this->getConnection();
$driver = $db->getDriverName();
$sql = $db->getQueryBuilder()->refreshMaterializedView($viewName, $concurrently, $withData);
$actual = DbHelper::replaceQuotes($sql, $driver);
$expected = DbHelper::replaceQuotes($expected, $driver);

$this->assertSame($expected, $actual);
}
}

0 comments on commit d38325b

Please sign in to comment.