@@ -2405,29 +2405,6 @@ def wap_publish(self, table_name: TableName, wap_id: str) -> None:
24052405 """
24062406 raise NotImplementedError (f"Engine does not support WAP: { type (self )} " )
24072407
2408- def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
2409- """Returns current grants for a table as a dictionary.
2410-
2411- This method queries the database and returns the current grants/permissions
2412- for the given table, parsed into a dictionary format. The it handles
2413- case-insensitive comparison between these current grants and the desired
2414- grants from model configuration.
2415-
2416- Args:
2417- table: The table/view to query grants for.
2418-
2419- Returns:
2420- Dictionary mapping permissions to lists of grantees. Permission names
2421- should be returned as the database provides them (typically uppercase
2422- for standard SQL permissions, but engine-specific roles may vary).
2423-
2424- Raises:
2425- NotImplementedError: If the engine does not support grants.
2426- """
2427- if not self .SUPPORTS_GRANTS :
2428- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2429- raise NotImplementedError ("Subclass must implement get_current_grants" )
2430-
24312408 def sync_grants_config (
24322409 self ,
24332410 table : exp .Table ,
@@ -2455,104 +2432,6 @@ def sync_grants_config(
24552432 if dcl_exprs :
24562433 self .execute (dcl_exprs )
24572434
2458- def _apply_grants_config_expr (
2459- self ,
2460- table : exp .Table ,
2461- grant_config : GrantsConfig ,
2462- table_type : DataObjectType = DataObjectType .TABLE ,
2463- ) -> t .List [exp .Expression ]:
2464- """Returns SQLGlot Grant expressions to apply grants to a table.
2465-
2466- Args:
2467- table: The table/view to grant permissions on.
2468- grant_config: Dictionary mapping permissions to lists of grantees.
2469- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2470-
2471- Returns:
2472- List of SQLGlot expressions for grant operations.
2473-
2474- Raises:
2475- NotImplementedError: If the engine does not support grants.
2476- """
2477- if not self .SUPPORTS_GRANTS :
2478- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2479- raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
2480-
2481- def _revoke_grants_config_expr (
2482- self ,
2483- table : exp .Table ,
2484- grant_config : GrantsConfig ,
2485- table_type : DataObjectType = DataObjectType .TABLE ,
2486- ) -> t .List [exp .Expression ]:
2487- """Returns SQLGlot expressions to revoke grants from a table.
2488-
2489- Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
2490- may return other expression types or handle revokes as strings.
2491-
2492- Args:
2493- table: The table/view to revoke permissions from.
2494- grant_config: Dictionary mapping permissions to lists of grantees.
2495- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2496-
2497- Returns:
2498- List of SQLGlot expressions for revoke operations.
2499-
2500- Raises:
2501- NotImplementedError: If the engine does not support grants.
2502- """
2503- if not self .SUPPORTS_GRANTS :
2504- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2505- raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
2506-
2507- @classmethod
2508- def _diff_grants_configs (
2509- cls , new_config : GrantsConfig , old_config : GrantsConfig
2510- ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2511- """Compute additions and removals between two grants configurations.
2512-
2513- This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2514- for both privilege keys and grantees, while preserving original casing
2515- in the output GrantsConfigs.
2516-
2517- Args:
2518- new_config: Desired grants configuration (specified by the user).
2519- old_config: Current grants configuration (returned by the database).
2520-
2521- Returns:
2522- A tuple of (additions, removals) GrantsConfig where:
2523- - additions contains privileges/grantees present in new_config but not in old_config
2524- - additions uses keys and grantee strings from new_config (user-specified casing)
2525- - removals contains privileges/grantees present in old_config but not in new_config
2526- - removals uses keys and grantee strings from old_config (database-returned casing)
2527-
2528- Notes:
2529- - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2530- - Overlapping grantees (case-insensitive) are excluded from the results.
2531- """
2532-
2533- def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2534- diffs : GrantsConfig = {}
2535- cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2536- for key , grantees in config1 .items ():
2537- cf_key = key .casefold ()
2538-
2539- # Missing key (add all grantees)
2540- if cf_key not in cf_config2 :
2541- diffs [key ] = grantees .copy ()
2542- continue
2543-
2544- # Include only grantees not in config2
2545- cf_grantees2 = cf_config2 [cf_key ]
2546- diff_grantees = []
2547- for grantee in grantees :
2548- if grantee .casefold () not in cf_grantees2 :
2549- diff_grantees .append (grantee )
2550- if diff_grantees :
2551- diffs [key ] = diff_grantees
2552- return diffs
2553-
2554- return _diffs (new_config , old_config ), _diffs (old_config , new_config )
2555-
25562435 @contextlib .contextmanager
25572436 def transaction (
25582437 self ,
@@ -3084,6 +2963,127 @@ def _check_identifier_length(self, expression: exp.Expression) -> None:
30842963 def get_table_last_modified_ts (self , table_names : t .List [TableName ]) -> t .List [int ]:
30852964 raise NotImplementedError ()
30862965
2966+ @classmethod
2967+ def _diff_grants_configs (
2968+ cls , new_config : GrantsConfig , old_config : GrantsConfig
2969+ ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2970+ """Compute additions and removals between two grants configurations.
2971+
2972+ This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2973+ for both privilege keys and grantees, while preserving original casing
2974+ in the output GrantsConfigs.
2975+
2976+ Args:
2977+ new_config: Desired grants configuration (specified by the user).
2978+ old_config: Current grants configuration (returned by the database).
2979+
2980+ Returns:
2981+ A tuple of (additions, removals) GrantsConfig where:
2982+ - additions contains privileges/grantees present in new_config but not in old_config
2983+ - additions uses keys and grantee strings from new_config (user-specified casing)
2984+ - removals contains privileges/grantees present in old_config but not in new_config
2985+ - removals uses keys and grantee strings from old_config (database-returned casing)
2986+
2987+ Notes:
2988+ - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2989+ - Overlapping grantees (case-insensitive) are excluded from the results.
2990+ """
2991+
2992+ def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2993+ diffs : GrantsConfig = {}
2994+ cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2995+ for key , grantees in config1 .items ():
2996+ cf_key = key .casefold ()
2997+
2998+ # Missing key (add all grantees)
2999+ if cf_key not in cf_config2 :
3000+ diffs [key ] = grantees .copy ()
3001+ continue
3002+
3003+ # Include only grantees not in config2
3004+ cf_grantees2 = cf_config2 [cf_key ]
3005+ diff_grantees = []
3006+ for grantee in grantees :
3007+ if grantee .casefold () not in cf_grantees2 :
3008+ diff_grantees .append (grantee )
3009+ if diff_grantees :
3010+ diffs [key ] = diff_grantees
3011+ return diffs
3012+
3013+ return _diffs (new_config , old_config ), _diffs (old_config , new_config )
3014+
3015+ def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
3016+ """Returns current grants for a table as a dictionary.
3017+
3018+ This method queries the database and returns the current grants/permissions
3019+ for the given table, parsed into a dictionary format. The it handles
3020+ case-insensitive comparison between these current grants and the desired
3021+ grants from model configuration.
3022+
3023+ Args:
3024+ table: The table/view to query grants for.
3025+
3026+ Returns:
3027+ Dictionary mapping permissions to lists of grantees. Permission names
3028+ should be returned as the database provides them (typically uppercase
3029+ for standard SQL permissions, but engine-specific roles may vary).
3030+
3031+ Raises:
3032+ NotImplementedError: If the engine does not support grants.
3033+ """
3034+ if not self .SUPPORTS_GRANTS :
3035+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3036+ raise NotImplementedError ("Subclass must implement get_current_grants" )
3037+
3038+ def _apply_grants_config_expr (
3039+ self ,
3040+ table : exp .Table ,
3041+ grant_config : GrantsConfig ,
3042+ table_type : DataObjectType = DataObjectType .TABLE ,
3043+ ) -> t .List [exp .Expression ]:
3044+ """Returns SQLGlot Grant expressions to apply grants to a table.
3045+
3046+ Args:
3047+ table: The table/view to grant permissions on.
3048+ grant_config: Dictionary mapping permissions to lists of grantees.
3049+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3050+
3051+ Returns:
3052+ List of SQLGlot expressions for grant operations.
3053+
3054+ Raises:
3055+ NotImplementedError: If the engine does not support grants.
3056+ """
3057+ if not self .SUPPORTS_GRANTS :
3058+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3059+ raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
3060+
3061+ def _revoke_grants_config_expr (
3062+ self ,
3063+ table : exp .Table ,
3064+ grant_config : GrantsConfig ,
3065+ table_type : DataObjectType = DataObjectType .TABLE ,
3066+ ) -> t .List [exp .Expression ]:
3067+ """Returns SQLGlot expressions to revoke grants from a table.
3068+
3069+ Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
3070+ may return other expression types or handle revokes as strings.
3071+
3072+ Args:
3073+ table: The table/view to revoke permissions from.
3074+ grant_config: Dictionary mapping permissions to lists of grantees.
3075+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3076+
3077+ Returns:
3078+ List of SQLGlot expressions for revoke operations.
3079+
3080+ Raises:
3081+ NotImplementedError: If the engine does not support grants.
3082+ """
3083+ if not self .SUPPORTS_GRANTS :
3084+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3085+ raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
3086+
30873087
30883088class EngineAdapterWithIndexSupport (EngineAdapter ):
30893089 SUPPORTS_INDEXES = True
0 commit comments