Skip to content

Commit 03e709c

Browse files
committed
refactor: add skip_grants flag to SnapshotEvaluator.create
1 parent 0dbc845 commit 03e709c

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
@@ -873,6 +873,7 @@ def create_snapshot(
873873
deployability_index=deployability_index,
874874
create_render_kwargs=create_render_kwargs,
875875
rendered_physical_properties=rendered_physical_properties,
876+
skip_grants=True,
876877
dry_run=True,
877878
)
878879

@@ -1411,12 +1412,12 @@ def _execute_create(
14111412
table_name=table_name,
14121413
model=snapshot.model,
14131414
is_table_deployable=is_table_deployable,
1415+
skip_grants=skip_grants,
14141416
render_kwargs=create_render_kwargs,
14151417
is_snapshot_deployable=is_snapshot_deployable,
14161418
is_snapshot_representative=is_snapshot_representative,
14171419
dry_run=dry_run,
14181420
physical_properties=rendered_physical_properties,
1419-
skip_grants=skip_grants,
14201421
)
14211422
if run_pre_post_statements:
14221423
adapter.execute(snapshot.model.render_post_statements(**create_render_kwargs))
@@ -1580,6 +1581,7 @@ def create(
15801581
model: Model,
15811582
is_table_deployable: bool,
15821583
render_kwargs: t.Dict[str, t.Any],
1584+
skip_grants: bool,
15831585
**kwargs: t.Any,
15841586
) -> None:
15851587
"""Creates the target table or view.
@@ -1723,6 +1725,7 @@ def create(
17231725
model: Model,
17241726
is_table_deployable: bool,
17251727
render_kwargs: t.Dict[str, t.Any],
1728+
skip_grants: bool,
17261729
**kwargs: t.Any,
17271730
) -> None:
17281731
pass
@@ -1798,10 +1801,10 @@ def promote(
17981801
view_properties=model.render_virtual_properties(**render_kwargs),
17991802
)
18001803

1801-
# Apply grants to the physical layer table
1804+
# Apply grants to the physical layer (referenced table / view) after promotion
18021805
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18031806

1804-
# Apply grants to the virtual layer view
1807+
# Apply grants to the virtual layer (view) after promotion
18051808
self._apply_grants(model, view_name, GrantsTargetLayer.VIRTUAL)
18061809

18071810
def demote(self, view_name: str, **kwargs: t.Any) -> None:
@@ -1816,6 +1819,7 @@ def create(
18161819
model: Model,
18171820
is_table_deployable: bool,
18181821
render_kwargs: t.Dict[str, t.Any],
1822+
skip_grants: bool,
18191823
**kwargs: t.Any,
18201824
) -> None:
18211825
ctas_query = model.ctas_query(**render_kwargs)
@@ -1861,7 +1865,7 @@ def create(
18611865
)
18621866

18631867
# Apply grants after table creation (unless explicitly skipped by caller)
1864-
if not kwargs.get("skip_grants", False):
1868+
if not skip_grants:
18651869
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18661870

18671871
def migrate(
@@ -1903,6 +1907,7 @@ def _replace_query_for_model(
19031907
name: str,
19041908
query_or_df: QueryOrDF,
19051909
render_kwargs: t.Dict[str, t.Any],
1910+
skip_grants: bool = False,
19061911
**kwargs: t.Any,
19071912
) -> None:
19081913
"""Replaces the table for the given model.
@@ -1940,7 +1945,7 @@ def _replace_query_for_model(
19401945
)
19411946

19421947
# Apply grants after table replacement (unless explicitly skipped by caller)
1943-
if not kwargs.get("skip_grants", False):
1948+
if not skip_grants:
19441949
self._apply_grants(model, name, GrantsTargetLayer.PHYSICAL)
19451950

