@@ -2483,29 +2483,6 @@ def wap_publish(self, table_name: TableName, wap_id: str) -> None:
24832483 """
24842484 raise NotImplementedError (f"Engine does not support WAP: { type (self )} " )
24852485
2486- def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
2487- """Returns current grants for a table as a dictionary.
2488-
2489- This method queries the database and returns the current grants/permissions
2490- for the given table, parsed into a dictionary format. The it handles
2491- case-insensitive comparison between these current grants and the desired
2492- grants from model configuration.
2493-
2494- Args:
2495- table: The table/view to query grants for.
2496-
2497- Returns:
2498- Dictionary mapping permissions to lists of grantees. Permission names
2499- should be returned as the database provides them (typically uppercase
2500- for standard SQL permissions, but engine-specific roles may vary).
2501-
2502- Raises:
2503- NotImplementedError: If the engine does not support grants.
2504- """
2505- if not self .SUPPORTS_GRANTS :
2506- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2507- raise NotImplementedError ("Subclass must implement get_current_grants" )
2508-
25092486 def sync_grants_config (
25102487 self ,
25112488 table : exp .Table ,
@@ -2533,104 +2510,6 @@ def sync_grants_config(
25332510 if dcl_exprs :
25342511 self .execute (dcl_exprs )
25352512
2536- def _apply_grants_config_expr (
2537- self ,
2538- table : exp .Table ,
2539- grant_config : GrantsConfig ,
2540- table_type : DataObjectType = DataObjectType .TABLE ,
2541- ) -> t .List [exp .Expression ]:
2542- """Returns SQLGlot Grant expressions to apply grants to a table.
2543-
2544- Args:
2545- table: The table/view to grant permissions on.
2546- grant_config: Dictionary mapping permissions to lists of grantees.
2547- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2548-
2549- Returns:
2550- List of SQLGlot expressions for grant operations.
2551-
2552- Raises:
2553- NotImplementedError: If the engine does not support grants.
2554- """
2555- if not self .SUPPORTS_GRANTS :
2556- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2557- raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
2558-
2559- def _revoke_grants_config_expr (
2560- self ,
2561- table : exp .Table ,
2562- grant_config : GrantsConfig ,
2563- table_type : DataObjectType = DataObjectType .TABLE ,
2564- ) -> t .List [exp .Expression ]:
2565- """Returns SQLGlot expressions to revoke grants from a table.
2566-
2567- Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
2568- may return other expression types or handle revokes as strings.
2569-
2570- Args:
2571- table: The table/view to revoke permissions from.
2572- grant_config: Dictionary mapping permissions to lists of grantees.
2573- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2574-
2575- Returns:
2576- List of SQLGlot expressions for revoke operations.
2577-
2578- Raises:
2579- NotImplementedError: If the engine does not support grants.
2580- """
2581- if not self .SUPPORTS_GRANTS :
2582- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2583- raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
2584-
2585- @classmethod
2586- def _diff_grants_configs (
2587- cls , new_config : GrantsConfig , old_config : GrantsConfig
2588- ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2589- """Compute additions and removals between two grants configurations.
2590-
2591- This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2592- for both privilege keys and grantees, while preserving original casing
2593- in the output GrantsConfigs.
2594-
2595- Args:
2596- new_config: Desired grants configuration (specified by the user).
2597- old_config: Current grants configuration (returned by the database).
2598-
2599- Returns:
2600- A tuple of (additions, removals) GrantsConfig where:
2601- - additions contains privileges/grantees present in new_config but not in old_config
2602- - additions uses keys and grantee strings from new_config (user-specified casing)
2603- - removals contains privileges/grantees present in old_config but not in new_config
2604- - removals uses keys and grantee strings from old_config (database-returned casing)
2605-
2606- Notes:
2607- - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2608- - Overlapping grantees (case-insensitive) are excluded from the results.
2609- """
2610-
2611- def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2612- diffs : GrantsConfig = {}
2613- cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2614- for key , grantees in config1 .items ():
2615- cf_key = key .casefold ()
2616-
2617- # Missing key (add all grantees)
2618- if cf_key not in cf_config2 :
2619- diffs [key ] = grantees .copy ()
2620- continue
2621-
2622- # Include only grantees not in config2
2623- cf_grantees2 = cf_config2 [cf_key ]
2624- diff_grantees = []
2625- for grantee in grantees :
2626- if grantee .casefold () not in cf_grantees2 :
2627- diff_grantees .append (grantee )
2628- if diff_grantees :
2629- diffs [key ] = diff_grantees
2630- return diffs
2631-
2632- return _diffs (new_config , old_config ), _diffs (old_config , new_config )
2633-
26342513 @contextlib .contextmanager
26352514 def transaction (
26362515 self ,
@@ -3182,6 +3061,127 @@ def _check_identifier_length(self, expression: exp.Expression) -> None:
31823061 def get_table_last_modified_ts (self , table_names : t .List [TableName ]) -> t .List [int ]:
31833062 raise NotImplementedError ()
31843063
3064+ @classmethod
3065+ def _diff_grants_configs (
3066+ cls , new_config : GrantsConfig , old_config : GrantsConfig
3067+ ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
3068+ """Compute additions and removals between two grants configurations.
3069+
3070+ This method compares new (desired) and old (current) GrantsConfigs case-insensitively
3071+ for both privilege keys and grantees, while preserving original casing
3072+ in the output GrantsConfigs.
3073+
3074+ Args:
3075+ new_config: Desired grants configuration (specified by the user).
3076+ old_config: Current grants configuration (returned by the database).
3077+
3078+ Returns:
3079+ A tuple of (additions, removals) GrantsConfig where:
3080+ - additions contains privileges/grantees present in new_config but not in old_config
3081+ - additions uses keys and grantee strings from new_config (user-specified casing)
3082+ - removals contains privileges/grantees present in old_config but not in new_config
3083+ - removals uses keys and grantee strings from old_config (database-returned casing)
3084+
3085+ Notes:
3086+ - Comparison is case-insensitive using casefold(); original casing is preserved in results.
3087+ - Overlapping grantees (case-insensitive) are excluded from the results.
3088+ """
3089+
3090+ def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
3091+ diffs : GrantsConfig = {}
3092+ cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
3093+ for key , grantees in config1 .items ():
3094+ cf_key = key .casefold ()
3095+
3096+ # Missing key (add all grantees)
3097+ if cf_key not in cf_config2 :
3098+ diffs [key ] = grantees .copy ()
3099+ continue
3100+
3101+ # Include only grantees not in config2
3102+ cf_grantees2 = cf_config2 [cf_key ]
3103+ diff_grantees = []
3104+ for grantee in grantees :
3105+ if grantee .casefold () not in cf_grantees2 :
3106+ diff_grantees .append (grantee )
3107+ if diff_grantees :
3108+ diffs [key ] = diff_grantees
3109+ return diffs
3110+
3111+ return _diffs (new_config , old_config ), _diffs (old_config , new_config )
3112+
3113+ def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
3114+ """Returns current grants for a table as a dictionary.
3115+
3116+ This method queries the database and returns the current grants/permissions
3117+ for the given table, parsed into a dictionary format. The it handles
3118+ case-insensitive comparison between these current grants and the desired
3119+ grants from model configuration.
3120+
3121+ Args:
3122+ table: The table/view to query grants for.
3123+
3124+ Returns:
3125+ Dictionary mapping permissions to lists of grantees. Permission names
3126+ should be returned as the database provides them (typically uppercase
3127+ for standard SQL permissions, but engine-specific roles may vary).
3128+
3129+ Raises:
3130+ NotImplementedError: If the engine does not support grants.
3131+ """
3132+ if not self .SUPPORTS_GRANTS :
3133+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3134+ raise NotImplementedError ("Subclass must implement get_current_grants" )
3135+
3136+ def _apply_grants_config_expr (
3137+ self ,
3138+ table : exp .Table ,
3139+ grant_config : GrantsConfig ,
3140+ table_type : DataObjectType = DataObjectType .TABLE ,
3141+ ) -> t .List [exp .Expression ]:
3142+ """Returns SQLGlot Grant expressions to apply grants to a table.
3143+
3144+ Args:
3145+ table: The table/view to grant permissions on.
3146+ grant_config: Dictionary mapping permissions to lists of grantees.
3147+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3148+
3149+ Returns:
3150+ List of SQLGlot expressions for grant operations.
3151+
3152+ Raises:
3153+ NotImplementedError: If the engine does not support grants.
3154+ """
3155+ if not self .SUPPORTS_GRANTS :
3156+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3157+ raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
3158+
3159+ def _revoke_grants_config_expr (
3160+ self ,
3161+ table : exp .Table ,
3162+ grant_config : GrantsConfig ,
3163+ table_type : DataObjectType = DataObjectType .TABLE ,
3164+ ) -> t .List [exp .Expression ]:
3165+ """Returns SQLGlot expressions to revoke grants from a table.
3166+
3167+ Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
3168+ may return other expression types or handle revokes as strings.
3169+
3170+ Args:
3171+ table: The table/view to revoke permissions from.
3172+ grant_config: Dictionary mapping permissions to lists of grantees.
3173+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3174+
3175+ Returns:
3176+ List of SQLGlot expressions for revoke operations.
3177+
3178+ Raises:
3179+ NotImplementedError: If the engine does not support grants.
3180+ """
3181+ if not self .SUPPORTS_GRANTS :
3182+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3183+ raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
3184+
31853185
31863186class EngineAdapterWithIndexSupport (EngineAdapter ):
31873187 SUPPORTS_INDEXES = True
0 commit comments