Skip to content

Commit 8498270

Browse files
committed
refactor: add skip_grants flag to SnapshotEvaluator.create
1 parent 9ebd1ea commit 8498270

2 files changed

Lines changed: 50 additions & 29 deletions

File tree

sqlmesh/core/snapshot/evaluator.py

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ def create_snapshot(
882882
deployability_index=deployability_index,
883883
create_render_kwargs=create_render_kwargs,
884884
rendered_physical_properties=rendered_physical_properties,
885+
skip_grants=True,
885886
dry_run=True,
886887
)
887888

@@ -1442,12 +1443,12 @@ def _execute_create(
14421443
table_name=table_name,
14431444
model=snapshot.model,
14441445
is_table_deployable=is_table_deployable,
1446+
skip_grants=skip_grants,
14451447
render_kwargs=create_render_kwargs,
14461448
is_snapshot_deployable=is_snapshot_deployable,
14471449
is_snapshot_representative=is_snapshot_representative,
14481450
dry_run=dry_run,
14491451
physical_properties=rendered_physical_properties,
1450-
skip_grants=skip_grants,
14511452
)
14521453
if run_pre_post_statements:
14531454
adapter.execute(snapshot.model.render_post_statements(**create_render_kwargs))
@@ -1612,6 +1613,7 @@ def create(
16121613
model: Model,
16131614
is_table_deployable: bool,
16141615
render_kwargs: t.Dict[str, t.Any],
1616+
skip_grants: bool,
16151617
**kwargs: t.Any,
16161618
) -> None:
16171619
"""Creates the target table or view.
@@ -1755,6 +1757,7 @@ def create(
17551757
model: Model,
17561758
is_table_deployable: bool,
17571759
render_kwargs: t.Dict[str, t.Any],
1760+
skip_grants: bool,
17581761
**kwargs: t.Any,
17591762
) -> None:
17601763
pass
@@ -1830,10 +1833,10 @@ def promote(
18301833
view_properties=model.render_virtual_properties(**render_kwargs),
18311834
)
18321835

1833-
# Apply grants to the physical layer table
1836+
# Apply grants to the physical layer (referenced table / view) after promotion
18341837
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18351838

1836-
# Apply grants to the virtual layer view
1839+
# Apply grants to the virtual layer (view) after promotion
18371840
self._apply_grants(model, view_name, GrantsTargetLayer.VIRTUAL)
18381841

18391842
def demote(self, view_name: str, **kwargs: t.Any) -> None:
@@ -1848,6 +1851,7 @@ def create(
18481851
model: Model,
18491852
is_table_deployable: bool,
18501853
render_kwargs: t.Dict[str, t.Any],
1854+
skip_grants: bool,
18511855
**kwargs: t.Any,
18521856
) -> None:
18531857
ctas_query = model.ctas_query(**render_kwargs)
@@ -1893,7 +1897,7 @@ def create(
18931897
)
18941898

18951899
# Apply grants after table creation (unless explicitly skipped by caller)
1896-
if not kwargs.get("skip_grants", False):
1900+
if not skip_grants:
18971901
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
18981902

18991903
def migrate(
@@ -1935,6 +1939,7 @@ def _replace_query_for_model(
19351939
name: str,
19361940
query_or_df: QueryOrDF,
19371941
render_kwargs: t.Dict[str, t.Any],
1942+
skip_grants: bool = False,
19381943
**kwargs: t.Any,
19391944
) -> None:
19401945
"""Replaces the table for the given model.
@@ -1972,7 +1977,7 @@ def _replace_query_for_model(
19721977
)
19731978

19741979
# Apply grants after table replacement (unless explicitly skipped by caller)
1975-
if not kwargs.get("skip_grants", False):
1980+
if not skip_grants:
19761981
self._apply_grants(model, name, GrantsTargetLayer.PHYSICAL)
19771982