19461951
def _get_target_and_source_columns(
@@ -2190,6 +2195,7 @@ def create(
21902195
model: Model,
21912196
is_table_deployable: bool,
21922197
render_kwargs: t.Dict[str, t.Any],
2198+
skip_grants: bool,
21932199
**kwargs: t.Any,
21942200
) -> None:
21952201
model = t.cast(SeedModel, model)
@@ -2203,29 +2209,38 @@ def create(
22032209
)
22042210
return
22052211

2206-
# Skip grants in parent create call since we'll apply them after data insertion
2207-
kwargs_no_grants = {**kwargs}
2208-
kwargs_no_grants["skip_grants"] = True
2209-
2210-
super().create(table_name, model, is_table_deployable, render_kwargs, **kwargs_no_grants)
2212+
super().create(
2213+
table_name,
2214+
model,
2215+
is_table_deployable,
2216+
render_kwargs,
2217+
skip_grants=True, # Skip grants; they're applied after data insertion
2218+
**kwargs,
2219+
)
22112220
# For seeds we insert data at the time of table creation.
22122221
try:
22132222
for index, df in enumerate(model.render_seed()):
22142223
if index == 0:
22152224
self._replace_query_for_model(
2216-
model, table_name, df, render_kwargs, **kwargs_no_grants
2225+
model,
2226+
table_name,
2227+
df,
2228+
render_kwargs,
2229+
skip_grants=True, # Skip grants; they're applied after data insertion
2230+
**kwargs,
22172231
)
22182232
else:
22192233
self.adapter.insert_append(
22202234
table_name, df, target_columns_to_types=model.columns_to_types
22212235
)
2236+
2237+
if not skip_grants:
2238+
# Apply grants after seed table creation and data insertion
2239+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
22222240
except Exception:
22232241
self.adapter.drop_table(table_name)
22242242
raise
22252243

2226-
# Apply grants after seed table creation or data insertion
2227-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2228-
22292244
def insert(
22302245
self,
22312246
table_name: str,
@@ -2257,6 +2272,7 @@ def create(
22572272
model: Model,
22582273
is_table_deployable: bool,
22592274
render_kwargs: t.Dict[str, t.Any],
2275+
skip_grants: bool,
22602276
**kwargs: t.Any,
22612277
) -> None:
22622278
assert isinstance(model.kind, (SCDType2ByTimeKind, SCDType2ByColumnKind))
@@ -2286,11 +2302,13 @@ def create(
22862302
model,
22872303
is_table_deployable,
22882304
render_kwargs,
2305+
skip_grants,
22892306
**kwargs,
22902307
)
22912308

2292-
# Apply grants after SCD Type 2 table creation
2293-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2309+
if not skip_grants:
2310+
# Apply grants after SCD Type 2 table creation
2311+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
22942312

22952313
def insert(
22962314
self,
@@ -2434,14 +2452,17 @@ def create(
24342452
model: Model,
24352453
is_table_deployable: bool,
24362454
render_kwargs: t.Dict[str, t.Any],
2455+
skip_grants: bool,
24372456
**kwargs: t.Any,
24382457
) -> None:
24392458
if self.adapter.table_exists(table_name):
24402459
# Make sure we don't recreate the view to prevent deletion of downstream views in engines with no late
24412460
# binding support (because of DROP CASCADE).
24422461
logger.info("View '%s' already exists", table_name)
2443-
# Always apply grants when present, even if view exists, to handle grants updates
2444-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2462+
2463+
if not skip_grants:
2464+
# Always apply grants when present, even if view exists, to handle grants updates
2465+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24452466
return
24462467

24472468
logger.info("Creating view '%s'", table_name)
@@ -2465,8 +2486,9 @@ def create(
24652486
column_descriptions=model.column_descriptions if is_table_deployable else None,
24662487
)
24672488

2468-
# Apply grants after view creation
2469-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2489+
if not skip_grants:
2490+
# Apply grants after view creation
2491+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24702492

24712493
def migrate(
24722494
self,
@@ -2643,6 +2665,7 @@ def create(
26432665
model: Model,
26442666
is_table_deployable: bool,
26452667
render_kwargs: t.Dict[str, t.Any],
2668+
skip_grants: bool,
26462669
**kwargs: t.Any,
26472670
) -> None:
26482671
is_snapshot_deployable: bool = kwargs["is_snapshot_deployable"]
@@ -2663,24 +2686,21 @@ def create(
26632686
)
26642687

26652688
# Apply grants after managed table creation
2666-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2689+
if not skip_grants:
2690+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
26672691

26682692
elif not is_table_deployable:
26692693
# Only create the dev preview table as a normal table.
26702694
# For the main table, if the snapshot is cant be deployed to prod (eg upstream is forward-only) do nothing.
26712695
# Any downstream models that reference it will be updated to point to the dev preview table.
26722696
# If the user eventually tries to deploy it, the logic in insert() will see it doesnt exist and create it
2673-
2674-
# Create preview table but don't apply grants here since the table is not deployable
2675-
# Grants will be applied later when the table becomes deployable
2676-
kwargs_no_grants = {**kwargs}
2677-
kwargs_no_grants["skip_grants"] = True
26782697
super().create(
26792698
table_name=table_name,
26802699
model=model,
26812700
is_table_deployable=is_table_deployable,
26822701
render_kwargs=render_kwargs,
2683-
**kwargs_no_grants,
2702+
skip_grants=skip_grants,
2703+
**kwargs,
26842704
)
26852705

26862706
def insert(
@@ -2707,6 +2727,7 @@ def insert(
27072727
column_descriptions=model.column_descriptions,
27082728
table_format=model.table_format,
27092729
)
2730+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
27102731
elif not is_snapshot_deployable:
27112732
# Snapshot isnt deployable; update the preview table instead
27122733
# If the snapshot was deployable, then data would have already been loaded in create() because a managed table would have been created
@@ -2756,7 +2777,7 @@ def migrate(
27562777
)
27572778

27582779
# Apply grants after verifying no schema changes
2759-
# This ensures metadata-only changes (grants) are applied
2780+
# This ensures metadata-only grants changes are applied
27602781
self._apply_grants(snapshot.model, target_table_name, GrantsTargetLayer.PHYSICAL)
27612782

27622783
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)