66
77import sqlalchemy as sa
88from sqlalchemy .ext import compiler
9- from sqlalchemy .schema import DDLElement , MetaData
109from sqlalchemy .orm import Session
10+ from sqlalchemy .schema import DDLElement , MetaData
1111
1212from mavedb .db .base import Base
1313
@@ -32,7 +32,53 @@ class MaterializedView(Base):
3232
3333 @classmethod
3434 def refresh (cls , connection , concurrently = True ):
35- """Refresh this materialized view."""
35+ """
36+ Refresh the underlying materialized view for this ORM-mapped class.
37+
38+ This class method delegates to `refresh_mat_view` to issue a database
39+ REFRESH MATERIALIZED VIEW (optionally CONCURRENTLY) statement for the
40+ materialized view backing the current model (`cls.__table__.fullname`).
41+
42+ Parameters
43+ ---------
44+ connection : sqlalchemy.engine.Connection | sqlalchemy.orm.Session
45+ An active SQLAlchemy connection or session bound to the target database.
46+ concurrently : bool, default True
47+ If True, performs a concurrent refresh (REFRESH MATERIALIZED VIEW CONCURRENTLY),
48+ allowing reads during the refresh when the database backend supports it.
49+ If False, performs a blocking refresh.
50+
51+ Returns
52+ -------
53+ None
54+
55+ Raises
56+ ------
57+ sqlalchemy.exc.DBAPIError
58+ If the database reports an error while refreshing the materialized view.
59+ sqlalchemy.exc.OperationalError
60+ For operational issues such as locks or insufficient privileges.
61+ ValueError
62+ If the connection provided is not a valid SQLAlchemy connection/session.
63+
64+ Notes
65+ -----
66+ - A concurrent refresh typically requires the materialized view to have a unique
67+ index matching all rows; otherwise the database may reject the operation.
68+ - This operation does not return a value; it is executed for its side effect.
69+ - Ensure the connection/session is in a clean transactional state if you rely on
70+ consistent snapshot semantics.
71+ - This function commits no changes; it is the caller's responsibility to
72+ commit the session if needed.
73+
74+ Examples
75+ --------
76+ # Refresh with concurrent mode (default)
77+ MyMaterializedView.refresh(connection)
78+
79+ # Perform a blocking refresh
80+ MyMaterializedView.refresh(connection, concurrently=False)
81+ """
3682 refresh_mat_view (connection , cls .__table__ .fullname , concurrently )
3783
3884
@@ -123,19 +169,91 @@ class MyView(Base):
123169
124170def refresh_mat_view (session : Session , name : str , concurrently = True ):
125171 """
126- Refreshes a single materialized view, given by `name`.
172+ Refresh a PostgreSQL materialized view within the current SQLAlchemy session.
173+
174+ This helper issues a REFRESH MATERIALIZED VIEW statement for the specified
175+ materialized view name. It first explicitly flushes the session because
176+ session.execute() bypasses SQLAlchemy's autoflush mechanism; without the flush,
177+ pending changes (e.g., newly inserted/updated rows that the view depends on)
178+ might not be reflected in the refreshed view.
179+
180+ Parameters
181+ ----------
182+ session : sqlalchemy.orm.Session
183+ An active SQLAlchemy session bound to a PostgreSQL database.
184+ name : str
185+ The exact name (optionally schema-qualified) of the materialized view to refresh.
186+ concurrently : bool, default True
187+ If True, uses REFRESH MATERIALIZED VIEW CONCURRENTLY allowing reads during
188+ the refresh and requiring a unique index on the materialized view. If False,
189+ performs a blocking refresh.
190+
191+ Raises
192+ ------
193+ sqlalchemy.exc.SQLAlchemyError
194+ Propagates any database errors encountered during execution (e.g.,
195+ insufficient privileges, missing view, lack of required unique index for
196+ CONCURRENTLY).
197+
198+ Notes
199+ -----
200+ - Using CONCURRENTLY requires the materialized view to have at least one
201+ unique index; otherwise PostgreSQL will raise an error.
202+ - The operation does not return a value; it is executed for its side effect.
203+ - Ensure the session is in a clean transactional state if you rely on
204+ consistent snapshot semantics.
205+ - This function commits no changes; it is the caller's responsibility to
206+ commit the session if needed.
207+
208+ Examples
209+ --------
210+ refresh_mat_view(session, "public.my_materialized_view")
211+ refresh_mat_view(session, "reports.daily_stats", concurrently=False)
127212 """
128213 # since session.execute() bypasses autoflush, must manually flush in order
129214 # to include newly-created/modified objects in the refresh
130215 session .flush ()
216+
131217 _con = "CONCURRENTLY " if concurrently else ""
132218 session .execute (sa .text ("REFRESH MATERIALIZED VIEW " + _con + name ))
133219
134220
135221def refresh_all_mat_views (session : Session , concurrently = True ):
136222 """
137- Refreshes all materialized views. Views are refreshed in non-deterministic order,
138- so view definitions can't depend on each other.
223+ Refreshes all PostgreSQL materialized views visible to the given SQLAlchemy session.
224+
225+ The function inspects the current database connection for registered materialized
226+ views and issues a REFRESH MATERIALIZED VIEW command for each one using the helper
227+ function `refresh_mat_view`. After all refresh operations complete, the session
228+ is committed to persist any transactional side effects of the refresh statements.
229+
230+ Parameters
231+ ----------
232+ session : sqlalchemy.orm.Session
233+ An active SQLAlchemy session bound to a PostgreSQL connection.
234+ concurrently : bool, default True
235+ If True, each materialized view is refreshed using the CONCURRENTLY option
236+ (only supported when the view has a unique index that satisfies PostgreSQL
237+ requirements). If False, a standard blocking refresh is performed.
238+
239+ Behavior
240+ --------
241+ - If inspection of the connection fails or returns no inspector, the function
242+ exits without performing any work.
243+ - Each materialized view name returned by the inspector is passed to
244+ `refresh_mat_view(session, name, concurrently)`.
245+
246+ Notes
247+ -----
248+ - Using CONCURRENTLY allows reads during refresh at the cost of requiring an
249+ appropriate unique index and potentially being slower.
250+ - Exceptions raised during individual refresh operations will propagate unless
251+ `refresh_mat_view` handles them internally; in such a case the commit will
252+ not be reached.
253+ - Ensure the session is in a clean transactional state if you rely on
254+ consistent snapshot semantics.
255+ - This function commits no changes; it is the caller's responsibility to
256+ commit the session if needed.
139257 """
140258 inspector = sa .inspect (session .connection ())
141259
0 commit comments