Skip to content

Commit a10408b

Browse files
committed
refactor: add skip_grants flag to SnapshotEvaluator.create
1 parent ad11122 commit a10408b

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
@@ -878,6 +878,7 @@ def create_snapshot(
878878
deployability_index=deployability_index,
879879
create_render_kwargs=create_render_kwargs,
880880
rendered_physical_properties=rendered_physical_properties,
881+
skip_grants=True,
881882
dry_run=True,
882883
)
883884

@@ -1436,12 +1437,12 @@ def _execute_create(
14361437
table_name=table_name,
14371438
model=snapshot.model,
14381439
is_table_deployable=is_table_deployable,
1440+
skip_grants=skip_grants,
14391441
render_kwargs=create_render_kwargs,
14401442
is_snapshot_deployable=is_snapshot_deployable,
14411443
is_snapshot_representative=is_snapshot_representative,
14421444
dry_run=dry_run,
14431445
physical_properties=rendered_physical_properties,
1444-
skip_grants=skip_grants,
14451446
)
14461447
if run_pre_post_statements:
14471448
adapter.execute(snapshot.model.render_post_statements(**create_render_kwargs))
@@ -1606,6 +1607,7 @@ def create(
16061607
model: Model,
16071608
is_table_deployable: bool,
16081609
render_kwargs: t.Dict[str, t.Any],
1610+
skip_grants: bool,
16091611
**kwargs: t.Any,
16101612
) -> None:
16111613
"""Creates the target table or view.
@@ -1749,6 +1751,7 @@ def create(
17491751
model: Model,
17501752
is_table_deployable: bool,
17511753
render_kwargs: t.Dict[str, t.Any],
1754+
skip_grants: bool,
17521755
**kwargs: t.Any,
17531756
) -> None:
17541757
pass
@@ -1824,10 +1827,10 @@ def promote(
18241827
view_properties=model.render_virtual_properties(**render_kwargs),
18251828
)
18261829

1827-
# Apply grants to the physical layer table
1830+
# Apply grants to the physical layer (referenced table / view) after promotion
18281831
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18291832

1830-
# Apply grants to the virtual layer view
1833+
# Apply grants to the virtual layer (view) after promotion
18311834
self._apply_grants(model, view_name, GrantsTargetLayer.VIRTUAL)
18321835

18331836
def demote(self, view_name: str, **kwargs: t.Any) -> None:
@@ -1842,6 +1845,7 @@ def create(
18421845
model: Model,
18431846
is_table_deployable: bool,
18441847
render_kwargs: t.Dict[str, t.Any],
1848+
skip_grants: bool,
18451849
**kwargs: t.Any,
18461850
) -> None:
18471851
ctas_query = model.ctas_query(**render_kwargs)
@@ -1887,7 +1891,7 @@ def create(
18871891
)
18881892

18891893
# Apply grants after table creation (unless explicitly skipped by caller)
1890-
if not kwargs.get("skip_grants", False):
1894+
if not skip_grants:
18911895
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18921896

18931897
def migrate(
@@ -1929,6 +1933,7 @@ def _replace_query_for_model(
19291933
name: str,
19301934
query_or_df: QueryOrDF,
19311935
render_kwargs: t.Dict[str, t.Any],
1936+
skip_grants: bool = False,
19321937
**kwargs: t.Any,
19331938
) -> None:
19341939
"""Replaces the table for the given model.
@@ -1966,7 +1971,7 @@ def _replace_query_for_model(
19661971
)
19671972

19681973
# Apply grants after table replacement (unless explicitly skipped by caller)
1969-
if not kwargs.get("skip_grants", False):
1974+
if not skip_grants:
19701975
self._apply_grants(model, name, GrantsTargetLayer.PHYSICAL)
19711976

