@@ -2396,29 +2396,6 @@ def wap_publish(self, table_name: TableName, wap_id: str) -> None:
23962396 """
23972397 raise NotImplementedError (f"Engine does not support WAP: { type (self )} " )
23982398
2399- def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
2400- """Returns current grants for a table as a dictionary.
2401-
2402- This method queries the database and returns the current grants/permissions
2403- for the given table, parsed into a dictionary format. The it handles
2404- case-insensitive comparison between these current grants and the desired
2405- grants from model configuration.
2406-
2407- Args:
2408- table: The table/view to query grants for.
2409-
2410- Returns:
2411- Dictionary mapping permissions to lists of grantees. Permission names
2412- should be returned as the database provides them (typically uppercase
2413- for standard SQL permissions, but engine-specific roles may vary).
2414-
2415- Raises:
2416- NotImplementedError: If the engine does not support grants.
2417- """
2418- if not self .SUPPORTS_GRANTS :
2419- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2420- raise NotImplementedError ("Subclass must implement get_current_grants" )
2421-
24222399 def sync_grants_config (
24232400 self ,
24242401 table : exp .Table ,
@@ -2446,104 +2423,6 @@ def sync_grants_config(
24462423 if dcl_exprs :
24472424 self .execute (dcl_exprs )
24482425
2449- def _apply_grants_config_expr (
2450- self ,
2451- table : exp .Table ,
2452- grant_config : GrantsConfig ,
2453- table_type : DataObjectType = DataObjectType .TABLE ,
2454- ) -> t .List [exp .Expression ]:
2455- """Returns SQLGlot Grant expressions to apply grants to a table.
2456-
2457- Args:
2458- table: The table/view to grant permissions on.
2459- grant_config: Dictionary mapping permissions to lists of grantees.
2460- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2461-
2462- Returns:
2463- List of SQLGlot expressions for grant operations.
2464-
2465- Raises:
2466- NotImplementedError: If the engine does not support grants.
2467- """
2468- if not self .SUPPORTS_GRANTS :
2469- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2470- raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
2471-
2472- def _revoke_grants_config_expr (
2473- self ,
2474- table : exp .Table ,
2475- grant_config : GrantsConfig ,
2476- table_type : DataObjectType = DataObjectType .TABLE ,
2477- ) -> t .List [exp .Expression ]:
2478- """Returns SQLGlot expressions to revoke grants from a table.
2479-
2480- Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
2481- may return other expression types or handle revokes as strings.
2482-
2483- Args:
2484- table: The table/view to revoke permissions from.
2485- grant_config: Dictionary mapping permissions to lists of grantees.
2486- table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
2487-
2488- Returns:
2489- List of SQLGlot expressions for revoke operations.
2490-
2491- Raises:
2492- NotImplementedError: If the engine does not support grants.
2493- """
2494- if not self .SUPPORTS_GRANTS :
2495- raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
2496- raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
2497-
2498- @classmethod
2499- def _diff_grants_configs (
2500- cls , new_config : GrantsConfig , old_config : GrantsConfig
2501- ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2502- """Compute additions and removals between two grants configurations.
2503-
2504- This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2505- for both privilege keys and grantees, while preserving original casing
2506- in the output GrantsConfigs.
2507-
2508- Args:
2509- new_config: Desired grants configuration (specified by the user).
2510- old_config: Current grants configuration (returned by the database).
2511-
2512- Returns:
2513- A tuple of (additions, removals) GrantsConfig where:
2514- - additions contains privileges/grantees present in new_config but not in old_config
2515- - additions uses keys and grantee strings from new_config (user-specified casing)
2516- - removals contains privileges/grantees present in old_config but not in new_config
2517- - removals uses keys and grantee strings from old_config (database-returned casing)
2518-
2519- Notes:
2520- - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2521- - Overlapping grantees (case-insensitive) are excluded from the results.
2522- """
2523-
2524- def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2525- diffs : GrantsConfig = {}
2526- cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2527- for key , grantees in config1 .items ():
2528- cf_key = key .casefold ()
2529-
2530- # Missing key (add all grantees)
2531- if cf_key not in cf_config2 :
2532- diffs [key ] = grantees .copy ()
2533- continue
2534-
2535- # Include only grantees not in config2
2536- cf_grantees2 = cf_config2 [cf_key ]
2537- diff_grantees = []
2538- for grantee in grantees :
2539- if grantee .casefold () not in cf_grantees2 :
2540- diff_grantees .append (grantee )
2541- if diff_grantees :
2542- diffs [key ] = diff_grantees
2543- return diffs
2544-
2545- return _diffs (new_config , old_config ), _diffs (old_config , new_config )
2546-
25472426 @contextlib .contextmanager
25482427 def transaction (
25492428 self ,
@@ -3072,6 +2951,127 @@ def _check_identifier_length(self, expression: exp.Expression) -> None:
30722951 f"Identifier name '{ name } ' (length { name_length } ) exceeds { self .dialect .capitalize ()} 's max identifier limit of { self .MAX_IDENTIFIER_LENGTH } characters"
30732952 )
30742953
2954+ @classmethod
2955+ def _diff_grants_configs (
2956+ cls , new_config : GrantsConfig , old_config : GrantsConfig
2957+ ) -> t .Tuple [GrantsConfig , GrantsConfig ]:
2958+ """Compute additions and removals between two grants configurations.
2959+
2960+ This method compares new (desired) and old (current) GrantsConfigs case-insensitively
2961+ for both privilege keys and grantees, while preserving original casing
2962+ in the output GrantsConfigs.
2963+
2964+ Args:
2965+ new_config: Desired grants configuration (specified by the user).
2966+ old_config: Current grants configuration (returned by the database).
2967+
2968+ Returns:
2969+ A tuple of (additions, removals) GrantsConfig where:
2970+ - additions contains privileges/grantees present in new_config but not in old_config
2971+ - additions uses keys and grantee strings from new_config (user-specified casing)
2972+ - removals contains privileges/grantees present in old_config but not in new_config
2973+ - removals uses keys and grantee strings from old_config (database-returned casing)
2974+
2975+ Notes:
2976+ - Comparison is case-insensitive using casefold(); original casing is preserved in results.
2977+ - Overlapping grantees (case-insensitive) are excluded from the results.
2978+ """
2979+
2980+ def _diffs (config1 : GrantsConfig , config2 : GrantsConfig ) -> GrantsConfig :
2981+ diffs : GrantsConfig = {}
2982+ cf_config2 = {k .casefold (): {g .casefold () for g in v } for k , v in config2 .items ()}
2983+ for key , grantees in config1 .items ():
2984+ cf_key = key .casefold ()
2985+
2986+ # Missing key (add all grantees)
2987+ if cf_key not in cf_config2 :
2988+ diffs [key ] = grantees .copy ()
2989+ continue
2990+
2991+ # Include only grantees not in config2
2992+ cf_grantees2 = cf_config2 [cf_key ]
2993+ diff_grantees = []
2994+ for grantee in grantees :
2995+ if grantee .casefold () not in cf_grantees2 :
2996+ diff_grantees .append (grantee )
2997+ if diff_grantees :
2998+ diffs [key ] = diff_grantees
2999+ return diffs
3000+
3001+ return _diffs (new_config , old_config ), _diffs (old_config , new_config )
3002+
3003+ def _get_current_grants_config (self , table : exp .Table ) -> GrantsConfig :
3004+ """Returns current grants for a table as a dictionary.
3005+
3006+ This method queries the database and returns the current grants/permissions
3007+ for the given table, parsed into a dictionary format. The it handles
3008+ case-insensitive comparison between these current grants and the desired
3009+ grants from model configuration.
3010+
3011+ Args:
3012+ table: The table/view to query grants for.
3013+
3014+ Returns:
3015+ Dictionary mapping permissions to lists of grantees. Permission names
3016+ should be returned as the database provides them (typically uppercase
3017+ for standard SQL permissions, but engine-specific roles may vary).
3018+
3019+ Raises:
3020+ NotImplementedError: If the engine does not support grants.
3021+ """
3022+ if not self .SUPPORTS_GRANTS :
3023+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3024+ raise NotImplementedError ("Subclass must implement get_current_grants" )
3025+
3026+ def _apply_grants_config_expr (
3027+ self ,
3028+ table : exp .Table ,
3029+ grant_config : GrantsConfig ,
3030+ table_type : DataObjectType = DataObjectType .TABLE ,
3031+ ) -> t .List [exp .Expression ]:
3032+ """Returns SQLGlot Grant expressions to apply grants to a table.
3033+
3034+ Args:
3035+ table: The table/view to grant permissions on.
3036+ grant_config: Dictionary mapping permissions to lists of grantees.
3037+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3038+
3039+ Returns:
3040+ List of SQLGlot expressions for grant operations.
3041+
3042+ Raises:
3043+ NotImplementedError: If the engine does not support grants.
3044+ """
3045+ if not self .SUPPORTS_GRANTS :
3046+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3047+ raise NotImplementedError ("Subclass must implement _apply_grants_config_expr" )
3048+
3049+ def _revoke_grants_config_expr (
3050+ self ,
3051+ table : exp .Table ,
3052+ grant_config : GrantsConfig ,
3053+ table_type : DataObjectType = DataObjectType .TABLE ,
3054+ ) -> t .List [exp .Expression ]:
3055+ """Returns SQLGlot expressions to revoke grants from a table.
3056+
3057+ Note: SQLGlot doesn't yet have a Revoke expression type, so implementations
3058+ may return other expression types or handle revokes as strings.
3059+
3060+ Args:
3061+ table: The table/view to revoke permissions from.
3062+ grant_config: Dictionary mapping permissions to lists of grantees.
3063+ table_type: The type of database object (TABLE, VIEW, MATERIALIZED_VIEW).
3064+
3065+ Returns:
3066+ List of SQLGlot expressions for revoke operations.
3067+
3068+ Raises:
3069+ NotImplementedError: If the engine does not support grants.
3070+ """
3071+ if not self .SUPPORTS_GRANTS :
3072+ raise NotImplementedError (f"Engine does not support grants: { type (self )} " )
3073+ raise NotImplementedError ("Subclass must implement _revoke_grants_config_expr" )
3074+
30753075
30763076class EngineAdapterWithIndexSupport (EngineAdapter ):
30773077 SUPPORTS_INDEXES = True
0 commit comments