Skip to content

Commit b85622d

Browse files
committed
refactor: add skip_grants flag to SnapshotEvaluator.create
1 parent 308d579 commit b85622d

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

@@ -1408,12 +1409,12 @@ def _execute_create(
14081409
table_name=table_name,
14091410
model=snapshot.model,
14101411
is_table_deployable=is_table_deployable,
1412+
skip_grants=skip_grants,
14111413
render_kwargs=create_render_kwargs,
14121414
is_snapshot_deployable=is_snapshot_deployable,
14131415
is_snapshot_representative=is_snapshot_representative,
14141416
dry_run=dry_run,
14151417
physical_properties=rendered_physical_properties,
1416-
skip_grants=skip_grants,
14171418
)
14181419
if run_pre_post_statements:
14191420
adapter.execute(snapshot.model.render_post_statements(**create_render_kwargs))
@@ -1577,6 +1578,7 @@ def create(
15771578
model: Model,
15781579
is_table_deployable: bool,
15791580
render_kwargs: t.Dict[str, t.Any],
1581+
skip_grants: bool,
15801582
**kwargs: t.Any,
15811583
) -> None:
15821584
"""Creates the target table or view.
@@ -1720,6 +1722,7 @@ def create(
17201722
model: Model,
17211723
is_table_deployable: bool,
17221724
render_kwargs: t.Dict[str, t.Any],
1725+
skip_grants: bool,
17231726
**kwargs: t.Any,
17241727
) -> None:
17251728
pass
@@ -1795,10 +1798,10 @@ def promote(
17951798
view_properties=model.render_virtual_properties(**render_kwargs),
17961799
)
17971800

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

1801-
# Apply grants to the virtual layer view
1804+
# Apply grants to the virtual layer (view) after promotion
18021805
self._apply_grants(model, view_name, GrantsTargetLayer.VIRTUAL)
18031806

18041807
def demote(self, view_name: str, **kwargs: t.Any) -> None:
@@ -1813,6 +1816,7 @@ def create(
18131816
model: Model,
18141817
is_table_deployable: bool,
18151818
render_kwargs: t.Dict[str, t.Any],
1819+
skip_grants: bool,
18161820
**kwargs: t.Any,
18171821
) -> None:
18181822
ctas_query = model.ctas_query(**render_kwargs)
@@ -1858,7 +1862,7 @@ def create(
18581862
)
18591863

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

18641868
def migrate(
@@ -1900,6 +1904,7 @@ def _replace_query_for_model(
19001904
name: str,
19011905
query_or_df: QueryOrDF,
19021906
render_kwargs: t.Dict[str, t.Any],
1907+
skip_grants: bool = False,
19031908
**kwargs: t.Any,
19041909
) -> None:
19051910
"""Replaces the table for the given model.
@@ -1937,7 +1942,7 @@ def _replace_query_for_model(
19371942
)
19381943

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

