Skip to content

Commit 90666b3

Browse files
committed
Add util for refreshing specific mat views
1 parent 52bdae8 commit 90666b3

File tree

3 files changed

+86
-2
lines changed

3 files changed

+86
-2
lines changed

django_pgviews/refresh.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
__all__ = ["refresh_specific_views"]
2+
3+
import logging
4+
from collections.abc import Iterable
5+
6+
from django_pgviews import view as pg
7+
from django_pgviews.dependencies import get_views_dependencies, get_views_dependendants, reorder_by_dependencies
8+
9+
logger = logging.getLogger("django_pgviews.refresh")
10+
11+
12+
def refresh_specific_views(
13+
to_refresh: Iterable[type[pg.View]],
14+
concurrently: bool = True,
15+
strict: bool = False,
16+
) -> int:
17+
"""
18+
For a specific set of views, refresh all the materialized views, including all dependants and dependencies.
19+
20+
Returns the number of materialized views refreshed.
21+
"""
22+
23+
to_refresh = list(to_refresh)
24+
25+
to_refresh.extend(get_views_dependendants(to_refresh))
26+
to_refresh.extend(get_views_dependencies(to_refresh))
27+
to_refresh = reorder_by_dependencies(to_refresh)
28+
29+
to_refresh_mat_views: list[type[pg.MaterializedView]] = [
30+
x for x in to_refresh if issubclass(x, pg.MaterializedView)
31+
]
32+
33+
count = 0
34+
35+
for model in to_refresh_mat_views:
36+
model.refresh(concurrently=concurrently, strict=strict)
37+
38+
logger.info(f"Refreshed {model._meta.label}")
39+
40+
count += 1
41+
42+
return count

tests/test_project/viewtest/test_views.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from django_pgviews.signals import all_views_synced, view_synced
2121

2222
from . import models
23-
from .models import LatestSuperusers
2423

2524
try:
2625
from psycopg.errors import UndefinedTable
@@ -252,7 +251,7 @@ def test_get_sql(self):
252251

253252
call_command("sync_pgviews", update=False)
254253

255-
assert LatestSuperusers.objects.count() == 1
254+
assert models.LatestSuperusers.objects.count() == 1
256255

257256
def test_sync_pgviews_materialized_views_check_sql_changed_disabled(self, settings: SettingsWrapper):
258257
settings.MATERIALIZED_VIEWS_CHECK_SQL_CHANGED = False

tests/test_refresh.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import pytest
2+
3+
from django_pgviews.exceptions import ConcurrentIndexNotDefinedError
4+
from django_pgviews.refresh import refresh_specific_views
5+
from tests.test_project.viewtest import models
6+
7+
8+
def test_refresh_no_views():
9+
assert refresh_specific_views([]) == 0
10+
11+
12+
@pytest.mark.django_db
13+
def test_refresh():
14+
assert models.MaterializedRelatedView.objects.count() == 0, "MaterializedRelatedView should not have anything"
15+
assert models.DependantMaterializedView.objects.count() == 0, "DependantMaterializedView should not have anything"
16+
17+
test_model = models.TestModel()
18+
test_model.name = "Bob"
19+
test_model.save()
20+
21+
assert refresh_specific_views([models.MaterializedRelatedView, models.RelatedView]) == 2
22+
23+
assert models.MaterializedRelatedView.objects.count() == 1
24+
assert models.DependantMaterializedView.objects.count() == 1
25+
26+
27+
@pytest.mark.django_db
28+
def test_refresh_concurrently():
29+
with pytest.raises(ConcurrentIndexNotDefinedError):
30+
assert refresh_specific_views(
31+
[models.MaterializedRelatedView, models.RelatedView, models.MaterializedRelatedViewWithIndex],
32+
concurrently=True,
33+
strict=True,
34+
)
35+
36+
assert (
37+
refresh_specific_views(
38+
[models.MaterializedRelatedView, models.RelatedView, models.MaterializedRelatedViewWithIndex],
39+
concurrently=True,
40+
strict=False,
41+
)
42+
== 3
43+
)

0 commit comments

Comments
 (0)