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