Skip to content

Commit d53feec

Browse files
committed
refactor: add skip_grants flag to SnapshotEvaluator.create
1 parent 2180b44 commit d53feec

File tree

2 files changed

+50
-29
lines changed

2 files changed

+50
-29
lines changed

sqlmesh/core/snapshot/evaluator.py

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,7 @@ def create_snapshot(
872872
deployability_index=deployability_index,
873873
create_render_kwargs=create_render_kwargs,
874874
rendered_physical_properties=rendered_physical_properties,
875+
skip_grants=True,
875876
dry_run=True,
876877
)
877878

@@ -1422,12 +1423,12 @@ def _execute_create(
14221423
table_name=table_name,
14231424
model=snapshot.model,
14241425
is_table_deployable=is_table_deployable,
1426+
skip_grants=skip_grants,
14251427
render_kwargs=create_render_kwargs,
14261428
is_snapshot_deployable=is_snapshot_deployable,
14271429
is_snapshot_representative=is_snapshot_representative,
14281430
dry_run=dry_run,
14291431
physical_properties=rendered_physical_properties,
1430-
skip_grants=skip_grants,
14311432
)
14321433
if run_pre_post_statements:
14331434
adapter.execute(snapshot.model.render_post_statements(**create_render_kwargs))
@@ -1591,6 +1592,7 @@ def create(
15911592
model: Model,
15921593
is_table_deployable: bool,
15931594
render_kwargs: t.Dict[str, t.Any],
1595+
skip_grants: bool,
15941596
**kwargs: t.Any,
15951597
) -> None:
15961598
"""Creates the target table or view.
@@ -1734,6 +1736,7 @@ def create(
17341736
model: Model,
17351737
is_table_deployable: bool,
17361738
render_kwargs: t.Dict[str, t.Any],
1739+
skip_grants: bool,
17371740
**kwargs: t.Any,
17381741
) -> None:
17391742
pass
@@ -1809,10 +1812,10 @@ def promote(
18091812
view_properties=model.render_virtual_properties(**render_kwargs),
18101813
)
18111814

1812-
# Apply grants to the physical layer table
1815+
# Apply grants to the physical layer (referenced table / view) after promotion
18131816
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18141817

1815-
# Apply grants to the virtual layer view
1818+
# Apply grants to the virtual layer (view) after promotion
18161819
self._apply_grants(model, view_name, GrantsTargetLayer.VIRTUAL)
18171820

18181821
def demote(self, view_name: str, **kwargs: t.Any) -> None:
@@ -1827,6 +1830,7 @@ def create(
18271830
model: Model,
18281831
is_table_deployable: bool,
18291832
render_kwargs: t.Dict[str, t.Any],
1833+
skip_grants: bool,
18301834
**kwargs: t.Any,
18311835
) -> None:
18321836
ctas_query = model.ctas_query(**render_kwargs)
@@ -1872,7 +1876,7 @@ def create(
18721876
)
18731877

18741878
# Apply grants after table creation (unless explicitly skipped by caller)
1875-
if not kwargs.get("skip_grants", False):
1879+
if not skip_grants:
18761880
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18771881

18781882
def migrate(
@@ -1914,6 +1918,7 @@ def _replace_query_for_model(
19141918
name: str,
19151919
query_or_df: QueryOrDF,
19161920
render_kwargs: t.Dict[str, t.Any],
1921+
skip_grants: bool = False,
19171922
**kwargs: t.Any,
19181923
) -> None:
19191924
"""Replaces the table for the given model.
@@ -1951,7 +1956,7 @@ def _replace_query_for_model(
19511956
)
19521957

19531958
# Apply grants after table replacement (unless explicitly skipped by caller)
1954-
if not kwargs.get("skip_grants", False):
1959+
if not skip_grants:
19551960
self._apply_grants(model, name, GrantsTargetLayer.PHYSICAL)
19561961

