Skip to content

Commit d38325b

Browse files
committed
Base refresh materialized view
1 parent ef81e8b commit d38325b

File tree

6 files changed

+144
-1
lines changed

6 files changed

+144
-1
lines changed

src/Command/AbstractCommand.php

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Closure;
88
use Throwable;
99
use Yiisoft\Db\Exception\Exception;
10+
use Yiisoft\Db\Exception\NotSupportedException;
1011
use Yiisoft\Db\Expression\Expression;
1112
use Yiisoft\Db\Query\Data\DataReaderInterface;
1213
use Yiisoft\Db\Query\QueryInterface;
@@ -21,6 +22,7 @@
2122
use function is_scalar;
2223
use function is_string;
2324
use function preg_replace_callback;
25+
use function sprintf;
2426
use function str_starts_with;
2527
use function stream_get_contents;
2628

@@ -526,6 +528,13 @@ public function upsert(
526528
return $this->setSql($sql)->bindValues($params);
527529
}
528530

531+
public function refreshMaterializedView(string $viewName, ?bool $concurrently = null, ?bool $withData = null): bool
532+
{
533+
$sql = $this->getQueryBuilder()->refreshMaterializedView($viewName, $concurrently ?? false, $withData);
534+
535+
throw new NotSupportedException(sprintf('"%s" command not supported', $sql));
536+
}
537+
529538
/**
530539
* @return QueryBuilderInterface The query builder instance.
531540
*/

src/Command/CommandInterface.php

+10
Original file line numberDiff line numberDiff line change
@@ -833,4 +833,14 @@ public function upsert(
833833
bool|array $updateColumns = true,
834834
array $params = []
835835
): static;
836+
837+
/**
838+
*
839+
* Execute `REFRESH MATERIALIZED VIEW` command
840+
* @param string $viewName
841+
* @param bool|null $concurrently If `null` then auto choice from depends on DBMS
842+
* @param bool|null $withData
843+
* @return bool
844+
*/
845+
public function refreshMaterializedView(string $viewName, ?bool $concurrently = null, ?bool $withData = null): bool;
836846
}

src/QueryBuilder/AbstractDDLQueryBuilder.php

+18
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Yiisoft\Db\Schema\SchemaInterface;
1212

1313
use function implode;
14+
use function is_bool;
1415
use function is_string;
1516
use function preg_split;
1617

@@ -302,4 +303,21 @@ public function truncateTable(string $table): string
302303
{
303304
return 'TRUNCATE TABLE ' . $this->quoter->quoteTableName($table);
304305
}
306+
307+
public function refreshMaterializedView(string $viewName, bool $concurrently = false, ?bool $withData = null): string
308+
{
309+
$sql = 'REFRESH MATERIALIZED VIEW ';
310+
311+
if ($concurrently) {
312+
$sql .= 'CONCURRENTLY ';
313+
}
314+
315+
$sql .= $this->quoter->quoteTableName($viewName);
316+
317+
if (is_bool($withData)) {
318+
$sql .= ' WITH ' . ($withData ? 'DATA' : 'NO DATA');
319+
}
320+
321+
return $sql;
322+
}
305323
}

src/QueryBuilder/DDLQueryBuilderInterface.php

+11
Original file line numberDiff line numberDiff line change
@@ -424,4 +424,15 @@ public function renameTable(string $oldName, string $newName): string;
424424
* Note: The method will quote the `table` parameter before using it in the generated SQL.
425425
*/
426426
public function truncateTable(string $table): string;
427+
428+
/**
429+
* Refresh materialized view
430+
*
431+
* @param string $viewName The name of the view to refresh.
432+
* @param bool $concurrently Refresh the materialized view without locking out concurrent selects on the materialized view.
433+
* @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
434+
*
435+
* @return string The `REFRESH MATERIALIZED VIEW` SQL statement
436+
*/
437+
public function refreshMaterializedView(string $viewName, bool $concurrently = false, ?bool $withData = null): string;
427438
}