19431948
def _get_target_and_source_columns(
@@ -2187,6 +2192,7 @@ def create(
21872192
model: Model,
21882193
is_table_deployable: bool,
21892194
render_kwargs: t.Dict[str, t.Any],
2195+
skip_grants: bool,
21902196
**kwargs: t.Any,
21912197
) -> None:
21922198
model = t.cast(SeedModel, model)
@@ -2200,29 +2206,38 @@ def create(
22002206
)
22012207
return
22022208

2203-
# Skip grants in parent create call since we'll apply them after data insertion
2204-
kwargs_no_grants = {**kwargs}
2205-
kwargs_no_grants["skip_grants"] = True
2206-
2207-
super().create(table_name, model, is_table_deployable, render_kwargs, **kwargs_no_grants)
2209+
super().create(
2210+
table_name,
2211+
model,
2212+
is_table_deployable,
2213+
render_kwargs,
2214+
skip_grants=True, # Skip grants; they're applied after data insertion
2215+
**kwargs,
2216+
)
22082217
# For seeds we insert data at the time of table creation.
22092218
try:
22102219
for index, df in enumerate(model.render_seed()):
22112220
if index == 0:
22122221
self._replace_query_for_model(
2213-
model, table_name, df, render_kwargs, **kwargs_no_grants
2222+
model,
2223+
table_name,
2224+
df,
2225+
render_kwargs,
2226+
skip_grants=True, # Skip grants; they're applied after data insertion
2227+
**kwargs,
22142228
)
22152229
else:
22162230
self.adapter.insert_append(
22172231
table_name, df, target_columns_to_types=model.columns_to_types
22182232
)
2233+
2234+
if not skip_grants:
2235+
# Apply grants after seed table creation and data insertion
2236+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
22192237
except Exception:
22202238
self.adapter.drop_table(table_name)
22212239
raise
22222240

2223-
# Apply grants after seed table creation or data insertion
2224-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2225-
22262241
def insert(
22272242
self,
22282243
table_name: str,
@@ -2254,6 +2269,7 @@ def create(
22542269
model: Model,
22552270
is_table_deployable: bool,
22562271
render_kwargs: t.Dict[str, t.Any],
2272+
skip_grants: bool,
22572273
**kwargs: t.Any,
22582274
) -> None:
22592275
assert isinstance(model.kind, (SCDType2ByTimeKind, SCDType2ByColumnKind))
@@ -2283,11 +2299,13 @@ def create(
22832299
model,
22842300
is_table_deployable,
22852301
render_kwargs,
2302+
skip_grants,
22862303
**kwargs,
22872304
)
22882305

2289-
# Apply grants after SCD Type 2 table creation
2290-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2306+
if not skip_grants:
2307+
# Apply grants after SCD Type 2 table creation
2308+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
22912309

22922310
def insert(
22932311
self,
@@ -2431,14 +2449,17 @@ def create(
24312449
model: Model,
24322450
is_table_deployable: bool,
24332451
render_kwargs: t.Dict[str, t.Any],
2452+
skip_grants: bool,
24342453
**kwargs: t.Any,
24352454
) -> None:
24362455
if self.adapter.table_exists(table_name):
24372456
# Make sure we don't recreate the view to prevent deletion of downstream views in engines with no late
24382457
# binding support (because of DROP CASCADE).
24392458
logger.info("View '%s' already exists", table_name)
2440-
# Always apply grants when present, even if view exists, to handle grants updates
2441-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2459+
2460+
if not skip_grants:
2461+
# Always apply grants when present, even if view exists, to handle grants updates
2462+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24422463
return
24432464

24442465
logger.info("Creating view '%s'", table_name)
@@ -2462,8 +2483,9 @@ def create(
24622483
column_descriptions=model.column_descriptions if is_table_deployable else None,
24632484
)
24642485

2465-
# Apply grants after view creation
2466-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2486+
if not skip_grants:
2487+
# Apply grants after view creation
2488+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
24672489

24682490
def migrate(
24692491
self,
@@ -2640,6 +2662,7 @@ def create(
26402662
model: Model,
26412663
is_table_deployable: bool,
26422664
render_kwargs: t.Dict[str, t.Any],
2665+
skip_grants: bool,
26432666
**kwargs: t.Any,
26442667
) -> None:
26452668
is_snapshot_deployable: bool = kwargs["is_snapshot_deployable"]
@@ -2660,24 +2683,21 @@ def create(
26602683
)
26612684

26622685
# Apply grants after managed table creation
2663-
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
2686+
if not skip_grants:
2687+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
26642688

26652689
elif not is_table_deployable:
26662690
# Only create the dev preview table as a normal table.
26672691
# For the main table, if the snapshot is cant be deployed to prod (eg upstream is forward-only) do nothing.
26682692
# Any downstream models that reference it will be updated to point to the dev preview table.
26692693
# If the user eventually tries to deploy it, the logic in insert() will see it doesnt exist and create it
2670-
2671-
# Create preview table but don't apply grants here since the table is not deployable
2672-
# Grants will be applied later when the table becomes deployable
2673-
kwargs_no_grants = {**kwargs}
2674-
kwargs_no_grants["skip_grants"] = True
26752694
super().create(
26762695
table_name=table_name,
26772696
model=model,
26782697
is_table_deployable=is_table_deployable,
26792698
render_kwargs=render_kwargs,
2680-
**kwargs_no_grants,
2699+
skip_grants=skip_grants,
2700+
**kwargs,
26812701
)
26822702

26832703
def insert(
@@ -2704,6 +2724,7 @@ def insert(
27042724
column_descriptions=model.column_descriptions,
27052725
table_format=model.table_format,
27062726
)
2727+
self._apply_grants(model, table_name, GrantsTargetLayer.PHYSICAL)
27072728
elif not is_snapshot_deployable:
27082729
# Snapshot isnt deployable; update the preview table instead
27092730
# If the snapshot was deployable, then data would have already been loaded in create() because a managed table would have been created
@@ -2753,7 +2774,7 @@ def migrate(
27532774
)
27542775

27552776
# Apply grants after verifying no schema changes
2756-
# This ensures metadata-only changes (grants) are applied
2777+
# This ensures metadata-only grants changes are applied
27572778
self._apply_grants(snapshot.model, target_table_name, GrantsTargetLayer.PHYSICAL)
27582779

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