19781983
def _get_target_and_source_columns(
@@ -2222,6 +2227,7 @@ def create(
22222227
model: Model,
22232228
is_table_deployable: bool,
22242229
render_kwargs: t.Dict[str, t.Any],
2230+
skip_grants: bool,
22252231
**kwargs: t.Any,
22262232
) -> None:
22272233
model = t.cast(SeedModel, model)
@@ -2235,29 +2241,38 @@ def create(
22352241
)
22362242
return
22372243

2238-
# Skip grants in parent create call since we'll apply them after data insertion
2239-
kwargs_no_grants = {**kwargs}
2240-
kwargs_no_grants["skip_grants"] = True
2241-
2242-
super().create(table_name, model, is_table_deployable, render_kwargs, **kwargs_no_grants)
2244+
super().create(
2245+
table_name,
2246+
model,
2247+
is_table_deployable,
2248+
render_kwargs,
2249+
skip_grants=True, # Skip grants; they're applied after data insertion
2250+
**kwargs,
2251+
)
22432252
# For seeds we insert data at the time of table creation.
22442253
try:
22452254
for index, df in enumerate(model.render_seed()):
22462255
if index == 0:
22472256
self._replace_query_for_model(
2248-
model, table_name, df, render_kwargs, **kwargs_no_grants
2257+
model,
2258+
table_name,
2259+
df,
2260+
render_kwargs,
2261+
skip_grants=True, # Skip grants; they're applied after data insertion
2262+
**kwargs,
22492263
)
22502264
else:
22512265
self.adapter.insert_append(
22522266
table_name, df, target_columns_to_types=model.columns_to_types
22532267
)
2268+
2269+
if not skip_grants:
2270+
# Apply grants after seed table creation and data insertion
2271+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
22542272
except Exception:
22552273
self.adapter.drop_table(table_name)
22562274
raise
22572275

2258-
# Apply grants after seed table creation or data insertion
2259-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2260-
22612276
def insert(
22622277
self,
22632278
table_name: str,
@@ -2289,6 +2304,7 @@ def create(
22892304
model: Model,
22902305
is_table_deployable: bool,
22912306
render_kwargs: t.Dict[str, t.Any],
2307+
skip_grants: bool,
22922308
**kwargs: t.Any,
22932309
) -> None:
22942310
assert isinstance(model.kind, (SCDType2ByTimeKind, SCDType2ByColumnKind))
@@ -2318,11 +2334,13 @@ def create(
23182334
model,
23192335
is_table_deployable,
23202336
render_kwargs,
2337+
skip_grants,
23212338
**kwargs,
23222339
)
23232340

2324-
# Apply grants after SCD Type 2 table creation
2325-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2341+
if not skip_grants:
2342+
# Apply grants after SCD Type 2 table creation
2343+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
23262344

23272345
def insert(
23282346
self,
@@ -2466,14 +2484,17 @@ def create(
24662484
model: Model,
24672485
is_table_deployable: bool,
24682486
render_kwargs: t.Dict[str, t.Any],
2487+
skip_grants: bool,
24692488
**kwargs: t.Any,
24702489
) -> None:
24712490
if self.adapter.table_exists(table_name):
24722491
# Make sure we don't recreate the view to prevent deletion of downstream views in engines with no late
24732492
# binding support (because of DROP CASCADE).
24742493
logger.info("View '%s' already exists", table_name)
2475-
# Always apply grants when present, even if view exists, to handle grants updates
2476-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2494+
2495+
if not skip_grants:
2496+
# Always apply grants when present, even if view exists, to handle grants updates
2497+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24772498
return
24782499

24792500
logger.info("Creating view '%s'", table_name)
@@ -2497,8 +2518,9 @@ def create(
24972518
column_descriptions=model.column_descriptions if is_table_deployable else None,
24982519
)
24992520

2500-
# Apply grants after view creation
2501-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2521+
if not skip_grants:
2522+
# Apply grants after view creation
2523+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
25022524

25032525
def migrate(
25042526
self,
@@ -2675,6 +2697,7 @@ def create(
26752697
model: Model,
26762698
is_table_deployable: bool,
26772699
render_kwargs: t.Dict[str, t.Any],
2700+
skip_grants: bool,
26782701
**kwargs: t.Any,
26792702
) -> None:
26802703
is_snapshot_deployable: bool = kwargs["is_snapshot_deployable"]
@@ -2695,24 +2718,21 @@ def create(
26952718
)
26962719

26972720
# Apply grants after managed table creation
2698-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2721+
if not skip_grants:
2722+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
26992723

27002724
elif not is_table_deployable:
27012725
# Only create the dev preview table as a normal table.
27022726
# For the main table, if the snapshot is cant be deployed to prod (eg upstream is forward-only) do nothing.
27032727
# Any downstream models that reference it will be updated to point to the dev preview table.
27042728
# If the user eventually tries to deploy it, the logic in insert() will see it doesnt exist and create it
2705-
2706-
# Create preview table but don't apply grants here since the table is not deployable
2707-
# Grants will be applied later when the table becomes deployable
2708-
kwargs_no_grants = {**kwargs}
2709-
kwargs_no_grants["skip_grants"] = True
27102729
super().create(
27112730
table_name=table_name,
27122731
model=model,
27132732
is_table_deployable=is_table_deployable,
27142733
render_kwargs=render_kwargs,
2715-
**kwargs_no_grants,
2734+
skip_grants=skip_grants,
2735+
**kwargs,
27162736
)
27172737

27182738
def insert(
@@ -2739,6 +2759,7 @@ def insert(
27392759
column_descriptions=model.column_descriptions,
27402760
table_format=model.table_format,
27412761
)
2762+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
27422763
elif not is_snapshot_deployable:
27432764
# Snapshot isnt deployable; update the preview table instead
27442765
# If the snapshot was deployable, then data would have already been loaded in create() because a managed table would have been created
@@ -2788,7 +2809,7 @@ def migrate(
27882809
)
27892810

27902811
# Apply grants after verifying no schema changes
2791-
# This ensures metadata-only changes (grants) are applied
2812+
# This ensures metadata-only grants changes are applied
27922813
self._apply_grants(snapshot.model, target_table_name, GrantsTargetLayer.PHYSICAL)
27932814

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