19571962
def _get_target_and_source_columns(
@@ -2201,6 +2206,7 @@ def create(
22012206
model: Model,
22022207
is_table_deployable: bool,
22032208
render_kwargs: t.Dict[str, t.Any],
2209+
skip_grants: bool,
22042210
**kwargs: t.Any,
22052211
) -> None:
22062212
model = t.cast(SeedModel, model)
@@ -2214,29 +2220,38 @@ def create(
22142220
)
22152221
return
22162222

2217-
# Skip grants in parent create call since we'll apply them after data insertion
2218-
kwargs_no_grants = {**kwargs}
2219-
kwargs_no_grants["skip_grants"] = True
2220-
2221-
super().create(table_name, model, is_table_deployable, render_kwargs, **kwargs_no_grants)
2223+
super().create(
2224+
table_name,
2225+
model,
2226+
is_table_deployable,
2227+
render_kwargs,
2228+
skip_grants=True, # Skip grants; they're applied after data insertion
2229+
**kwargs,
2230+
)
22222231
# For seeds we insert data at the time of table creation.
22232232
try:
22242233
for index, df in enumerate(model.render_seed()):
22252234
if index == 0:
22262235
self._replace_query_for_model(
2227-
model, table_name, df, render_kwargs, **kwargs_no_grants
2236+
model,
2237+
table_name,
2238+
df,
2239+
render_kwargs,
2240+
skip_grants=True, # Skip grants; they're applied after data insertion
2241+
**kwargs,
22282242
)
22292243
else:
22302244
self.adapter.insert_append(
22312245
table_name, df, target_columns_to_types=model.columns_to_types
22322246
)
2247+
2248+
if not skip_grants:
2249+
# Apply grants after seed table creation and data insertion
2250+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
22332251
except Exception:
22342252
self.adapter.drop_table(table_name)
22352253
raise
22362254

2237-
# Apply grants after seed table creation or data insertion
2238-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2239-
22402255
def insert(
22412256
self,
22422257
table_name: str,
@@ -2268,6 +2283,7 @@ def create(
22682283
model: Model,
22692284
is_table_deployable: bool,
22702285
render_kwargs: t.Dict[str, t.Any],
2286+
skip_grants: bool,
22712287
**kwargs: t.Any,
22722288
) -> None:
22732289
assert isinstance(model.kind, (SCDType2ByTimeKind, SCDType2ByColumnKind))
@@ -2297,11 +2313,13 @@ def create(
22972313
model,
22982314
is_table_deployable,
22992315
render_kwargs,
2316+
skip_grants,
23002317
**kwargs,
23012318
)
23022319

2303-
# Apply grants after SCD Type 2 table creation
2304-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2320+
if not skip_grants:
2321+
# Apply grants after SCD Type 2 table creation
2322+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
23052323

23062324
def insert(
23072325
self,
@@ -2445,14 +2463,17 @@ def create(
24452463
model: Model,
24462464
is_table_deployable: bool,
24472465
render_kwargs: t.Dict[str, t.Any],
2466+
skip_grants: bool,
24482467
**kwargs: t.Any,
24492468
) -> None:
24502469
if self.adapter.table_exists(table_name):
24512470
# Make sure we don't recreate the view to prevent deletion of downstream views in engines with no late
24522471
# binding support (because of DROP CASCADE).
24532472
logger.info("View '%s' already exists", table_name)
2454-
# Always apply grants when present, even if view exists, to handle grants updates
2455-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2473+
2474+
if not skip_grants:
2475+
# Always apply grants when present, even if view exists, to handle grants updates
2476+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24562477
return
24572478

24582479
logger.info("Creating view '%s'", table_name)
@@ -2476,8 +2497,9 @@ def create(
24762497
column_descriptions=model.column_descriptions if is_table_deployable else None,
24772498
)
24782499

2479-
# Apply grants after view creation
2480-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2500+
if not skip_grants:
2501+
# Apply grants after view creation
2502+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24812503

24822504
def migrate(
24832505
self,
@@ -2654,6 +2676,7 @@ def create(
26542676
model: Model,
26552677
is_table_deployable: bool,
26562678
render_kwargs: t.Dict[str, t.Any],
2679+
skip_grants: bool,
26572680
**kwargs: t.Any,
26582681
) -> None:
26592682
is_snapshot_deployable: bool = kwargs["is_snapshot_deployable"]
@@ -2674,24 +2697,21 @@ def create(
26742697
)
26752698

26762699
# Apply grants after managed table creation
2677-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2700+
if not skip_grants:
2701+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
26782702

26792703
elif not is_table_deployable:
26802704
# Only create the dev preview table as a normal table.
26812705
# For the main table, if the snapshot is cant be deployed to prod (eg upstream is forward-only) do nothing.
26822706
# Any downstream models that reference it will be updated to point to the dev preview table.
26832707
# If the user eventually tries to deploy it, the logic in insert() will see it doesnt exist and create it
2684-
2685-
# Create preview table but don't apply grants here since the table is not deployable
2686-
# Grants will be applied later when the table becomes deployable
2687-
kwargs_no_grants = {**kwargs}
2688-
kwargs_no_grants["skip_grants"] = True
26892708
super().create(
26902709
table_name=table_name,
26912710
model=model,
26922711
is_table_deployable=is_table_deployable,
26932712
render_kwargs=render_kwargs,
2694-
**kwargs_no_grants,
2713+
skip_grants=skip_grants,
2714+
**kwargs,
26952715
)
26962716

26972717
def insert(
@@ -2718,6 +2738,7 @@ def insert(
27182738
column_descriptions=model.column_descriptions,
27192739
table_format=model.table_format,
27202740
)
2741+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
27212742
elif not is_snapshot_deployable:
27222743
# Snapshot isnt deployable; update the preview table instead
27232744
# If the snapshot was deployable, then data would have already been loaded in create() because a managed table would have been created
@@ -2767,7 +2788,7 @@ def migrate(
27672788
)
27682789

27692790
# Apply grants after verifying no schema changes
2770-
# This ensures metadata-only changes (grants) are applied
2791+
# This ensures metadata-only grants changes are applied
27712792
self._apply_grants(snapshot.model, target_table_name, GrantsTargetLayer.PHYSICAL)
27722793

27732794
def delete(self, name: str, **kwargs: t.Any) -> None:

tests/core/test_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3192,7 +3192,6 @@ def test_grants_through_plan_apply(sushi_context, mocker):
31923192
update={
31933193
"grants": {"select": ["analyst", "reporter"]},
31943194
"grants_target_layer": GrantsTargetLayer.ALL,
3195-
"stamp": "add initial grants",
31963195
}
31973196
)
31983197
sushi_context.upsert_model(model_with_grants)
@@ -3219,5 +3218,6 @@ def test_grants_through_plan_apply(sushi_context, mocker):
32193218
sushi_context.plan("dev", no_prompts=True, auto_apply=True)
32203219

32213220
assert sync_grants_mock.call_count == 2
3221+
32223222
expected_grants = {"select": ["analyst", "reporter", "manager"], "insert": ["etl_user"]}
32233223
assert all(call[0][1] == expected_grants for call in sync_grants_mock.call_args_list)

0 commit comments

Comments
 (0)