tests/Db/Command/CommandTest.php

+35
Original file line numberDiff line numberDiff line change
@@ -727,4 +727,39 @@ public function testProfilerData(string $sql = null): void
727727
);
728728
parent::testProfilerData();
729729
}
730+
731+
public static function refreshMaterializedViewDataProvider(): array
732+
{
733+
return [
734+
[
735+
'default_mt',
736+
null,
737+
null,
738+
],
739+
[
740+
'concurrently_mt',
741+
true,
742+
null,
743+
],
744+
[
745+
'concurrently_with_data_mt',
746+
true,
747+
true,
748+
],
749+
[
750+
'concurrently_without_data_mt',
751+
true,
752+
false,
753+
],
754+
];
755+
}
756+
757+
758+
public function testRefreshMaterializedView(string $viewName, ?bool $concurrently, ?bool $withData): void
759+
{
760+
$db = $this->getConnection();
761+
$this->expectException(NotSupportedException::class);
762+
763+
$db->createCommand()->refreshMaterializedView($viewName, $concurrently, $withData);
764+
}
730765
}

tests/Db/QueryBuilder/QueryBuilderTest.php

+61-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ public function testGetExpressionBuilderException(): void
178178

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

181-
$expression = new class () implements ExpressionInterface {
181+
$expression = new class() implements ExpressionInterface {
182182
};
183183
$qb = $db->getQueryBuilder();
184184
$qb->getExpressionBuilder($expression);
@@ -310,4 +310,64 @@ public function testUpsertExecute(
310310
$actualParams = [];
311311
$actualSQL = $db->getQueryBuilder()->upsert($table, $insertColumns, $updateColumns, $actualParams);
312312
}
313+
314+
315+
public static function refreshMaterializedViewDataProvider(): array
316+
{
317+
return [
318+
[
319+
'concurrently_mt',
320+
true,
321+
null,
322+
'REFRESH MATERIALIZED VIEW CONCURRENTLY [[concurrently_mt]]',
323+
],
324+
[
325+
'concurrently_with_data_mt',
326+
true,
327+
true,
328+
'REFRESH MATERIALIZED VIEW CONCURRENTLY [[concurrently_mt]] WITH DATA',
329+
],
330+
[
331+
'concurrently_without_data_mt',
332+
true,
333+
false,
334+
'REFRESH MATERIALIZED VIEW CONCURRENTLY [[concurrently_mt]] WITH NO DATA',
335+
],
336+
[
337+
'not_concurrently_mt',
338+
false,
339+
null,
340+
'REFRESH MATERIALIZED VIEW [[concurrently_mt]]',
341+
],
342+
[
343+
'not_concurrently_with_data_mt',
344+
false,
345+
true,
346+
'REFRESH MATERIALIZED VIEW [[concurrently_mt]] WITH DATA',
347+
],
348+
[
349+
'not_concurrently_without_data_mt',
350+
false,
351+
false,
352+
'REFRESH MATERIALIZED VIEW [[concurrently_mt]] WITH NO DATA',
353+
],
354+
];
355+
}
356+
357+
/**
358+
* @dataProvider refreshMaterializedViewDataProvider
359+
* @param bool $concurrently
360+
* @param bool|null $withData
361+
* @return void
362+
*/
363+
public function testRefreshMaterializedView(string $viewName, bool $concurrently, ?bool $withData, string $expected): void
364+
{
365+
$db = $this->getConnection();
366+
$driver = $db->getDriverName();
367+
$sql = $db->getQueryBuilder()->refreshMaterializedView($viewName, $concurrently, $withData);
368+
$actual = DbHelper::replaceQuotes($sql, $driver);
369+
$expected = DbHelper::replaceQuotes($expected, $driver);
370+
371+
$this->assertSame($expected, $actual);
372+
}
313373
}

0 commit comments

Comments
 (0)