19721977
def _get_target_and_source_columns(
@@ -2216,6 +2221,7 @@ def create(
22162221
model: Model,
22172222
is_table_deployable: bool,
22182223
render_kwargs: t.Dict[str, t.Any],
2224+
skip_grants: bool,
22192225
**kwargs: t.Any,
22202226
) -> None:
22212227
model = t.cast(SeedModel, model)
@@ -2229,29 +2235,38 @@ def create(
22292235
)
22302236
return
22312237

2232-
# Skip grants in parent create call since we'll apply them after data insertion
2233-
kwargs_no_grants = {**kwargs}
2234-
kwargs_no_grants["skip_grants"] = True
2235-
2236-
super().create(table_name, model, is_table_deployable, render_kwargs, **kwargs_no_grants)
2238+
super().create(
2239+
table_name,
2240+
model,
2241+
is_table_deployable,
2242+
render_kwargs,
2243+
skip_grants=True, # Skip grants; they're applied after data insertion
2244+
**kwargs,
2245+
)
22372246
# For seeds we insert data at the time of table creation.
22382247
try:
22392248
for index, df in enumerate(model.render_seed()):
22402249
if index == 0:
22412250
self._replace_query_for_model(
2242-
model, table_name, df, render_kwargs, **kwargs_no_grants
2251+
model,
2252+
table_name,
2253+
df,
2254+
render_kwargs,
2255+
skip_grants=True, # Skip grants; they're applied after data insertion
2256+
**kwargs,
22432257
)
22442258
else:
22452259
self.adapter.insert_append(
22462260
table_name, df, target_columns_to_types=model.columns_to_types
22472261
)
2262+
2263+
if not skip_grants:
2264+
# Apply grants after seed table creation and data insertion
2265+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
22482266
except Exception:
22492267
self.adapter.drop_table(table_name)
22502268
raise
22512269

2252-
# Apply grants after seed table creation or data insertion
2253-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2254-
22552270
def insert(
22562271
self,
22572272
table_name: str,
@@ -2283,6 +2298,7 @@ def create(
22832298
model: Model,
22842299
is_table_deployable: bool,
22852300
render_kwargs: t.Dict[str, t.Any],
2301+
skip_grants: bool,
22862302
**kwargs: t.Any,
22872303
) -> None:
22882304
assert isinstance(model.kind, (SCDType2ByTimeKind, SCDType2ByColumnKind))
@@ -2312,11 +2328,13 @@ def create(
23122328
model,
23132329
is_table_deployable,
23142330
render_kwargs,
2331+
skip_grants,
23152332
**kwargs,
23162333
)
23172334

2318-
# Apply grants after SCD Type 2 table creation
2319-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2335+
if not skip_grants:
2336+
# Apply grants after SCD Type 2 table creation
2337+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
23202338

23212339
def insert(
23222340
self,
@@ -2460,14 +2478,17 @@ def create(
24602478
model: Model,
24612479
is_table_deployable: bool,
24622480
render_kwargs: t.Dict[str, t.Any],
2481+
skip_grants: bool,
24632482
**kwargs: t.Any,
24642483
) -> None:
24652484
if self.adapter.table_exists(table_name):
24662485
# Make sure we don't recreate the view to prevent deletion of downstream views in engines with no late
24672486
# binding support (because of DROP CASCADE).
24682487
logger.info("View '%s' already exists", table_name)
2469-
# Always apply grants when present, even if view exists, to handle grants updates
2470-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2488+
2489+
if not skip_grants:
2490+
# Always apply grants when present, even if view exists, to handle grants updates
2491+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24712492
return
24722493

24732494
logger.info("Creating view '%s'", table_name)
@@ -2491,8 +2512,9 @@ def create(
24912512
column_descriptions=model.column_descriptions if is_table_deployable else None,
24922513
)
24932514

2494-
# Apply grants after view creation
2495-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2515+
if not skip_grants:
2516+
# Apply grants after view creation
2517+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24962518

24972519
def migrate(
24982520
self,
@@ -2669,6 +2691,7 @@ def create(
26692691
model: Model,
26702692
is_table_deployable: bool,
26712693
render_kwargs: t.Dict[str, t.Any],
2694+
skip_grants: bool,
26722695
**kwargs: t.Any,
26732696
) -> None:
26742697
is_snapshot_deployable: bool = kwargs["is_snapshot_deployable"]
@@ -2689,24 +2712,21 @@ def create(
26892712
)
26902713

26912714
# Apply grants after managed table creation
2692-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2715+
if not skip_grants:
2716+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
26932717

26942718
elif not is_table_deployable:
26952719
# Only create the dev preview table as a normal table.
26962720
# For the main table, if the snapshot is cant be deployed to prod (eg upstream is forward-only) do nothing.
26972721
# Any downstream models that reference it will be updated to point to the dev preview table.
26982722
# If the user eventually tries to deploy it, the logic in insert() will see it doesnt exist and create it
2699-
2700-
# Create preview table but don't apply grants here since the table is not deployable
2701-
# Grants will be applied later when the table becomes deployable
2702-
kwargs_no_grants = {**kwargs}
2703-
kwargs_no_grants["skip_grants"] = True
27042723
super().create(
27052724
table_name=table_name,
27062725
model=model,
27072726
is_table_deployable=is_table_deployable,
27082727
render_kwargs=render_kwargs,
2709-
**kwargs_no_grants,
2728+
skip_grants=skip_grants,
2729+
**kwargs,
27102730
)
27112731

27122732
def insert(
@@ -2733,6 +2753,7 @@ def insert(
27332753
column_descriptions=model.column_descriptions,
27342754
table_format=model.table_format,
27352755
)
2756+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
27362757
elif not is_snapshot_deployable:
27372758
# Snapshot isnt deployable; update the preview table instead
27382759
# If the snapshot was deployable, then data would have already been loaded in create() because a managed table would have been created
@@ -2782,7 +2803,7 @@ def migrate(
27822803
)
27832804

27842805
# Apply grants after verifying no schema changes
2785-
# This ensures metadata-only changes (grants) are applied
2806+
# This ensures metadata-only grants changes are applied
27862807
self._apply_grants(snapshot.model, target_table_name, GrantsTargetLayer.PHYSICAL)
27872808

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